初識指標
一、什麼是指標?
在瞭解指標之前先要先弄清楚地址的概念。
如果在程式中定義了一個變數,在對程式進行編譯時,系統就會給這個變數分配記憶體單元。編譯系統根據程式中定義的變數型別,分配一定長度的空間。
例如:整型變數分配4個位元組,字元型分配1個位元組,單精度分配4個位元組等。記憶體區的每一個位元組有一個編號,這就是“地址編號”,它就相當於旅館中的房間號,每一個房間都可以看作一塊記憶體區域,都可以用來存放東西,我們給每個房間都編一個房間門牌號,用於更好的區分每一個房間,記憶體中也是一樣的,整個記憶體由很多個位元組組成,每個位元組都有其對應的“房間號”,這就是“地址”了。通過這個“房間號”就可以找到其對應的“房間”,然後就可以從房間裡取東西,或者把東西放進房間裡了。
理解了地址的概念之後,那所謂的指標,就是記憶體地址,也就是地址的編號,可以把“指標指向地址”理解成“用小本本把房間號記下來”,那這個小本本就相當於一個用於記房間號的指標了,一個變數的地址稱為此變數的“指標”。
二、指標常量與指標變數
1、指標常量
之前有了解過不同資料型別的變數所佔記憶體位元組數的這個概念,那麼系統在編譯時給一個變數分配的記憶體地址就稱為此變數的“指標”,這個指標的指向是無法改變的,所以又稱為指標常量,陣列的地址也是指標常量(也稱為地址常量)。
int a = 10;
//&a = 10000; //&a取變數a的地址,是一個地址常量,不能夠改變它的位置
scanf("%d",&a); //輸入222
printf("a=%d\t &a=%p/n",a,&a); //輸出地址
2、指標變數
(1)指標變數的概念
如果有一個變數專門用來存放另一個變數的地址,則稱這個變數為“指標變數”,也就是說C語言中有一類變數是專門用來儲存(指向)地址的,我們將它稱為“指標變數”,指標變數的中儲存的地址可以被改變,也就是可以改變指標變數的指向,就好比一張紙或一個小本本,寫著一個房間的房間號,那把這個房間的房間號擦掉,寫上另一個房間的房間號也是可以的,這就是指標變數和指標常量最大的區別所在了,可以改變指標變數的指向。
//定義指標變數格式:資料型別 *變數名;
int* p;
(2)指標變數的定義
定義指標變數的一般格式:
型別名* 指標變數名;
int a= 10;
int* p; //定義了一個整型指標變數p,可以用於指向整型資料的地址(裡面儲存的是整型變數的地址)
p = &a; //將整型變數a的地址賦值給整型指標變數p,整型指標p指向了整型變數a的地址。
int*p,*q;
char* p1,*q1;
double *p2,*q2;
/* 注意:左端的int、char等是在定義指標變數時必須指定的“基型別”。指標變數的基型別用來規定此指標變數可以指向的變數的型別。如:上面定義的*p和*q只能用於指向int整型變數的地址,p2和q2只能用於指向double雙精度型別變數的地址。 */
char *q;
int *p;
printf("%d %d\n",sizeof(p),sizeof(q)); //都輸出為4,指標變數所佔記憶體大小一般是佔4個位元組
(3) 指標變數的引用:
int* p; //定義了一個整型指標變數p,這裡的'*'是指標變數定義符
*p; //*p解引用,這裡'*'是解引用符號
int a=10;
int *p;
p = &a;
printf("*&a=%d"); //對a的地址進行解引用,輸出為10,。
printf("&p=%p "); //輸出為指標變數p的地址(p自己的地址,不是儲存其他變數地址的地址)
與指標和地址相關運算子:’*’(指標運算子)和’&’(取地址運算子) //區別對待位運算子&
//例如:int a,*p; p=&a; *p=10;
//在引用指標變數時,有以下幾種情況:
//1、給指標變數賦值
如:int a = 10,b=20;
int *p=&a;
//定義一個整型指標變數p,初始化p的值為a的地址,也就是p指向a地址
/*解引用:*/
*p=30; //通過指標變數p引用a變數,改變a的值為30
//這裡的’*’為解引用符號,*p引用指標變數p所指向地址中對應的值
scanf(“%d”,p); //scanf通過指標變數p給變數a賦值
printf(“%d\n”,*p); //通過指標變數p輸出變數a的值
*p=b; //將b的值放入指標變數p所指向的記憶體地址中(a的地址單元中)
p=&b; //改變指標p的指向,指標p不再指向a的地址了,而是指向b的地址
printf(“%d\n”,*p); //輸出變數b的值
//輸出記憶體地址編號
printf(“%p\n”,p); //以十六進位制的格式輸出指標變數p所指向地址的記憶體地址編號
printf(“%d\n”,&a); //以十進位制的格式輸出變數a所在的記憶體地址編號
printf(“%o\n”,&b); //以八進位制的格式輸出變數b所在的記憶體地址編號
printf(“%p\n”,&p); //以十六進位制的格式輸出指標變數p所在的記憶體地址編號
三、指標變數作為函式引數
函式的引數不僅可以是整型、浮點型、字元型的資料,還可以是指標型別。它的作用是將一個變數的地址傳遞到另一個函式中。
1、函式引數為指標型別的函式:
//1、函式引數為指標型別的函式:
void fun1(int x,int y)
{//這裡定義了一個普通函式fun1
printf(“x=%d\ty=%d\n”,x++,y++);
}
void fun2(int *x,int *y)
{//這裡定義了一個形參為整型指標型別函式fun2,其形參為指標型別的變數
printf(“x=%d\ty=%d\n”,(*x)++,(*y)++); //注意*和++的優先順序,++的優先順序高
//注意:和printf(“x=%d\ty=%d\n”,x++,y++);的區別,也就是沒有*和有*的區別
//沒有*就是指標的偏移,指標本身移動
}
int main()
{
int a=10,b=20,*p,*q;
fun2(&a,&b); //這裡呼叫函式fun時,所傳遞的實參必須是地址
printf(“a=%d\tb=%d\n”,a,b); //輸出的a和b的值為11,21
p=&a; //使用整型指標變數p指向整型變數a的地址
q=&b; //使用整型指標變數q指向整型變數b的地址
fun2(p,q); //這裡使用指標變數p和q作為實參傳遞
printf(“*p=%d\t*q=%d\n”,*p,*q);
return 0;
}
2、指標函式
//返回值為指標型別的函式稱為“指標函式”:
int *fun3(int *x) //這是一個指標函式,返回值型別為整型int指標型別
{//int* x = &a;
++*x;
return x; //返回指標變數x所指向的記憶體地址
}
//呼叫
int a=10;
int* p;
p=fun3(&a);
printf("a=%d\t"); //輸出11;
int *fun4()
{
int a=10; //區域性變數:出了作用域,記憶體揮被釋放
//如果加static,出了作用域,其記憶體不會被釋放,但是隻能在作用域範圍內使用
return &a; //返回a記憶體地址
//注意:不允許返回區域性變數的地址
}
int* p;
p=fun4(); //p=&a;使用了非法空間
四、通過指標引用陣列
1、陣列元素的指標
陣列元素的地址表示:
如:int a[10] = {0,1,2,3,4,5,6,7,8,9},*p;
&a[0]; //引用陣列元素a[0]地址的表示方法
2、指標指向陣列元素
p=&a[1]; //指標變數p指向陣列元素a[1]的地址
3、指標指向的移動(指標的偏移)
int a[10] = {0,1,2,3,4,5,6,7,8,9},*p;
p=&a[0];
++*p; //指標指向地址中的數值加1
printf(“%#p\n”,p); //列印指標變數p所指向的地址編號
p++; //指標移動到陣列元素a[1]的位置
printf(“%#X\n”,p); //列印移動後指標變數p所指向的地址編號
//指標變數++(或--)移動一次是移動其基型別大小的記憶體區域
for(int i=0;i<10;i++)
{
printf(“%d”,*(p+i)); //通過指標移動引用陣列元素,輸出陣列
//指標本身位置不改變
}
for(int i=0;i<10;i++)
{
printf(“%d”,p[i])); //通過指標帶下標的形式引用陣列元素
//[]相當於*解引用
}
for(int i=0;i<10;i++)
{
printf(“%d”,*(a+i)); //通過陣列首地址帶下標的形式引用陣列元素
//這裡不能使用*a++,陣列的首地址是一個地址常量,其指向不能被改變
}
for(int i=0;i<10;i++)
{
printf(“%d”,*p++); //指標本身的偏移(指標指向的改變)
//如果使用指標本身偏移後,再使用*(p++)就指向陣列外面未知區域去了
}
4、指標指向字串
char *p = “abcdefg”; //通過字元指標直接引用字串
//字串是一個字元陣列,其首地址是地址常量
while (*p)
{
printf("%c\t", *(p++));
}
int* p;
char* str = "abcdefg1234567890";
p = (int*)str; //將str強轉成int*型別
for(int i=0;i<strlen(str);i++)
{
printf(“%d”,*(p+i));
}
//輸出ae26 +亂碼,因為p指標一次移動4個位元組,不是一個1位元組