2011-06-14 87 views
9

所以我一直在教自己C,爲了學習如何從一開始就正確地管理內存並編寫更好的代碼,我一直在運行Valgrind。這幫助我解決了內存泄漏問題,但似乎無法擺脫這種「有條件的跳轉或移動取決於未初始化的值/未初始化的值由堆分配創建」的情況,儘管我已經縮小了它的範圍到的代碼塊:Valgrind對未初始化值的抱怨是否爲假陽性?

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

int main()  
{ 
    char* test = (char*) malloc(3); 
    strncpy(test, "123", 2); 
    printf("%s\n", test); 
    free(test); 
    return 0; 
} 

當我與---track-origins=yes運行Valgrind的,我得到這樣的輸出:

==91702== Conditional jump or move depends on uninitialised value(s) 
==91702== at 0x100011507: strlen (mc_replace_strmem.c:282) 
==91702== by 0x1000AA338: puts (in /usr/lib/libSystem.B.dylib) 
==91702== by 0x100000EFA: main (valgrind_test.c:10) 
==91702== Uninitialised value was created by a heap allocation 
==91702== at 0x100010345: malloc (vg_replace_malloc.c:236) 
==91702== by 0x100000EEA: main (valgrind_test.c:8) 

這似乎是一個誤報給我,但我不夠自信在我自己的知識寫下來。也許我分配錯誤或使用strncpy錯誤?我不確定。

在此先感謝

+4

你的字符串沒有終止符,所以valgrind可能是正確的,當它抱怨。 – 2011-06-14 15:38:27

+1

在這裏使用snprintf會更好恕我直言。 snprintf(test,3,「123」); – puffadder 2011-06-14 15:41:40

回答

17

不,這是破損的代碼。

您有一個包含3個未初始化字符的內存塊。然後你複製"12",並且不要終止。謹防strncpy()

我引述the documentation

的函數strncpy()函數是類似的,除了不超過n個字節的src的被複制。因此,如果src的前n個字節中沒有空字節,則結果不會以null結尾。

由於在源的前2個字符內沒有終止,所以目的地不會終止。

+3

它永遠不會傷害添加一個筆記:**從來沒有使用'strncpy' ** – 2011-06-14 16:01:53

+0

似乎我沒有閱讀手冊頁足夠接近 - 我認爲strncpy會用空值填充目標字符串的其餘部分。只有當n比源字符串長時纔會發生這種情況。 – pivotal 2011-06-14 17:02:24

+0

@R ..'strncpy'對於固定大小的記錄格式很有用。 – ninjalj 2011-06-14 23:19:00

1

你的字符串沒有終結符,所以valgrind可能是正確的,當它抱怨。變化:

strncpy(test, "123", 2); 

到:

strcpy(test, "12"); 
4

慣用的方式來使用strcpy()strncpy()

如果你知道緩衝區有該字符串加上NUL終止空間,你可以使用strcpy() 。這可能會使用常量,或者在代碼中進行檢查(您應該確保檢查是正確的)。

否則,你可以這樣做:

strncpy(dest, src, length); 
dest[length - 1] = '\0'; 

它具有以下缺點:

  • 它可以截斷字符串。
  • 它可能效率低下,因爲它總是填充length字節。

還有OpenBSD的strlcpy()

strcpy()/strncpy()的任何其他用途都有可能是可疑的,您應該仔細看看它們。底線:避免任何適度複雜的C字符串函數,嘗試使用某些庫來動態分配字符串。 Qmail/Postfix自己推出,GNU有obstacks