使用 strtok 时出现段错误
Seg fault when using strtok
我正在尝试从如下所示的输入中读取每个数字:
179 2358 5197 867
5541 172 4294 1397
2637 136 3222 591
... 逐行获取每一行的 min/max,然后使用 strtok 获取行中的每个数字,但我在第二个 while 循环中遇到段错误。
代码:
#include "header.h"
#include <string.h>
int main(void) {
int8_t* line = malloc(sizeof(int8_t) * 75);
int8_t* temp;
int32_t minim, maxim;
int32_t current;
stdin = fopen("stdin", "r");
while (fgets(line, 75 * sizeof(int8_t), stdin)) {
printf("%s", line);
temp = strtok(line," \n\t");
maxim = minim = atoi(temp);
while (temp != NULL) {
current = atoi(temp);
temp = strtok(NULL, " \n\t");
if (current < minim)
minim = current;
if (current > maxim)
maxim = current;
}
printf("\nMin and max: %d %d\n", minim, maxim);
}
printf("\n");
return 0;
}
header:
#ifndef HEADER_H
# define HEADER_H
# include <stdio.h>
# include <stdlib.h>
# include <stdbool.h>
typedef char int8_t;
typedef signed short int int16_t;
typedef signed int int32_t;
typedef signed long long int int64_t;
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long int uint64_t;
#endif
我只是不明白它可能出了什么问题。谢谢
stdin = fopen("stdin", "r");
这不是你想的那样。这会尝试在当前目录中打开一个名为“stdin”的文件。它不会 打开标准输入流。
你很可能没有这个名字的文件,所以这个函数可能会失败并且 returns NULL。因为你没有检查 return 值,所以你将 NULL 指针传递给 fgets
。这会调用未定义的行为,在本例中表现为崩溃。
标准输入流在您的程序启动时已经打开。所以删除 fopen
调用,它应该可以工作。
好的,所以...
你的 <header.h>
破坏了我的编译器,因为它重新定义了标识符 int8_t
等。由标准保留。 (编译器的抱怨不太正确,因为相关的 header 没有被包括在内,但你就是这样。)如果你定义你自己的类型,使用你自己的标识符。或者为 "real" intX_t 类型包含 <stdint.h>
(是的,我知道某个 "big" 编译器没有那个 header)。
最简单的当然是对字符串使用char *
而不是int8_t *
。 (char
的 signed-ness 是 implementation-defined,无论如何,一个好的编译器会大声抱怨使用 char *
的许多隐式转换 not涉及。)
您使用 exact-width 类型 int32_t
作为 minim
和 maxim
,但忽略了使用正确的 printf()
宽度与之对应的说明符(PRId32
,在 <inttypes.h>
中指定)。由于我看不到对 exact-width 类型的任何特定需求,我将它们替换为普通的 int
(仅 %d
就足够了)。
完成后,删除提及 sizeof( char )
,因为根据定义 1
.
检查 return 函数值。 fopen()
可能会失败。确保它没有。
不要 "reuse" stdin
文件描述符。到处都是混乱。您的 stdin
是来自终端还是文件或管道取决于您调用可执行文件的方式。如果打开文件,请使用 FILE * handle_name
,而不是 stdin
。此外,stdin
是 一个打开的文件描述符(即您程序的标准输入),因此您必须使用 freopen()
,而不是 fopen()
,让它从不同的来源正确接收。最简单的事情就是实际使用 stdin
as-is(这也给了你最大的灵活性 使用 你的程序)。
做释放你获得的资源。 free()
记忆。 fclose()
个文件。许多操作系统保护您免受这种疏忽并在您之后进行清理。有些人没有。
一旦你解决了那些你在评论中打喷嚏的问题...
#include <stdlib.h> // <-- added
#include <stdio.h> // <-- added
#include <string.h>
int main() {
char* line = malloc(75); // <-- turned to char *
char* temp; // <-- turned to char *
int minim, maxim; // <-- turned to int
int current; // <-- turned to int
while (fgets(line, 75, stdin)) { // <-- using stdin directly
printf("%s", line);
temp = strtok(line," \n\t");
maxim = minim = atoi(temp);
while (temp != NULL) {
current = atoi(temp);
temp = strtok(NULL, " \n\t");
if (current < minim)
minim = current;
if (current > maxim)
maxim = current;
}
printf("\nMin and max: %d %d\n", minim, maxim);
}
printf("\n");
free( line ); // <-- releasing memory
return 0;
}
...您的程序有效:
./testme.exe < file.dat # feeding file.dat to stdin
179 2358 5197 867
Min and max: 179 5197
5541 172 4294 1397
Min and max: 172 5541
2637 136 3222 591
Min and max: 136 3222
这里的教训:干净地编写代码。启用最严格的编译器警告,并留意它们。
至于像您一样用 fopen()
的结果覆盖 stdin
,标准规定(强调我的):
229) [...] [stderr
, stdin
, or stdout
] need not be modifiable lvalues to which the value returned by the fopen
function may be assigned.
我正在尝试从如下所示的输入中读取每个数字:
179 2358 5197 867
5541 172 4294 1397
2637 136 3222 591
... 逐行获取每一行的 min/max,然后使用 strtok 获取行中的每个数字,但我在第二个 while 循环中遇到段错误。
代码:
#include "header.h"
#include <string.h>
int main(void) {
int8_t* line = malloc(sizeof(int8_t) * 75);
int8_t* temp;
int32_t minim, maxim;
int32_t current;
stdin = fopen("stdin", "r");
while (fgets(line, 75 * sizeof(int8_t), stdin)) {
printf("%s", line);
temp = strtok(line," \n\t");
maxim = minim = atoi(temp);
while (temp != NULL) {
current = atoi(temp);
temp = strtok(NULL, " \n\t");
if (current < minim)
minim = current;
if (current > maxim)
maxim = current;
}
printf("\nMin and max: %d %d\n", minim, maxim);
}
printf("\n");
return 0;
}
header:
#ifndef HEADER_H
# define HEADER_H
# include <stdio.h>
# include <stdlib.h>
# include <stdbool.h>
typedef char int8_t;
typedef signed short int int16_t;
typedef signed int int32_t;
typedef signed long long int int64_t;
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long int uint64_t;
#endif
我只是不明白它可能出了什么问题。谢谢
stdin = fopen("stdin", "r");
这不是你想的那样。这会尝试在当前目录中打开一个名为“stdin”的文件。它不会 打开标准输入流。
你很可能没有这个名字的文件,所以这个函数可能会失败并且 returns NULL。因为你没有检查 return 值,所以你将 NULL 指针传递给 fgets
。这会调用未定义的行为,在本例中表现为崩溃。
标准输入流在您的程序启动时已经打开。所以删除 fopen
调用,它应该可以工作。
好的,所以...
你的
<header.h>
破坏了我的编译器,因为它重新定义了标识符int8_t
等。由标准保留。 (编译器的抱怨不太正确,因为相关的 header 没有被包括在内,但你就是这样。)如果你定义你自己的类型,使用你自己的标识符。或者为 "real" intX_t 类型包含<stdint.h>
(是的,我知道某个 "big" 编译器没有那个 header)。最简单的当然是对字符串使用
char *
而不是int8_t *
。 (char
的 signed-ness 是 implementation-defined,无论如何,一个好的编译器会大声抱怨使用char *
的许多隐式转换 not涉及。)您使用 exact-width 类型
int32_t
作为minim
和maxim
,但忽略了使用正确的printf()
宽度与之对应的说明符(PRId32
,在<inttypes.h>
中指定)。由于我看不到对 exact-width 类型的任何特定需求,我将它们替换为普通的int
(仅%d
就足够了)。完成后,删除提及
sizeof( char )
,因为根据定义1
.检查 return 函数值。
fopen()
可能会失败。确保它没有。不要 "reuse"
stdin
文件描述符。到处都是混乱。您的stdin
是来自终端还是文件或管道取决于您调用可执行文件的方式。如果打开文件,请使用FILE * handle_name
,而不是stdin
。此外,stdin
是 一个打开的文件描述符(即您程序的标准输入),因此您必须使用freopen()
,而不是fopen()
,让它从不同的来源正确接收。最简单的事情就是实际使用stdin
as-is(这也给了你最大的灵活性 使用 你的程序)。做释放你获得的资源。
free()
记忆。fclose()
个文件。许多操作系统保护您免受这种疏忽并在您之后进行清理。有些人没有。
一旦你解决了那些你在评论中打喷嚏的问题...
#include <stdlib.h> // <-- added
#include <stdio.h> // <-- added
#include <string.h>
int main() {
char* line = malloc(75); // <-- turned to char *
char* temp; // <-- turned to char *
int minim, maxim; // <-- turned to int
int current; // <-- turned to int
while (fgets(line, 75, stdin)) { // <-- using stdin directly
printf("%s", line);
temp = strtok(line," \n\t");
maxim = minim = atoi(temp);
while (temp != NULL) {
current = atoi(temp);
temp = strtok(NULL, " \n\t");
if (current < minim)
minim = current;
if (current > maxim)
maxim = current;
}
printf("\nMin and max: %d %d\n", minim, maxim);
}
printf("\n");
free( line ); // <-- releasing memory
return 0;
}
...您的程序有效:
./testme.exe < file.dat # feeding file.dat to stdin
179 2358 5197 867
Min and max: 179 5197
5541 172 4294 1397
Min and max: 172 5541
2637 136 3222 591
Min and max: 136 3222
这里的教训:干净地编写代码。启用最严格的编译器警告,并留意它们。
至于像您一样用 fopen()
的结果覆盖 stdin
,标准规定(强调我的):
229) [...] [
stderr
,stdin
, orstdout
] need not be modifiable lvalues to which the value returned by thefopen
function may be assigned.