C: strtok 传递分段错误

C: strtok delivers segmentation fault

我正在尝试逐行读取文件,并对每一行进行标记,这些行的字符串由空格和制表符分隔。但是,当我 运行 我的程序时,我在尝试打印令牌时收到 Segmentation Fault 错误。我不明白为什么会这样,因为我使用缓冲区作为字符串来标记化并检查标记是否为空。下面是我的代码:

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

#define MAX_LINE_LENGTH 70

int main(void)
{
    FILE * testFile;
    char buf[MAX_LINE_LENGTH];
    testFile = fopen("test_file.txt", "r");

    if (testFile == NULL)
    {
        printf("Cannot open test_file.txt.\n");
        exit(0);
    }

     while (fgets(buf, sizeof(buf), testFile) != NULL) {
        char *token = strtok(buf," \t"); 


        while (token != NULL) 
        {
            token = strtok(NULL, " \t"); 

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

    exit(1);
}

以下是test_file.txt的内容:

String1 String2 String3
String4 String5 String6
String7 String8 String9

看起来您在打印时没有检查标记指针是否为 NULL。

如果您需要打印所有标记,您还需要在 strtok 系统调用之后在 while 循环内打印,此外还要检查标记是否为 NULL。

两个有用的提示 -- (1) 启用编译器警告,例如gcc/clang 的最小 -Wall -Wextra -pedantic 或 VS 的 /W3 (任何其他编译器都会有类似的选项),并且在没有警告的情况下编译之前不接受代码; (2) #include <string.h> 其中 strtok 被定义。

除了@dreamer 指出的缺乏验证之外,您必须使用 strtok 的隐式定义。您应该会收到一条编译器警告。不要忽略任何警告,而是去修复它,它通常会告诉你问题代码所在的确切行。

接下来,不要硬编码文件名。将文件名作为第一个参数传递给您的程序(或默认从 stdin 读取)一样简单。您的第二个选择是将文件名作为程序的输入。

将它们放在一起,您可以做一些简单的事情,例如:

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

#define MAX_LINE_LENGTH 70
#define DELIM " \t\n"

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

    char buf[MAX_LINE_LENGTH];
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

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

    while (fgets (buf, sizeof buf, fp))
        for (char *p = strtok(buf, DELIM); p; p = strtok(NULL, DELIM))
            puts (p);

    if (fp != stdin)   /* close file if not stdin */
        fclose (fp);

    return 0;
}

(注意: 您需要包含 '\n' 作为分隔符,以防止额外的 '\n' 成为每行最后一个标记的一部分)

例子Use/Output

$ ./bin/strtokfile test_file.txt
String1
String2
String3
String4
String5
String6
String7
String8
String9

检查一下,如果您有任何问题,请告诉我。