2012-12-28 245 views
8

我只是用strncpy搞亂了。strncpy導致分段錯誤

我的程序看起來像這樣

typedef struct 
{ 
    char from_str[10]; 
}test; 

main() 
{ 

    test  s1; 
    memset(&s1,0,sizeof(test)); 
    char  src[10]="himansh"; 
    char  dest[10]; 

    memset(dest,0,10); 
    src[3]='\0'; 

    printf("src is %s and strlen is %d \n", 
      src,strlen(src)); 

    fflush(stdout); 

    strncpy(s1.from_str,src,100); 

    printf("s1.from_str is %s , src is %s \n", 
      s1.from_str,src); 
    return 1; 

} 

這裏之前,我做函數strncpy我已經在「SRC」字符串,長度的「SRC」字符串變成3增加了一個「\ 0」字符,目的地陣列大小的10.但是在strncpy中,我把要複製的字節數設爲100.

這意味着我的源字符串以NULL結尾。現在像任何字符串函數一樣,strncpy應該儘量只複製3個字節,即使我提供的字節數大於3(本例中爲100)。它是這樣做的,但我也遇到了分段錯誤。

我的結果如下所示

src is him and strlen is 3 
s1.from_str is him , src is him 
Segmentation fault (core dumped) 

這是爲什麼分割故障發生在這裏。

任何人都可以在這裏幫助我。

+0

你認爲它應該嘗試做什麼,它做什麼是兩個完全不同的東西。 –

回答

13

我可以指出你的男人網頁,網站等,但最終重要的是C標準本身。作爲標準運行時庫的一部分,使用和行爲在C99-§7.23.2.4定義爲:

#include <string.h> 
char *strncpy(char * restrict s1, 
     const char * restrict s2, 
     size_t n); 

說明strncpy功能拷貝不超過n個字符(即遵循一個字符空字符不會被複制)從s2指向的數組轉到 s1指向的數組。如果在重疊對象之間進行復制,則行爲不確定。 如果s2指向的數組的長度小於n個字符,則在s1指向的數組副本中會添加空字符,直到寫入全部n個字符爲止。

返回 strncpy函數返回s1的值。

顯著隱含的信息在這裏,最重要的是:strncpy()以空字符終止您的目標字符串,如果源字符串長度(不包括其空字符終止)達到或超過指定的目標緩衝區長度)。

此外,雖然在標準中明確規定(見上文),它繼續混淆了我很多的工程師怎麼都沒有意識到,strncpy()尾填充空字符到指定的長度n目標字符串緩衝區到達時源字符串長度爲,比目標緩衝區大小小。這得出了以下不可避免的結論:

strncpy() API將始終將n字符寫入目標緩衝區引用的地址。

在你的情況,因爲目標緩衝區只有10字符寬,你寫90個其他字符過去寫存儲器的定義高端,因此走進的未定義行爲土地。

在這一點上,你必須問自己:「那麼最新的使用?」有一個可以說是最基本的用例。它允許你複製最多n字符到目標緩衝區,並且知道你不會超過n字符。期。不過說到底,你想有一個空值終止字符串,因此正確用法是這樣的:

char dst[ N ]; 
strncpy(dst, src, N-1); 
dst[N-1] = 0; 

其中Ndst緩衝區的硬長度字符,是大於,或相等到1。需要注意的是dst可能只是-AS-不失爲一個動態分配的內存指針:

char *dst = malloc(N * sizeof(char)); 
strncpy(dst, src, N-1); 
dst[N-1] = 0; 

通過上述,您將總是必須在dst一個空結尾的字符串。如果源字符串長度爲小於指定的目標緩衝區長度,則strncpy()將用空字符尾部填充緩衝區的其餘部分,直到源字符複製+尾部填充空字符總數等於n,並且最後的陳述是多餘的。如果源字符串長度爲等於或大於目標緩衝區長度,則strncpy()將停止複製一次N-1達到字符數,並且最終語句在緩衝區末尾設置空字符。這會導致原始源代碼的「精簡」前綴字符串,但最重要的是,它可以確保您不會超出目標緩衝區的邊界,而後面的字符串API調用將掃描終結符。

上述技術的有用性總是值得商榷的。我是一個C++的人,所以std::string拯救了我所有這種瘋狂的快樂。但現實情況是這樣的:有時候你會在乎src是否在其整體dst中被複制;有時候你沒有。有用性是情況依賴。爲了在UI中呈現字符串數據,這不會(可能)重要。對於複製要用於關鍵數據的字符串,部分前綴子字符串不會被接受。當警方向「約瑟夫約翰遜約翰」發出逮捕令時,當他的父親(「約瑟夫約翰遜」)被囚禁入獄時,會有一些解釋要做,因爲權證發行軟件的名字緩衝區只有15個字符。

所有這一切說,你分段故障歸結爲這樣一句話:

strncpy(s1.from_str,src, 100); // length parameter is wrong. 

產品召回大膽的聲明,上面:strncpy()將永遠寫n字符由目標緩衝區中引用的地址。」。這意味着上述代碼將總是寫入100個字符到目標緩衝區,在您的情況下只有10個字符寬,因此未定義的行爲,並可能ker-boom

通過執行糾正這種如果目標緩衝區是一個固定長度的字符數組以下:

strncpy(s1.from_str,src, sizeof(s1.from_str)/sizeof(s1.from_str[0])-1); 
s1.from_str[ sizeof(s1.from_str)/sizeof(s1.from_str[0])-1 ] = 0; 

參見如何做到這一點對於長度`Ñ字符的動態字符串的先前使用。

+1

thnx @WhozCraig ..非常詳細和描述性..我只是與strncpy鬼混,我知道如何安全地使用strncpy。我只是想知道如果'src'字符串是NULL終止的,那麼如果'n'大於'src'字符串的大小並且'dest'字符串的大小足夠大以容納多少個字符被複制到'dest'字符串中'src'字符串但小於'n'。關於strncpy的MAN頁面描述對我來說還不夠清楚。 –

+1

'strncpy'是可預測的固定大小的字段。它不是**「字符串處理函數」。 – vonbrand

1

參見:http://www.manpagez.com/man/3/strncpy/

的stpncpy()和函數strncpy()函數至多n個字符複製從S2 到S1。如果s2長度小於n個字符,則s1的其餘部分爲 ,填充'\ 0'字符。否則,s1不會終止。

其餘填充....

所以:

strncpy(s1.from_str, src, 10); 
+0

那麼這與這個問題有什麼關係? – SomeWittyUsername

+0

但是這裏src字符串的大小小於dest字符串的大小,並且n大於src和dest字符串的大小。 –

+0

@icepack,因爲from_str後的90個字節(可能內存不屬於您)將被覆蓋。然後它取決於編譯器設置/操作系統。 ...什麼事情發生 –

5

http://www.cplusplus.com/reference/cstring/strncpy/

字符*函數strncpy(字符*目的地,爲const char *源,爲size_t NUM ) ;

從字符串複製字符將源 的前幾個字符複製到目標。如果在複製num數字字符之前發現源C字符串(它由空字符發信號爲 )的末尾,則將 目標使用零填充,直到寫入總數爲 的num字符。

所以,雖然源字符串長度的又因爲strncpy()函數的傳遞行爲小於目標緩衝區大小的尺寸,它試圖覆蓋超出目標緩衝區大小的人物其餘引起分段故障

而是超出了100個字符大小應該等於目標緩衝區允許的最大尺寸複製的,所以,你可以寫

strncpy(s1.from_str,src,sizeof(s1.from_str)/sizeof(s1.from_str[0]) - 1); Actual size -1 to accomodate the null terminator 

或更好地寫出了_countof

#define _countof(s) (sizeof(s)/sizeof(s[0])) 
................ 
strncpy(s1.from_str,src,_countof(s1.from_str) - 1); 
+1

這個seg錯誤發生在一臺LINUX機器上,但它不在另一臺UNIX機器上發生。爲什麼這樣 ? –

+1

@HimanshuGupta:在分配的內存之外寫入是一個未定義的行爲(UB),分段錯誤是許多UB中的一個[包括惡魔從你的鼻子飛出](http://www.catb.org/jargon/html/N /nasal-demons.html) – Abhijit

+0

thnx @Abhijit .. –

0

strncpy(s1.from_str,src,100);

你爲什麼要使用你的函數,from_str均被和src都已經連續10個字節分配100,但你要複製100個字節,這是導致賽格。故障。

使用這樣的,

strncpy(s1.from_str,src,10);

+0

我只是在鬼混。這發生在LINUX機器上,但我沒有在另一臺UNIX機器上發生任何seg錯誤。 –

+0

由於這會導致「未定義的行爲」,因此您可能無法在其他LINUX機器上發生seg故障,但在您的情況下最好使用'strcpy'。 –

+0

Thnx @Adeel Ahmed –