2013-02-09 67 views
0

我很新的C,我越來越用strncpy()函數功能卡\用strncpy()來複製爲const char *

這裏是我工作的一個例子:

int main() 
{ 

const char *s = "how"; 

struct test { 
    char *name; 
}; 

struct test *t1 = malloc(sizeof(struct test)); 

strncpy(t1->name, s, sizeof(*s)); 
t1->name[NAMESIZE] = '\0'; 

printf("%s\n", t1->name); 

} 

我有一個const char *,我需要設置測試的「名稱」值爲const char。搞清楚這件事我真的很難過。這甚至是正確的方法嗎?

非常感謝!

+4

從哪裏開始... – 2013-02-09 19:37:58

+0

@KerrekSB:說得很好:d – LihO 2013-02-09 19:41:19

回答

5

好吧,你分配的結構,而不是字符串裏面的結構。在複製之前,你需要做到這一點。即使你這樣做了,當你試圖設置字符串終止符時,你可能會覆蓋未分配的內存。

而且,由於高攝入酒量,我只注意到你實際上只複製了一個字符,但它仍然是未定義的行爲

+0

謝謝您。我分配了t1-> name = malloc(sizeof(s)),然後使用了strncpy。它現在可以工作,但是它說strncpy是char上的一個函數,但是我使用了sizeof char *。 – isal 2013-02-09 19:47:38

+0

@isal'sizeof(char *)'是4或8個字節,取決於您是在32位還是64位平臺上。 'sizeof(* s)'是1,因爲它與C規範中規定的sizeof(char)相同等於1。你應該使用'strlen(s)+ 1'。 – 2013-02-09 19:49:45

+0

啊,謝謝。這就說得通了。 – isal 2013-02-09 19:54:50

2

沒有任何嘗試的完整性或教育方向,這是你的代碼應該工作的版本。您可以在本網站上分別播放「發現差異」並分別尋找解釋。

int main() 
{ 
    const char s[] = "how";     // s is an array, const char[4] 

    struct test{ char name[NAMESIZE]; }; // test::name is an array 

    struct test * t1 = malloc(sizeof *t1); // DRY 

    strncpy(t1->name, s, NAMESIZE);   // size of the destination 
    t1->name[NAMESIZE - 1] = '\0';   // because strncpy is evil 

    printf("%s\n", t1->name); 

    free(t1);        // clean up 
} 
+0

我沒有改變結構定義的自由。但是我意識到我在做malloc(sizeof struct test)而不是sizeof * t1的錯誤。謝謝 – isal 2013-02-09 19:59:38

+0

@isal:然後,不要忘記爲字符串分配內存,並使用['strlen'](http://www.cplusplus.com/reference/cstring/strlen/)來計算大小這樣的字符串。 – LihO 2013-02-09 20:00:47

+0

@isal:如果您必須動態處理'test :: name',請參閱Stephen的答案,但不要忘記分開清理。 – 2013-02-09 20:01:35

3

讓我們在這個時間一步:

struct test *t1 = malloc(sizeof(struct test)); 

這個分配用於struct test空間;足夠的空間指針name,但沒有任何指向指向的指針的內存。至少,你要做到以下幾點:

t1->name = malloc(strlen(s) + 1); 

已經這樣做了,你可以繼續複製字符串。但是,您已經計算了一次字符串的長度以分配內存;通過調用strncpy隱含地再次執行它是沒有意義的。相反,請執行以下操作:

const size_t len = strlen(s) + 1; // +1 accounts for terminating NUL 
t1->name = malloc(len); 
memcpy(t1->name, s, len); 

通常,請嘗試使用此基本模式;計算字符串的長度一次當他們進入您的代碼,但然後使用顯式大小的內存緩衝區和mem*操作,而不是隱式長度的字符串與str*操作。如果正確完成,至少是安全的(並且通常更安全)並且更高效。

如果t1->name是一個固定大小的數組(而許多人更喜歡使用strlcpy),則可以使用strncpy。這將如下所示:

struct test { char name[MAXSIZE]; }; 
struct test *t1 = malloc(sizeof *t1); 
strncpy(t1->name, s, MAXSIZE - 1); 
t1->name[MAXSIZE-1] = 0; // force NUL-termination 

注意,size參數strncpy應該總是目的地,而不是源的大小,避免了目標緩衝區的邊界之外寫作。

+0

非常感謝您的深入解釋,現在它更加清晰。 – isal 2013-02-09 19:57:51

+0

可能會在'strncpy'''中調用'MAXSIZE - 1''「超越所有原因進行優化? :-) – 2013-02-09 20:00:59

1

函數strncpy()是總是錯誤

  • 如果結果太長,目標字符串不會以空終止
  • 如果目標是太長(第三個參數)時,尾端將完全用NUL填充。如果你有很大的緩衝區和短的字符串,這會浪費很多週期。

相反,你cound使用memcpy()或strcpy的,(或者你的情況,甚至的strdup())

int main() 
{ 
const char *s = "how"; 

struct test { 
    char *name; 
    }; 
struct test *t1 
size_t len; 

t1 = malloc(sizeof *t1); 

#if USE_STRDUP 

    t1->name = strdup(s); 

#else 

    len = strlen(s); 
    t1->name = malloc (1+len); 
    memcpy(t1->name, s, len); 
    t1->name[len] = '\0'; 

#endif  

printf("%s\n", t1->name); 

return 0; 
} 
+0

這應該是合格的:「對於動態分配的目標,strncpy總是錯誤的*」? – 2013-02-09 20:03:05

+1

不。總是錯的。由於您手動修復角落案例,因此您可以首先使用memcpy。 – wildplasser 2013-02-09 20:09:00

+0

嗯。假設你總是將*複製到一個小緩衝區中。要使用'memcpy',你必須首先獲得整個(可能大的)字符串的長度。使用'strncpy'你可能會付出一些額外的不必要的零,但不會超過(短)目標長度。 – 2013-02-10 01:35:52