C語言陣列與指標定義分析

2021-05-18 04:39:44 字數 1844 閱讀 5871

昨天同事寫了乙個程式,**如下:

檔案a:

char * p1 = "hello";

char p2 = "world";

檔案b:

#include

extern char * p1;

extern char * p2;

int main()

用gcc編譯以後問結果如何,回答:輸出hello和world,結果hello輸出了,world輸出的時候發生段錯誤,最後將puts(p2);語句改為puts(&p2);之後正確輸出,哎,顏面掃地啊,慚愧,慚愧,靜下心來好好琢磨一番,才有了這篇文章的誕生。

分析1:

在檔案a中定義的陣列和指標被編譯器彙編為如下**:

.file   "a.c"

.globl p1

.section        .rodata

.lc0:

.string "hello"

.data

.align 4

.type   p1, @object

.size   p1, 4

p1:.long   .lc0

.globl p2

.type   p2, @object

.size   p2, 6

p2:.string "world"

.ident  "gcc: (gnu) 4.1.2 20080704 (red hat 4.1.2-46)"

.section        .note.gnu-stack,"",@progbits

注意以p1和p2定義的差別,p1實際是乙個long大小的空間,裡面儲存的是.lc0標籤的位置,而.lc0標籤的位置代表了字串的位置,所以在檔案b中使用以下語句: puts(p1);p1代表的是乙個指標,通過指標裡面的值可以找到字串的位置,所以正確輸出。

在使用puts(p2)語句的時候,其實p2在記憶體中的位置裡面直接放的是字串,從char p2 = "world";到extern char * p2;其實發生了乙個轉變,編輯將p2當成純粹的乙個指標來使用,即在檔案b中p2和p1在編譯器的眼中是一樣的,但其實定義的時候並不一樣,這樣從p2的位置取字串的位址然後通過這個位址取的字串顯然會崩潰,因為p2中本來放的就是字串,將字串當成位址再取字串,鬼知道會指到**去,所以崩潰。

但是使用puts(&p2);語句的時候能正確,是因為編譯器將p2標籤的位址傳遞puts函式,這樣從p2的位址取的p2標籤的位置,然後再p2標籤的地方獲取字串就正確了,檔案b生成的彙編**可以看出差距:

// puts(p1)語句生成的彙編**

movl     p1, %eax

movl    %eax, (%esp)

call      puts

// puts(p2)語句生成的彙編**

movl    $p2, %eax

movl    %eax, (%esp)

call      puts

分析2

所以,通過分析1可以看出來這樣的extern使用會出問題,但在函式中使用則沒有問題,如下所示:

void foo(char p)

void foo2(char * p)

對foo和foo2函式傳遞指標和資料名沒問題,因為編譯器自己在裡面會處理,有興趣的可以看看生成的彙編**。

總結:在乙個檔案中定義字元陣列,如果在別的檔案中extern成指標的時候,感覺其實隱含了乙個型別轉換,但這個轉換雖然沒有警告,但不代表是正確的,程式執行的時候會崩潰!

c語言陣列與指標的定義 例子

對以下變數給出定義 1 int a 乙個整型數 2 int a 乙個指向整型的指標 3 int a 乙個指向指標的指標 4 int b 10 乙個包含10個整型數的陣列 5 int b 10 乙個包含10個指標的陣列,指標所指向的是整型數 6 int b 10 乙個指向包含10個整型數陣列的指標 7...

C語言指標陣列與陣列指標

初學者總是分不出指標陣列與陣列指標的區別。其實很好理解 指標陣列 首先它是乙個陣列,陣列的元素都是指標,陣列佔多少個位元組由陣列本身決定。它是 儲存指標的陣列 的簡稱。陣列指標 首先它是乙個指標,它指向乙個陣列。在32 位系統下永遠是佔4 個位元組,至於它指向的陣列佔多少位元組,不知道。它是 指向陣...

C語言指標 指標與陣列

1 指標與一維陣列 2 指標與二維陣列 3 指標陣列與陣列指標 指標裡面最難的一種就是指標與陣列了,對於指標和二維陣列來說這裡面的關係比較複雜。牽涉到編譯器的原理和編譯過程。1 指標與一維陣列 指標是指向乙個記憶體的位址,一維陣列的陣列名代表一塊記憶體 這個陣列 的首位址,和陣列首元素的位址一樣,但...