簡體   English   中英

c使用fgets讀取文件,strtok導致分段錯誤

[英]c reading a file using fgets, strtok causes segmentation fault

嘗試逐行讀取文件,文件中的一行如下所示:

InputVector:0(1,3,4,2,40)

編碼 :

FILE *file = fopen(filename, "r");
char buff[26];
char *token;

while(fgets(buff, 26, (FILE*)file) != NULL) {

    buff[strlen(buff)] = '\0';

    printf("%s\n", buff);
    token = strtok(buff, INV_DELIM1);
    printf("%s\n", token);
    token = strtok(NULL, INV_DELIM2);
    printf("%s\n", token);

    while(token != NULL) {
        token = strtok(NULL, INV_DELIM3);
        printf("%s\n", token);
    }
}

我的猜測是,在while循環中, strtok()在最后一個數字之后沒有返回NULL ,並且繼續運行並導致分段錯誤。 我嘗試在fgets()之后的buff末尾添加"\\0" ,但它沒有任何作用。

delim1: ":",
delim2: "(",
delim3: ",)"

我得到的輸出是

InputVector:0(1,3,4,2,40)
InputVector
0
1
3
4
2
40
segfault

您反復有如下代碼:

token = strtok(NULL, INV_DELIM2);
printf("%s\n", token);

如果strtok()返回NULL,則將其傳遞給printf() ,由於format參數中的%s ,它希望獲得指向以0終止的有效字符串的指針。 NULL不是指向以0終止的有效字符串的指針,因此發生壞事,在您的情況下表現為崩潰。

解決方案:在嘗試使用strtok()返回的指針之前,請確保其不為NULL。

對未來的建議:了解如何使用調試器單步執行代碼,並習慣於使用valgrind幫助跟蹤內存問題。 當您可以使用工具找出問題所在並確切了解問題出在哪里時,您不必對發生的事情做出錯誤的猜測。

不要跳過緩沖區大小 如果最長的行可以是25字符,則不要使用26字符作為緩沖區大小,而是:

#define MAXC 1024  /* constant for max characters in buf */
...
    char buff[MAXC] = 1024;

(由您決定, 128可以與其他任何值一起使用,以保證輸入長度的任何變化都不會超出數組的范圍。我寧願緩沖區的長度不能超過1個字符,而是1000個字符太短。)

然后通過檢查長度並驗證buff中的最后一個字符為'\\n'字符來驗證每個fgets調用,例如

    while(fgets(buff, MAXC, file) != NULL) {
        size_t len = strlen (buff);
        if (len == MAXC - 1 && buff[len - 1] != '\n') {
            fputs ("error: line too long.\n", stderr);
            /* handle error - generally by reading and dicarding
             * characters until '\n' or EOF encounterd and 
             * then either calling continue or break
             */
        }

這將確保在調用strtok之前具有有效的字符串。

您不需要多個定界符

然后,如評論中所述,不需要單獨的定界符。 #define DELIM ":(,)\\n"或用const char *delim = ":(,)\\n"聲明的單個delim就足夠了。 然后,您可以使用以下命令簡單地遍歷所有令牌:

    for (token = strtok(buff, delim); token; token = strtok(NULL, delim))
        printf ("%s\n", token);

簡短的例子

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

#define MAXC 1024

int main (int argc, char **argv) {

    char buff[MAXC] = "";
    char *token = NULL;
    const char *delim = ":(,)\n";
    FILE *file = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!file) {    /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    while(fgets(buff, MAXC, file) != NULL) {
        size_t len = strlen (buff);
        if (len == MAXC - 1 && buff[len - 1] != '\n') {
            fputs ("error: line too long.\n", stderr);
            /* handle error - generally by reading and dicarding
             * characters until '\n' or EOF encounterd and 
             * then either calling continue or break
             */
        }

        for (token = strtok(buff, delim); token; token = strtok(NULL, delim))
            printf ("%s\n", token);
    }
    if (file != stdin) fclose (file);   /* close file if not stdin */

    return 0;
}

(如果需要其他結果,可以調整delim

使用/輸出示例

$ echo "InputVector:0(1,3,4,2,40)" | ./bin/strtok_delims
InputVector
0
1
3
4
2
40

仔細檢查一下,如果您還有其他問題,請告訴我。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM