2013-08-20 16 views
0

在第一章,第k &ř引入了一個功能拷貝如下:K&R代碼示例混亂:複製串

void copy(char to[], char from[]) { 
/* copy from from[] to to[], assumes sufficient space */ 
    int i = 0; 
    while ((to[i] = from[i]) != '\0') { 
     i++; 
    } 
} 

周圍有點擺弄這個功能,我有一些意想不到的結果。 示例程序:

int main() { 
    char a[3] = {'h', 'a', '\n'}; 
    char b[3]; 
    printf("a: %s", a); // prints ha 
    copy(b, a); 
    printf("a: %s", a); // prints nothing 
    printf("b: %s", b); // prints ha 

    return 0; 
} 

現在我的問題:

  1. 爲什麼從a複製到b的工作,那就是爲什麼在副本while循環永遠終止,即使a不含一個'\ 0'?

  2. 爲什麼a發生了變異?

+0

這是一個未定義的行爲。這意味着每一件事都是可能的,絕對是一切。 – nouney

+3

爲什麼'int'和'char'之間的差異?如果你的編譯器沒有給你提供警告,那麼你的配置是錯誤的。 – Medinoc

+5

我假設你修改了K&R例子來使用'char'來代替?否則,所有投注都將關閉,因爲您的代碼將複製4個字節的塊,導致seg.faults和未定義的行爲。 – Lundin

回答

2

您可能正在經歷緩衝區溢出。

由於a未正常結束(缺少\0),copy副本從ab,只要它發現沒有\0。因此,有更多的字節寫入b,因爲它可以包含然後溢出到a(與平臺有關,未定義的行爲)。

溢出的部分是a之後的\0,因此使得a爲零長度字符串。

你的籌碼很可能是這樣的:

     b  a   
[ arbitrary memory ][ 0 0 0 ][ h a \n ][ 0 ? ? ? ? ] 

?表示未知數據,因爲我們不知道是什麼樣的存在,它是無處規定。 但我們知道必須是 a 0,否則printf會打印更多垃圾。

copy副本直到有零發現開始a。在a結束後偶然有 0,然後被複制到b。作爲b已經充滿 內容從ab溢出到a,使你的籌碼是這樣的:

     b   a 
[ arbitrary memory ][ h a \n ][ 0 a \n ][ 0 ? ? ? ? ] 

由於有一個\0a開始,printf假定a是空的。

1

即使你沒有明確地把'\0'在變量a,它很可能是a[3](這在技術上是出界的)恰好是零。

很多內存通常填充有零/ \0值,雖然絕對有不能保證這個。

這就解釋了爲什麼您成功將字符串複製到b

你的複製功能是錯誤的它「認爲」的ints其複製陣列感:

void copy(int to[], int from[]) { 

當它應該是複製的char acters陣列:

void copy(char to[], int char[]) { 
+2

在'char'上寫'int's也會有效果......(即它會垃圾堆棧,可能是爲什麼'a'突變)。 – trojanfoe

+0

啊,我錯過了整數部分。謝謝。 – abelenky

1

它的工作原理,因爲你的while循環沒有做一個邏輯運算,它做一個分配。 因此,只要經過循環,只要賦值爲真(並且只要它不爲零),所以它在'\ 0'(whats 0)到達時終止。 ,如果可能終止(不確定的行爲),即使沒有'\ 0'也會終止,因爲在離開你的界限之後,任何零值字節的外露的可能性非常大。但是在離開數組邊界後,程序的行爲可能是任何事情。 (它甚至可以讓鼻龍產卵;)) b不打印任何東西的原因可能是Byte順序的原因,因爲你正在將int值寫入Byte數組,所以它可能是第一個字節Byteorder放置在第一個字節中,因此從外部開始它將被視爲'\ 0',即使您的目的是將整個int視爲符號而不是4個單個值。 p.s .:這甚至會打破嚴格的別名規則。

2

這個copy函數依賴於終止空字節來確定它應該停止複製的時間。當你使用一個字符串常量時,它會自動以null結尾。然而,正常的數組不是空終止的,所以函數繼續訪問a末尾的內存,直到其中一個字節恰巧是\0。當copy函數停止複製取決於該內存區域的內容。你不知道什麼,如果有的話,恰好在那裏,所以你不知道多長時間copy將繼續複製或將發生什麼。

1

更好地檢查在下面的while循環之前是否爲NULL。

while ((to[i] = from[i]) != '\0'){ i++; }

您的問題:

1,循環終止,因爲存儲在內存中後的東西等於0(或 '\ 0'),這是不確定的。

2. a在致電副本後可能會發生變化,這也是未定義的。在ab之後存儲的兩個變量都存儲在影響範圍內。在上面提到的尼莫情況下,a突變後功能拷貝被執行。

爲了安全起見,總是在char數組的末尾插入'\ 0'。