2009-10-21 156 views
5

我想了解strcpy和strncpy的區別/缺點。 有人可以請幫助:當dest緩衝區小於src緩衝區時strcpy

void main() 
{ 
char src[] = "this is a long string"; 
char dest[5]; 

strcpy(dest,src) ; 
printf("%s \n", dest); 
printf("%s \n", src); 

} 

輸出是:

this is a long string 
a long string 

問:我不明白,源刺痛是怎麼修改。按照解釋,strcpy的應該保持複製,直到它遇到「\ 0」,它確實是這樣,但怎麼來的「SRC」字符串得到了修改。

請解釋。

+0

這稱爲緩衝區Overun。 – lsalamon 2009-10-21 16:00:36

+0

此緩衝區溢出問題說明了爲什麼您應該選擇使用strcpy而不是strcpy。 – 2009-10-21 16:03:24

+0

我無法重現您的代碼。我在dest數組中獲得'tring'。 – Spidey 2009-10-21 16:35:07

回答

11

簡單的答案是你有(用這個strcpy()調用)在系統的規範之外做了一些事情,因此當之無愧地遭受未定義的行爲。

更困難的答案涉及檢查系統上的具體內存佈局以及strcpy()如何在內部工作。它可能是這樣的:

 N+28 "g0PP" 
    N+24 "trin" 
    N+20 "ng s" 
    N+16 "a lo" 
    N+12 " is " 
src N+08 "this" 
    N+04 "DPPP" 
dest N+00 "DDDD" 

字母D代表在dest字節,字母P是填充字節,0字符作爲字符串終止ASCII NULL字符。

現在的strcpy(DEST,SRC)將有所改變存儲器的內容(假定它能夠正確地處理重疊的內存區域):

 N+28 "g0PP" 
    N+24 "trin" 
    N+20 "g0 s" 
    N+16 "trin" 
    N+12 "ng s" 
src N+08 "a lo" 
    N+04 " is " 
dest N+00 "this" 

即而dest現在「包含」完整的字符串「這是一個很長的字符串」(如果你計算溢出的內存),src現在包含一個完全不同的以NUL結尾的字符串「long string」。

7

這是一個緩衝區溢出和undefined行爲。

在你的情況,似乎編譯器已放置destsrc順序在內存中,當你拷貝從srcdest,繼續複製過去的dest年底覆蓋的src一部分。

+0

你能否說得更具描述性?讓我們考慮一下我的dest和src在內存中是連續的。所以他們應該從位置1000開始(說).. 因此,dest需要1000-1004(5個字節),src需要22個字節(21個字符+空終止)。 所以我們總共使用了27個字節1000到1026. 如果我提到的(在內存方面)是正確的,請詳細解釋src是如何被覆蓋的? – user193891 2009-10-21 16:03:39

+2

並且src和dst似乎與4個字符的倍數對齊,所以在dest長度爲5個字符的情況下,新的mangled src將啓動8個字符到原始src(它現在爲dest)。 – ndim 2009-10-21 16:04:33

+0

您能否解釋一下內存映射,以便更容易理解?只是假設所有分配的內存都從地址1000開始分配..你能解釋strcpy前後dest和src佔用的空間嗎? – user193891 2009-10-21 16:21:17

1

高度親切的字符串是確切的鄰居。所以在你的情況下,你可能有這張圖片

dst | | | | | src | | | | | |

所以你開始寫,它發生了src的字段被覆蓋。

Howerver你肯定不會依賴它。一切都可能發生,你有什麼是未定義的行爲。所以其他時間和/或其他選項可能會在其他計算機上發生其他情況。

問候 弗里德里希

0

我建議的快速閱讀:

http://en.wikipedia.org/wiki/Strncpy#strncpy

這表明你的差異。基本上,strncpy可以讓你指定要複製的字節數,這意味着結果字符串不一定是終止的。

現在,當您使用strcpy將一個字符串複製到另一個字符串時,它不會檢查結果區域的內存以查看它是否足夠大 - 它在這方面不牽涉到您的手。它檢查src字符串中的空字符。

當然,這個例子中的dst只有5個字節。那麼會發生什麼?它不斷地寫作,直到目的地的結尾,然後繼續記憶。在這種情況下,堆棧中的下一部分內存是您的src字符串。所以雖然你的代碼並不是有意的拷貝它,但是內存中的字節佈局加上dst結尾的寫入操作導致了這一點。

希望有幫助!

1

您的代碼導致緩衝區溢出 - 複製到dest的目標字符多於它所能容納的字符數。 附加字符被寫在棧上的另一個地方,在你的情況下,src指向的地方。

您需要使用strncpy()函數。

0

無論是我誤解你的問題,或者你誤解的strcpy:

問:我不明白,在 源刺痛是怎麼修改。按照 解釋的strcpy應該保持 複製,直到它遇到「\ 0」,所以 它,但怎麼來的「SRC」字符串得到 修改。

這聽起來好像是你期待strcpy在到達dest結尾時停止複製到dest,基於看到一個\0字符,這不是它所做的,strcpy將複製到目標,直到到達源字符串的末尾,由\0字符分隔。它假定你爲拷貝分配了足夠的內存,在拷貝之前,dest緩衝區可以包含任何內容,包括所有的空值。strncpy通過讓你真正地告訴它你複製的緩衝區有多大來解決這個問題,所以你可以避免複製超過適合的情況。

1

作爲附加說明,請記住,strncpy功能不適合在需要使用緩衝區溢出保護進行復制時使用。這個功能並不是爲此目的而設計的,從來沒有用於這個目的。 strncpy是很久以前創建的一個函數,用於在某些舊版本的UNIX中的某些非常特定的文件系統中執行一些非常特定於應用程序的字符串複製。不幸的是,該圖書館的作者設法「剽竊」了通用冠冕堂皇的名字strncpy,以用於這個非常狹窄和特定的目的。爲了向後兼容的目的,它被保存下來。而現在,我們有一兩代程序員完全根據其名稱做出關於strncpy目的的假設,因此不恰當地使用它。實際上,strncpy幾乎沒有任何有意義的用途。

C標準庫(至少它的C89/90版本)不提供帶緩衝區溢出保護的字符串複製功能。爲了執行這種受保護的複製,您必須使用某個平臺特定的功能,如strlcpystrcpy_s或自己寫一個。

P.S. StackOverflow上的這個thread包含了一個關於真正目的strncpy開發的好的討論。請參閱此post專門用於精確說明其在UNIX文件系統中的角色。此外,請參閱here以獲得有關如何獲得strncpy的好文章。

再次,strncpy是複製完全不同類型的字符串 - 固定長度字符串的函數。它甚至不打算用於傳統的C風格的以null結尾的字符串。

+0

我發現strncpy有用說,如果我有一個緩衝區,並從文本文件讀取行,我知道這將是 2009-10-21 17:45:52

+0

@詹姆斯莫里斯:我沒有看到你到底想通過在那裏使用'strncpy'來達到什麼目的。在這種情況下,'strncpy'的哪個特性對你很重要? – AnT 2009-10-21 17:53:53

+0

這種方式的答案不正確。 strncpy肯定不會超過一個緩衝區,如果你有一個「字符串」 b)你有正確的長度適當的空間。 對於這一切,你可能最好使用下面的代碼(僞C,部分取自代碼完成II) char buf [MAX_LEN + 1]; strncpy(buf,src,MAX_LEN); 在這種情況下,strncpy比strcpy更安全。但是你說的是,標準C中沒有一個功能可以「緩衝」超限保護。這就是C如何實現,速度,速度,速度 – Friedrich 2009-10-22 03:40:59