懂得C語言的人都知道,C語言之所以強大,以及其自由性,絕大部分體現在其靈活的指標運用上。因此,說指標是c語言的靈魂,一點都不為過。所以從我的標題加了個(一)也可以看出指標的重要性,我儘可能的向大家交代清楚我對於指標的理解。所以在講解的過程中我儘可能的用代碼加文字的描述方式,通過代碼的分析來加深我們對於指標的理解,我給出的都是完整的代碼,所以讀者可以在看的過程中直接copy下去即可運行,希望下面的講解能夠對你有所協助。
首先讓我們來看看定義一個指標的一般形式為:
基底類型 *指標變數名
看了上面的指標的定義形式,我們可能對於有些地方會有疑惑,如為什麼要指定基底類型呢?因為我們都知道整型和字元型在記憶體中占的位元組數是不相同的,當我們進行指標的移動和指標的運算時,如果指標指向的是一個整型變數,那麼指標移動一個位置就是移動4個位元組,但是如果指標指向的是一個字元型的變數,那麼指標移動的就是一個位元組,因此我們必須規定指標變數所指向的基底類型。
為了不枯燥的講解我們來看看下面的代碼吧。(注意:本部落格的所有代碼均使用vc6編譯運行,所以可能有的規則跟C語言的稍有區別)
#include <stdio.h>
int main()
{
int a,b;
int *pointer_1,*pointer_2;
a=100;
b=200;
pointer_1=&a;
pointer_2=&b;
printf("--------------------變換前-------------------\n");
printf("a=%d\tb=%d\n",a,b);
printf("*pointer_1=%d\t*pointer_2=%d\n",*pointer_1,*pointer_2);
*pointer_1=300;
int c=500;
pointer_2=&c;
printf("--------------------變換後-------------------\n");
printf("a=%d\t*pointer_1=%d\n",a,*pointer_1);
printf("c=%d\tb=%d\t*pointer_2=%d\n",c,b,*pointer_2);
}
運行結果如下:
在此我們定義了兩個整型指標int *pointer_1,*pointer_2;,它們分別指向變數a和b,值得注意的是*pointer_1和a、*pointer_2和b是共用同一個儲存空間的,當我們在接下類的代碼中改變 *pointer_1=300;時,由輸出就可以看出來a的值也跟隨發生了改變。但是當我們聲明了一個 int c=500;之後,使用pointer_2=&c;,b的值不變,僅僅是改變*pointer_2,因為我僅僅是改變了*pointer_2指向了c的儲存空間,如果有有興趣的讀者可以自己驗證下如果我們修改了a的值之後*pointer_1的值會跟隨一起改變,因為他們指向的是同一個儲存空間。
接下來看看如何在函數的參數中來使用指標。
#include <stdio.h>
swap(int p1,int p2)
{
int temp;
temp=p1;
p1=p2;
p2=temp;
}
int main()
{
int a,b;
int *pointer_1,*pointer_2;
int c,d;
c=a;
d=b;
pointer_1=&a;
pointer_2=&b;
a=20;
b=30;
swap(a,b);
printf("a=%d\tb=%d\n",a,b);
printf("a=%d\tb=%d\n",*pointer_1,*pointer_2);
printf("c=%d\td=%d\n",c,d);
}
初步分析上面的代碼,看似是要通過一個函數的調用來實現一個a、b的交換,還有就是通過c=a;、 d=b;來實現對c、d賦初值。先來看看下面的運行結果:
結果跟我們想象的不一樣,a、b沒有實現交換的原因是因為我們使用的是傳值,而不是傳址,所以調用的過程中做的處理就是把a、b的值複製到另外申請的兩個空間p1、p2中去,因而交換操作是在p1、p2的空間中進行的,所以對於a、b的值並沒有影響。c、d的初值為什麼沒有跟a、b的值一樣呢,因為我們在初始化的過程中給c、d賦初值的時候a、b的並沒有給定初值,所以a、b的初值是在編譯的過程中由系統給定的,又因為我們申請的c、d的空間是跟a、b沒有任何關係的,所以接下來再對a、b賦初值的時候c、d的初值並不會改變。
下一個代碼:
#include <stdio.h>
swap(int *p1,int *p2)
{
int *temp;
temp=p1;
p1=p2;
p2=temp;
}
int main()
{
int a,b;
int *pointer_1,*pointer_2;
int c,d;
c=a;
d=b;
pointer_1=&a;
pointer_2=&b;
a=20;
b=30;
printf("********************調用前******************\n");
printf("a=%d\tb=%d\n",a,b);
swap(pointer_1,pointer_2);
printf("********************調用後******************\n");
printf("a=%d\tb=%d\n",a,b);
printf("*pointer_1=%d\t*pointer_2=%d\n",*pointer_1,*pointer_2);
printf("c=%d\td=%d\n",c,d);
return 0;
}
看看上面這個代碼似乎滿足了我們前面說的傳址的要求,那先讓我們來看看實驗結果吧。
結果似乎也是出乎我們的意料之外,為什麼使用了傳值卻還是沒有能夠實現呢?如果我們在調用函數中加上一句 printf("*p1=%d\t*p2=%d\n",*p1,*p2);,得到下面的結果:
從結果來看似乎告訴我們,我們已經實現交換了,但是為什麼沒有能夠返回來呢?在這裡要注意了,因為我們在函數的交換語句僅僅是改變了局部指標變數p1和p2的值,所以沒有改變a、b的值,所以使用printf("*p1=%d\t*p2=%d\n",*p1,*p2);使得我們的確看到了a、b交換的假象,僅僅是改變了局部變數p1和p2的值。
下一個代碼:
#include <stdio.h>
#include <stdlib.h>
swap(int *p1,int *p2)
{
int *temp;
temp=(int *)malloc(sizeof(int));
*temp=*p1;
*p1=*p2;
*p2=*temp;
free(temp);
}
int main()
{
int a,b;
int *pointer_1,*pointer_2;
int c,d;
c=a;
d=b;
pointer_1=&a;
pointer_2=&b;
a=20;
b=30;
printf("********************調用前******************\n");
printf("a=%d\tb=%d\n",a,b);
swap(pointer_1,pointer_2);
printf("********************調用後******************\n");
printf("a=%d\tb=%d\n",a,b);
printf("*pointer_1=%d\t*pointer_2=%d\n",*pointer_1,*pointer_2);
printf("c=%d\td=%d\n",c,d);
return 0;
}
看看也行結果:
最後終於出現了一個我們想要的結果了。從以上的分析讀者自己也知道原因所在了吧,這裡操作的才是p1、p2所指向的地址,才真正的做到了對於a、b儲存空間的數值的交換。細心的讀者可能看到了我們在代碼中用了紅色部分標記的代碼,它完全可以用一句int temp;來替代,之所以我們在這裡要用int *temp;無非是要大家牢記對於指標一些特殊的使用,如果我們沒有這句temp=(int *)malloc(sizeof(int));,以上代碼在編譯的過程中是不會有任何錯誤的,但是在啟動並執行過程中就會出現錯誤,所以通常情況下我們在使用指標的過程中,要特別注意野指標情況的出現,以免出現一些莫名奇妙的有錯。