C語言陣列與指標的定義與宣告不一致會發生什麼?
阿新 • • 發佈:2021-01-17
下面的宣告取自某個原始檔:
int a[10];
int *b = a;
但在另一個原始檔中,卻發現了這樣的程式碼:
extern int *a;
extern int b[];
int x,y;
...
x = a[3];
y = b[3];
請解釋一下,當兩條賦值語句執行時會發生什麼?(假定整型和指標的長度都是4個位元組。)
int a[10];
int *b = a;與
extern int *a;
extern int b[];宣告和定義並不一致。
先看一下程式跑的結果吧:
//file: a.c int a[10] = {1,2,3,4,5,6,7,8,9,10}; int *b = a; void test() { printf("a: 0x%x\n", a); int i; for(i = 0; i < 10; i++) { printf("&a[%d] = 0x%x\n",i, &a[i]); } printf("b: 0x%x\n", b); }
#include <stdio.h>
extern int *a;
extern int b[];
extern test();
int x, y;
int main () {
test();
x = a[3];
y = b[3];
return 0;
}
我們先看一下test函式列印的結果:
- 在a.c檔案中:
a陣列的起始地址這次是0x404040,b是一個指標也指向了這個地址。
- 在main.c檔案中:
> p a $1 = (int *) 0x200000001 > p a+1 $2 = (int *) 0x200000005 > p *a Cannot access memory at address 0x200000001 > p a[3] Cannot access memory at address 0x20000000d
int *a 是某個地方的整型指標,這個指標的地址並不知道,儲存的內容也不知道,我們debug打出這次的地址是0x200000001,內容無法獲取。
所以這裡利用a[3]即 *(a+ 3*4) = 0x20000000d來訪問一個未知的地址內容雖然有可能會有值,但也是不允許的。
所以 x = a[3]; 會Crash。
我們再來看一下b,b在a.c檔案中是一個整型指標,指向a陣列的起始地址0x404040。
在main.c檔案中,b被宣告為一個整形陣列
> p b $3 = 0x404068 <b> > p b[3] $4 = 0 > p b[0] $7 = 4210752 > p b[1] $8 = 0 > p b[3] $9 = 0 > p &b $10 = (int (*)[]) 0x404068 <b> > p &b[0] $11 = (int *) 0x404068 <b> > p &b[3] $12 = (int *) 0x404074 <x>
這次b陣列的起始地址是0x404068 ,可以看到和a陣列沒有任何關係,b[3]的地址即0x404068 + 12個位元組,即0x404074 ,這個地址並不知道儲存的什麼東西,雖然這裡取值有可能取到,但也是不允許的。
這裡我特意把a陣列初始化成了非0,所以這裡也可以很清楚的看到main.c中宣告為陣列的b的地址和a.c中的a陣列並不一樣,main.c中b[3]的地址也不再a.c中的b陣列範圍內,儲存的內容也不一樣。
所以這2個賦值有可能不會Crash,也有可能會Crash,因為都是取得未知地址的值。
這個示例很好的演示了定義和宣告保持一致的重要性!!!