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
检查一下,如果您有任何问题,请告诉我。
我正在尝试逐行读取文件,并对每一行进行标记,这些行的字符串由空格和制表符分隔。但是,当我 运行 我的程序时,我在尝试打印令牌时收到 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
检查一下,如果您有任何问题,请告诉我。