C語言中,數組做為函數的參數,退化為指針。數組作為參數傳給函數時,傳的是指針而不是數組,傳遞的是數組的首元素的地址。這裡我們以將以整形變量排序來講解。
void sortArray(int a[] ,int num )以及void sortArray(int a[100] ,int num )都可以用void sortArray(int *a ,int num )表示。一般來說函數參數如果為數組,可以有兩個參數,一個是數組名,一個是數組長度。對於排序而已,一般是要知道給定數組的首元素的地址,即需要排序的數組在內存中的起始地址,同時還需給定待排序的數據個數。
這裡我們采用簡單的冒泡排序,模塊代碼如下:
/*2016-7-12 Jason Gel */ void sortArray(int *a ,int num ) { int i ,j ,temp; for(i =0 ;ia[j]) //交換類代碼 { temp = a[i]; a[i]=a[j]; a[j]=temp; } } } }
如果a是一個數組,很顯然大家都知道如何傳遞參數,代碼如下:
int num =0 ; //在32機器中告訴C編譯器分配4個字節的內存 int a [] = {1,3,5,12,6,7,54,32}; //告訴C編譯器分配32個字節的內存 // num = sizeof(a)/sizeof(int); num = sizeof(a)/sizeof(a[0]); printf("排序之前:"); printArray(a,num); sortArray(a,num); printf("排序之後:"); printArray(a,num); }如果a是一個單一整形變量的地址,還能類似於用num = sizeof(a)/sizeof(a[0]) 求得num的值嗎?如以下代碼:
int test =5; int *p = &test; int num1 = 0; num1 = sizeof(p)/sizeof(p[0]); sortArray(p,num1); printf("排序之後:"); printArray(p,num1);
這樣可以嗎?很多人犯迷糊了,p[0]不是指數組首元素的值嗎,這裡p不是數組啊,p[0]都好像不存在,怎麼能這樣用?我們一定還記得,在C語言中可以用指針表示數組的每一個元素,本質上,對同一個對象有兩種不同的符號表示,如定義:a[n]時等價於*(a+n),即尋址到內存的a,然後移動n個單元,再取出數組。故p[0]等價於*(p+0),該值的類型為int型。
num1=sizeof(p)/sizeof(p[0]) 等價於 num1=sizeof(p)/sizeof(int );
該語句在語法上面沒有任何錯誤,但是在32機器和64位機器運行結果不同,在32機器出現正常結果,64位機器出現錯誤結果,原因見本文最後。
/** 函數原型聲明4中等價形式 int sum (int *a , int n) int sum (int * , int ) int sum (int a[] , int n) int sum (int [] , int ) //可能略微不熟悉的一種 */定義函數時,名稱是不可以省略的,以下兩種形式是等價的。
/** 函數原型聲明4中等價形式 int sum (int *a , int n) {} int sum (int a[] , int n) {} */
int num =0 ; //在32機器中告訴C編譯器分配4個字節的內存 int a [] = {1,3,5,12,6,7,54,32}; //告訴C編譯器分配32個字節的內存 printf("a:%d ,a+1:%d,&a:%d,&a+1:%d\n",a,a+1,&a,&a+1) ; //a+1 和 &a+1 結果不一樣 //雖然輸出結果上面,a和&a一樣 。 但是a 和 &a所代表的數據類型不一樣 /*重要*/ //a 代表的數據首元素的地址 (首元素),同時與整個數組地址重合,但其不能代表整個數組,只能代表起始個體的地址 //&a代表的是整個數組的地址 (特別特別的注意) 它的加1是以整塊數組所占字節數總數為單位1輸出結果:a:1638176 ,a+1:1638180,&a:1638176,&a+1:1638208
/** 2016-7-12 Jason Gel **/ #include#include #include //void printArray(int * a ,int num ) 和 void printArray(int a[] ,int num )是等價的 //函數定義時候,名稱是不可以省略的。函數原型容許省略名稱。 /** 函數原型聲明4中等價形式 int sum (int *a , int n) int sum (int * , int ) int sum (int a[] , int n) int sum (int [] , int ) //可能略微不熟悉的一種 */ void printArray(int * a ,int num ) { int i ; for(i = 0; i< num; i++) { printf("%3d",a[i]); } printf("\n"); } //這裡用的是冒泡排序(起泡排序) void sortArray(int *a ,int num ) { int i ,j ,temp; for(i =0 ;i a[j]) //交換類代碼 { temp = a[i]; a[i]=a[j]; a[j]=temp; } } } } int main () { int num =0 ; //在32機器中告訴C編譯器分配4個字節的內存 int a [] = {1,3,5,12,6,7,54,32}; //告訴C編譯器分配32個字節的內存 int test =5; int *p = &test; int num1 = 0; num1 = sizeof(p)/sizeof(p[0]); printf("num1:%d, sizeof(p):%d,sizeof(p[0]):%d \n",num1,sizeof(p),sizeof(p[0])); sortArray(p,num1); printf("單一元素排序之後:"); printArray(p,num1); printf("a:%d ,a+1:%d,&a:%d,&a+1:%d\n",a,a+1,&a,&a+1) ; printf("sizeof(num1):%d\n",sizeof(num1)); printf("sizeof(a):%d\n\n",sizeof(a)); printf("sizeof(int):%d sizeof(double):%d sizeof(char):%d \n",sizeof(int),sizeof(double),sizeof(char)) ; printf("sizeof(int *):%d sizeof(double*):%d sizeof(char*):%d \n",sizeof(int *),sizeof(double*),sizeof(char*)) ; //a+1 和 &a+1 結果不一樣 //雖然輸出結果上面,a和&a一樣 。 但是a 和 &a所代表的數據類型不一樣 /*重要*/ //a 代表的數據首元素的地址 (首元素),同時與整個數組地址重合,但其不能代表整個數組,只能代表起始個體的地址 //&a代表的是整個數組的地址 (特別特別的注意) 它的加1是以整塊數組所占字節數總數為單位1 // num =sizeof(a);//這個是獲取的整個數組的字節數,為32個字節 printf("實參a的數據類型為整個數組,所占字節為:%d \n",sizeof(a)) ; // num = sizeof(a)/sizeof(int); num = sizeof(a)/sizeof(a[0]); //注意規范 printf("排序之前:"); printArray(a,num); sortArray(a,num); printf("排序之後:"); printArray(a,num); return 0; }
VC 32位編譯器 運行截圖:
64位編譯器運行截圖:
核心:
可以看出在64位機器中,int*的指針為8個字節,在32位中int*為 4個字節,由於:
sizeof(p)/sizeof(p[0]) //等價於sizeof(int * ) /sizeof( int )
所以在64位機器上面原本應該為1的現在變成了2,導致程序出現錯誤。
從程序輸出結果我們可以看出:實參a的數據類型為整個數組,所占字節為32。雖然實參a表示的是數組名,但是它實際的數據類型不是int *,而是表示的整個數組所占字節數。這裡不要與前文的a與&a表示地址時候弄混淆。