文本文件上的Strtok导致段错误
Strtok on text file leads to seg fault
我有一个文本文件,内容如下:
5f6
2f6
4f6
我想从该文本文件中获取数字(作为字符,然后使用 atol()
将它们转换为整数
我有代码:
#include <ncurses.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
initscr();
cbreak();
noecho();
char buf[100];
char * ptr;
char * ptr2;
char * ptr3;
char * ptr4;
int a;
int b;
int c;
int d;
FILE* file;
if (strcmp(argv[1],"test.txt") == 0)
{
file = fopen("test.txt","r");
while (fgets(buf,100,file) )
ptr = strtok(str,"f");
ptr2 = strtok(NULL," ");
ptr3 = strtok(NULL,"f");
ptr4 = strtok(NULL," ");
a = atol(ptr);
b = atol(ptr2);
c = atol(ptr3);
d = atol(ptr4);
}
refresh();
getchar();
endwin();
return (0);
}
然而,程序段错误但编译。我将如何更有效地执行此操作(通过不出现段错误的方法)?
你有几个问题
你没有检查文件是否打开。
在fopen()
之后一定要保证可以从文件中读取,如果fopen()
失败,那么returnsNULL
就这么简单
if (file == NULL)
return -1;
将防止程序的其余部分出现问题。
您的 while
循环只包含一个语句,因为它缺少大括号。
没有大括号你的 while 循环等同于
while (fgets(buf, sizeof(buf), file))
{
ptr = strtok(buf, "f");
}
您没有检查 strtok()
是否返回了非 NULL
值。
如果在字符串中找不到标记,strtok()
returns NULL
,并且您将返回的指针传递给了 atol
。
这会导致未定义的行为,并且可能会导致分段错误。
您不检查是否有参数传递给程序,但您仍然尝试将它与字符串进行比较。还有潜在的未定义行为。
我不知道下面的程序是否会做你需要的,因为它是你自己的程序,我只是让它更安全,避免了未定义的行为
#include <ncurses.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
char buf[100];
char *ptr;
char *ptr2;
char *ptr3;
char *ptr4;
int a;
int b;
int c;
int d;
FILE *file;
initscr();
cbreak();
noecho();
if (argc > 1)
{
file = fopen(argv[1], "r");
if (file == NULL)
return -1;
while (fgets(buf,100,file) != NULL)
{
ptr = strtok(str,"f");
ptr2 = strtok(NULL," ");
ptr3 = strtok(NULL,"f");
ptr4 = strtok(NULL," ");
if (ptr != NULL)
a = atoi(ptr);
if (ptr2 != NULL)
b = atoi(ptr2);
if (ptr3 != NULL)
c = atoi(ptr3);
if (ptr4 != NULL)
d = atoi(ptr4);
}
}
refresh();
getchar();
endwin();
return 0;
}
例如,如果您想从
中获取数字
5f6
作为数字,这比您想象的要容易得多。只需读取第一个和第三个字符,然后使用简单的算术将它们转换为数字。
示例:
char line[8];
while (fgets(line, sizeof line, file) != NULL)
{
int firstDigit = line[0] - '0';
int secondDigit = line[2] - '0';
printf("%d %d\n", firstDigit, secondDigit);
}
对于您显示的示例输入
5f6
2f6
4f6
输出将是
5 6
2 6
4 6
如果您想了解算法,它之所以有效,是因为大多数字符编码(如最常见的 ASCII)将数字字符保持在连续范围内。在 ASCII 的示例中,例如的值'5'
为 53
,'0'
的值为 48
。这意味着 '5' - '0'
的减法结果 53 - 48
等于 5
.
我有一个文本文件,内容如下:
5f6
2f6
4f6
我想从该文本文件中获取数字(作为字符,然后使用 atol()
我有代码:
#include <ncurses.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
initscr();
cbreak();
noecho();
char buf[100];
char * ptr;
char * ptr2;
char * ptr3;
char * ptr4;
int a;
int b;
int c;
int d;
FILE* file;
if (strcmp(argv[1],"test.txt") == 0)
{
file = fopen("test.txt","r");
while (fgets(buf,100,file) )
ptr = strtok(str,"f");
ptr2 = strtok(NULL," ");
ptr3 = strtok(NULL,"f");
ptr4 = strtok(NULL," ");
a = atol(ptr);
b = atol(ptr2);
c = atol(ptr3);
d = atol(ptr4);
}
refresh();
getchar();
endwin();
return (0);
}
然而,程序段错误但编译。我将如何更有效地执行此操作(通过不出现段错误的方法)?
你有几个问题
你没有检查文件是否打开。
在
fopen()
之后一定要保证可以从文件中读取,如果fopen()
失败,那么returnsNULL
就这么简单if (file == NULL) return -1;
将防止程序的其余部分出现问题。
您的
while
循环只包含一个语句,因为它缺少大括号。没有大括号你的 while 循环等同于
while (fgets(buf, sizeof(buf), file)) { ptr = strtok(buf, "f"); }
您没有检查
strtok()
是否返回了非NULL
值。如果在字符串中找不到标记,
strtok()
returnsNULL
,并且您将返回的指针传递给了atol
。这会导致未定义的行为,并且可能会导致分段错误。
您不检查是否有参数传递给程序,但您仍然尝试将它与字符串进行比较。还有潜在的未定义行为。
我不知道下面的程序是否会做你需要的,因为它是你自己的程序,我只是让它更安全,避免了未定义的行为
#include <ncurses.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
char buf[100];
char *ptr;
char *ptr2;
char *ptr3;
char *ptr4;
int a;
int b;
int c;
int d;
FILE *file;
initscr();
cbreak();
noecho();
if (argc > 1)
{
file = fopen(argv[1], "r");
if (file == NULL)
return -1;
while (fgets(buf,100,file) != NULL)
{
ptr = strtok(str,"f");
ptr2 = strtok(NULL," ");
ptr3 = strtok(NULL,"f");
ptr4 = strtok(NULL," ");
if (ptr != NULL)
a = atoi(ptr);
if (ptr2 != NULL)
b = atoi(ptr2);
if (ptr3 != NULL)
c = atoi(ptr3);
if (ptr4 != NULL)
d = atoi(ptr4);
}
}
refresh();
getchar();
endwin();
return 0;
}
例如,如果您想从
中获取数字5f6
作为数字,这比您想象的要容易得多。只需读取第一个和第三个字符,然后使用简单的算术将它们转换为数字。
示例:
char line[8];
while (fgets(line, sizeof line, file) != NULL)
{
int firstDigit = line[0] - '0';
int secondDigit = line[2] - '0';
printf("%d %d\n", firstDigit, secondDigit);
}
对于您显示的示例输入
5f6 2f6 4f6
输出将是
5 6 2 6 4 6
如果您想了解算法,它之所以有效,是因为大多数字符编码(如最常见的 ASCII)将数字字符保持在连续范围内。在 ASCII 的示例中,例如的值'5'
为 53
,'0'
的值为 48
。这意味着 '5' - '0'
的减法结果 53 - 48
等于 5
.