2016-09-19 256 views
0

我正在逐行讀取文件,其中每行的格式爲:C:strncpy意外截斷字符串

「number1 \ t number2」。

我正在使用strtok和strncpy來分割,然後根據需要存儲這兩個值。 但是,我發現在strncpy之後,number1被截斷了一個數字。

任何想法,爲什麼這可能是以及如何解決它?

爲了簡單起見,我硬編碼了line_of_text來模擬問題。

謝謝!

代碼:

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


int main() 
{ 
    char line_of_text[80] = " 18306000 \t 100\n"; 
    // NB: There's a \t between the two values, the rest are spaces. 

    char* token; 

    int digits_per_num = 9; 

    char first_token[digits_per_num]; 
    char second_token[digits_per_num]; 

    token = strtok (line_of_text, "\t"); 

    printf("first token: %s\n", token); 

    if (token != NULL) 
    { 
     strncpy (first_token, token, digits_per_num); 
    } 

    token = strtok (NULL, ",\t\n"); 
    if (token != NULL) 
    { 
     strncpy (second_token, token, digits_per_num); 
    } 


    printf("first token copy: %s\n", first_token); 
    printf("second token copy: %s\n", second_token); 

} 

輸出:

first token: 18306000 
first token copy: 1830600<junk> 
second token copy: 100 
+0

'「18306000 100 \ n」'是'「\ t18306000 \ t100 \ n」'? – BLUEPIXY

+0

不,它是:「18306000 \ t100 \ n」 - 所以只有兩個值之間的選項卡,其餘是空格。對不起,我之前沒有說清楚。 – Sadia1990

+1

在字符串文字中使用'\ t'(對於'line_of_text')來顯示標籤的位置 - 這就是轉義序列的用途!你可能需要在調用'strtok()'時使用'「\ t」'作爲分隔符,就像@BLUEPIXY指出的那樣(相當簡單)。請注意,您需要在字符串上允許空終止符;你遇到了緩衝區溢出和未定義的行爲,因爲你不能確保你的字符串足夠短。請記住,如果源太長而不適合,'strncpy()'不會終止目標。所有'strn *()'函數都有怪癖。 –

回答

2

第一令牌由10個字節組成:18306000\0

strncpy()只寫入空字符,如果它適合目標緩衝區。但是你已經分配了一個字符太少,所以它沒有。

最簡單的解決方法是包括兩個strtok的電話等分隔的空間:

token = strtok (line_of_text, " \t\n,"); 

我也建議使用snprintf()代替strncpy所以你總是保證在最後得到一個空字符你的字符串。

+3

該標記實際上是空間,空間,空間,空間,空間,18306000。共12個字符(不含終結者) –

+0

好的,非常感謝!我將digits_per_num的值增加到了12,並且已經解決了這個問題。 – Sadia1990

1

問題是緩衝區不夠大的字符串;在這種情況下,strncpy函數不會空終止緩衝區。

只是按照您在評論中所建議的方式增加緩衝區大小並不是一個可靠的解決方案,因爲如果有人提供具有更長數字的不同輸入,則會重複出現相同的問題。

一種選擇是手動終止緩衝:

strncpy(first_token, token, digits_per_num); 
first_token[digits_per_num - 1] = 0; 

(注:使用sizeof first_token代替digits_per_num會更穩健太)。

但是在這種情況下,無效輸入由無聲截斷處理。如果這個不適合你的程序,那麼你可以使用不同的邏輯,並且完全避免了直觀strncpy功能:

if (strlen(token) + 1 > digits_per_num) 
{ 
    fprintf(stderr, "Error, input was more than 9 digits\n"); 
    exit(EXIT_FAILURE); 
} 
strcpy(first_token, token); 

它的安全使用strcpy當先前檢查的長度。