1. 程式人生 > 其它 >C語言陣列與指標的定義與宣告不一致會發生什麼?

C語言陣列與指標的定義與宣告不一致會發生什麼?

技術標籤:C和指標c語言演算法指標

下面的宣告取自某個原始檔:

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,因為都是取得未知地址的值。

這個示例很好的演示了定義和宣告保持一致的重要性!!!