指針在C語言中的地位很高。記得上大學那會,不是能夠很好的理解指針這個東西,經常一節課下來聽懂的並沒有多少,當然,主要原因是沒好好聽課。這幾年中對於編程語言的理解更加的進步,漸漸的,也就能夠明白原來指針是這樣的。
指針---就是內存地址。也是一個變量,只是這個變量中保存的數據是其他變量的地址而已。這裏說了指針也是一個變量,那麼指針的聲明應該是和變量的聲明一樣嘍。是的,但也有一點不一樣。
變量的聲明是:type var_name;
指針的聲明是:type *var_name;
type代表變量的數據類型,var_name是變量名,才從上面的對比中可以發現,指針在聲明時,在變量名之前加了一個 * ,這個可以算是指針的標識了。
關於指針變量的類型,必須是有效的C語言數據類型。這個類型指的是指針這個變量所指向的變量的類型。這句話的意思是,無論你聲明一個int類型的指針還是聲明一個char類型的指針,指針對象的類型是一樣的,不同的是指針所指向的那個變量的類型一個是int類型,一個是char類型。下面,聲明幾個指針:
int *ip;
double *dp;
float *fp;
char *ch;
上面聲明瞭4個指針變量,這4個指針變量的類型是相同的,但是指向的變量的類型不同。下面,來看看指針的使用。上面我們說到了一個符號: * 下面我們在來說一個符號: & 。
在C語言中,每一個變量都有地址,每一個變量的內存地址,都可以使用&訪問:
int a = 10;
printf("%x\n", &a);
打印結果:5fbff7dc
Program ended with exit code: 0
這裏就是使用 & 去變量a的地址。下面我們來使用 * 這個符號來定義一個指針,用來保存變量a的地址。
int *ip;
int a = 10;
ip = &a;
printf("%x\n", &a);
printf("%x\n", ip);
打印結果:
5fbff7f4
5fbff7f4
Program ended with exit code: 0
通過上面的結果我們可以看到,兩個打印結果相同,這裏就證實了,指針就是變量的內存地址。
上面代碼中:ip = &a;是給指針變量賦值的語句,是將變量a的內存地址賦值給指針變量ip。在實際的開發中,有時我在定義指針的時候,並不能知曉要賦何值給這個指針,那麼給指針變量賦一個NULL是一個很好的習慣,這樣的指針是一個空指針。空指針是一個定義在標準庫中的值爲0的常量。
指針的聲明和定義已經說了,下面來說下指針相關的操作和使用:
1、指針的運算。
指針的運算分爲算術運算和邏輯運算,算術運算的符號有:++,--,+,-。邏輯運算符號有:==,<,>,<=,>=。下面逐個說明。
還用上面我們聲明的指針ip,在上面ip的打印結果是5fbff7f4
我們在代碼中加入 ip++; 再打印ip的結果,
int *ip;
int a = 10;
ip = &a;
printf("%x\n", &a);
printf("%x\n", ip);
ip++;
printf("%x\n", ip);
運行結果:5fbff7f4
5fbff7f4
5fbff7f8
Program ended with exit code: 0
當我們對ip進行自增運算的時候,其結果比不是+1,而是+4,這是爲何?我們知道,指針是變量的內存地址,在上面的打印結果也證實了這一點。這樣就很好理解了,我們知道,在內存管理中,int類型的數據在內存中佔有4個字節的內存,所以,ip++就不是簡單的+1,而是加了一個內存空間。ip++後,指向的是變量a的內存地址後面的那個地址了。同理,ip--也不是簡單的-1而是-4。
我們在用代碼來看看+,-運算:
int *ip;
int a = 10;
ip = &a;
printf("%x\n", &a);
printf("%x\n", ip);
ip++;
printf("%x\n", ip);
ip -= 2;
printf("%x\n", ip);
ip += 1;
printf("%x\n", ip);
打印結果:5fbff7f4
5fbff7f4
5fbff7f8
5fbff7f0
5fbff7f4
Program ended with exit code: 0
從打印結果來看,ip+2,也不是直接+2,而是加了兩個int類型的內存空間(也就是8個字節),ip-1也是減去了1個int類型的內存空間(4個字節)。
相對於算術運算,邏輯預算更簡單,指針也是變量,所以指針的邏輯運算和其他變量的邏輯運算相同。這裏就不多說了。
在指針的知識中,還有一個很重要的東西,指針數組。
在上一篇文章中,已經對數組的知識進行了簡單整理,知道了數組的用途很廣泛。可能有一種情況,我們想讓數組存儲的不是直接的變量,而是指向變量的指針,這就要用到指針數組。下面我們來看一個示例:
聲明一個指向int類型的指針數組:
int a[3] = {10,20,30};
int *array[3];
for (int i = 0; i < 3; i++) {
array[i] = &a[i];
}
for (int j = 0; j < 3; j++) {
printf("a[%d]的地址:%x, 值:%d\n", j, array[j], *array[j]);
}
打印結果:
a[0]的地址:5fbff7fc, 值:10
a[1]的地址:5fbff800, 值:20
a[2]的地址:5fbff804, 值:30
Program ended with exit code: 0
從代碼和結果來看,array數組就是一個指針數組,存儲了數組a中變量的內存地址。
下面,再來說說指向指針的指針-----二級指針。
指針中存在多級指針的概念,二級指針是最簡單的多級指針。先來看一張圖:
通過上面的圖,很容易發現二級指針,其實就是指向變量內存地址的指針。就如同上面圖裏的那樣,變量a是一個整型變量,值爲100,定義一個指針p指向a,那麼,p中保存的值就是a的內存地址,再用一個指針q指向指針p,q中保存的就是指針p的內存地址。這就是二級指針。
聲明二級指針要用兩個符號 * ,下面是一段二級指針的代碼:
int a = 100;
int *p = &a;
int **q = &p;
printf("a = %d,p = %x,q = %x\n", a, p, q);
printf("a = %d\n", *p);
printf("a = %d\n", **q);
printf("p = %x\n", &a);
printf("p = %x\n", *q);
printf("q = %x\n", &p);
打印結果:
a = 100,p = 5fbff7fc,q = 5fbff7f0
a = 100
a = 100
p = 5fbff7fc
p = 5fbff7fc
q = 5fbff7f0
Program ended with exit code: 0
通過上面的代碼和打印結果,很明顯就可以看出二級指針,指針,變量三者之間的聯繫。這裏要注意一點不能使用&&a的方式來獲取a變量的二級指針。
還有一點關於指針的使用時將指針作爲函數的參數,或者作爲函數的返回值。指針也是變量,這樣的話,作爲函數的參數就很好理解了,只是在函數定義的時候,將形參定義爲指針即可。我們說的main函數就有一個指針數組作爲形參。還有將指針作爲函數的返回值,這個需要在函數聲明時,返回值類型是指針,如:int *getMax();這樣就可以返回一個指針了。另外需要注意一點,C語言中不允許,在函數外返回局部變量的地址,想要返回局部變量,可將局部變量修飾我static變量。