Posted on 2007-10-01 01:40
ZelluX 閱讀(2226)
評論(0) 編輯 收藏 所屬分類:
C/C++
水木上的帖子
s 是全局數據區(qū),
s1 是函數的棧空間區(qū)域,函數執(zhí)行完成,這個空間就沒了
------------------------------------------------------------------------------------------
7.2 可是我聽說 char a[ ] 和 char *a 是一樣的。
并非如此。(你所聽說的應該跟函數的形式參數有關;參見問題 6.4) 數組不是指針。 數組定義 char a[6] 請求預留 6 個字符的位置, 并用名稱 ``a" 表示。也就是說, 有一個稱為 ``a" 的位置, 可以放入 6 個字符。 而指針申明 char *p, 請求一個位置放置一個指針, 用名稱 ``p" 表示。 這個指針幾乎可以指向任何位置: 任何字符和任何連續(xù)的字符, 或者哪里也不指(參見問題 5.1 和 1.10)。
一個圖形勝過千言萬語。聲明
char a[] = "hello";
char *p = "world";
將會初始化下圖所示的數據結果:
+---+---+---+---+---+---+
a: | h | e | l | l | o |\0 |
+---+---+---+---+---+---+
+-----+ +---+---+---+---+---+---+
p: | *======> | w | o | r | l | d |\0 |
+-----+ +---+---+---+---+---+---+
根據 x 是數組還是指針, 類似 x[3] 這樣的引用會生成不同的代碼。認識到這一點大有裨益。以上面的聲明為例, 當編譯器看到表達式 a[3] 的時候, 它生成代碼從 a 的位置開始跳過 3 個, 然后取出那個字符. 如果它看到 p[3], 它生成代碼找到 ``p" 的位置, 取出其中的指針值, 在指針上加 3 然后取出指向的字符。換言之, a[3] 是 名為 a 的對象 (的起始位置) 之后 3 個位置的值, 而 p[3] 是 p 指向的對象的 3 個位置之后的值. 在上例中, a[3] 和 p[3] 碰巧都是 'l' , 但是編譯器到達那里的途徑不盡相同。本質的區(qū)別在于類似 a 的數組和類似 p 的指針一旦在表達式中出現就會按照不同的方法計算, 不論它們是否有下標。下一問題繼續(xù)深入解釋。 參見問題 1.13。
參考資料: [K&R2, Sec. 5.5 p. 104]; [CT&P, Sec. 4.5 pp. 64-5]。
7.3 那么, 在 C 語言中 ``指針和數組等價" 到底是什么意思 ?
在 C 語言中對數組和指針的困惑多數都來自這句話。說數組和指針 ``等價" 不表示它們相同, 甚至也不能互換。它的意思是說數組和指針的算法定義可以用指針方便的訪問數組或者模擬數組。
特別地, 等價的基礎來自這個關鍵定義:
一個 T 的數組類型的左值如果出現在表達式中會蛻變?yōu)橐粋€指向數組第一個成員的指針(除了三種例外情況); 結果指針的類型是 T 的指針。
這就是說, 一旦數組出現在表達式中, 編譯器會隱式地生成一個指向數組第一個成員地指針, 就像程序員寫出了 &a[0] 一樣。例外的情況是, 數組為 sizeof 或 & 操作符的操作數, 或者為字符數組的字符串初始值。
作為這個這個定義的后果, 編譯器并那么不嚴格區(qū)分數組下標操作符和指針。在形如 a[i] 的表達式中, 根據上邊的規(guī)則, 數組蛻化為指針然后按照指針變量的方式如 p[i] 那樣尋址, 如問題 6.2 所述, 盡管最終的內存訪問并不一樣。 如果你把數組地址賦給指針:
p = a;
那么 p[3] 和 a[3] 將會訪問同樣的成員。
參見問題 6.6 和 6.11。
------------------------------------------------------------------------------------------
char *s1 = "hello";
char s2[6] = "hello";
類型指針與類型數組名在很多場合中可等價使用。容易給人造成的印象是兩者是等價。
這話不盡然。首先我們要明白這是兩個不同的東西。
s1的類型char *,而s2的類型是array of char。
s1初始化為一個指針值,指向一個內存區(qū)域,該處有6個字符的數據,
即'h', 'e', 'l', 'l', 'o', '\0'。 在運行過程中,s1的值可改變,指向其他任何允許的地址。
但上面的數據("hello")不會在程序退出之前銷毀[注:這是另外一個比較迷惑人的細節(jié)],
即使s1變量生命周期結束。
s2初始化為6個字符的數組,也是'h', 'e', 'l', 'l', 'o', '\0'。在運行過程中,s2的內容可改變,
也就是存儲在s2中的hello也就"消失"了。
但為什么容易給人造成類型指針與類型數組名可等價的疑惑呢?雖然類型不同,但C規(guī)定(為了
追求簡潔與靈活性,C假設使用者知道自己代碼會有什么結果。)在很多場合下,認為數組名
與類型指針類型兼容。記憶中只有2中情況下,數組名不可等同視為數組指針,&與sizeof操作符。
void foo1(const char *str) {...};
void foo2(int size) {return size};
...
char *s1 = "hello";
char s2[6] = "hello";
foo1(s1); // ok
foo1(s2); // ok
foo1(&s2); // incompatible
foo2(&s2[0]); // ok
s1[0] = 0; // error
s2[0] = 0; // ok
s1 = s2; // ok
s2 = s1; // error
// 下面假設在ia32平臺上運行
foo2(sizeof(s1)); // return 4, pointer size
foo2(sizeof(s2)); // return 6, array size
只記得上面的這些內容,不知道對錯,與大家共同提高。