近日閱讀c專家編程,對c語言中的指針數組的區別有了新的認識。
先看一段代碼:
//des.c
int a[] = {3,2};
void hello(){
printf("d.c %d",a);
}
//test.c
#include<stdio.h>
extern void hello();
extern int *a;
int main(void){
hello();
printf("\n : %d",a);
//printf("\n : %d",a[1]);
return EXIT_SUCCESS;
}
上面的代碼的輸出爲
d.c 134520856
: 3
第一行代碼是第一個文件d.c輸出了int a[];a的內容
第二行代碼是第二個文件hello.c輸出了extern int *a;指針a的內容
gcc編譯的時候,在鏈接階段了,hello.o有extern a符號,在d.o中找到,所以extern a 和d.o的a是同一個符號(我認爲稱他們“指向相同”有歧義)
也可以用圖像表示
。數組第一項在內存地址134520856處。
第一個文件d.c將a當成數組來處理,可以按照想象的進行輸出,但是
但是第二個文件是把符號a當成指針來操作的(因爲 extern int *a), 指針所在的地址是134520856,但是指針的值是3
如果去掉註釋之後,則會報錯,因爲在main函數中,按照編譯器的規矩,a[1]可以被我們這樣認爲 *(a+1);
因爲a等於3,a+1等於4,*(a+1)的意思就是取內存地址爲4的字節內容,我不知道地址爲4的那個字節裏面是什麼東西。
再看下面代碼:
int *a;
void hello(){
a =(int *) malloc(2);
a[0]=3;
a[1]=2;
printf("d.c %d",a);
}
extern void hello();
extern int *a;
int main(void){
hello();
printf("\n : %d",a);
return EXIT_SUCCESS;
}
輸出結果:
d.c 161968136
: 161968136
我說了實際上 只要是extern a就表示這兩個a符號,實際上是同一個符號a,(你可以將兩個文件的函數輸出&a,就會發現他們的地址是一樣的)。
這種情況下的內存分配是這樣的。
最後再看一個代碼:
int *a;void hello(){
a =(int *) malloc(2);
a[0]=3;
a[1]=2;
printf("d.c value:%d\n",a);
printf("d.c address:%d\n",&a);
}
extern void hello();
extern int a[];
int main(void){
hello();
printf("hello.c value:%d\n",a);
printf("hello.c address:%d\n",&a);
printf("hello.c a[1]",a[1]);
return EXIT_SUCCESS;
}
輸出結果爲:
d.c value:160223240
d.c address:134520864
hello.c value:134520864
hello.c address:134520864
hello.c a[1]
內存分佈圖爲:
在hello.c中,a被當成int a[];
a的值爲160223240, *(a+1),就能夠訪問到2.
總結:
編譯器在編譯的時候左值會由編譯器分配地址,而右值運行時才能知道,當我們聲明一個指針變量的時候,會首先爲指針變量開闢一個內存空間,
即指針地址是確定的,但是指針所指向的地方時在運行時才知道。如果使用指針引用定義數組中的元素時,會將數組元素的值解析成地址,就造成了
訪問錯誤