英文:
segmentation fault occurs when using fclose()
问题
我正在创建一个函数,当运行时,它会读取一个文件,并将另一个文件移动到文件中描述的位置 "PREVIOUSSTOP"(文件只包含一个数字),然后使用该数字将名为 "info" 的文件移动到 "PREVIOUSSTOP" 中描述的位置(如果 "PREVIOUSSTOP" 中的数字是 x,则将 info 文件向上移动 x 个句子)。当我在某个函数中使用 fclose() 时,出现了分段错误。有人能帮忙修复这个问题吗?我不知道为什么会发生这种情况,因为文件不等于 NULL。我尝试使用 gdb 调试,但结果是一个包含 600 多个问号的回溯。
#include <stdio.h>
#include <stdlib.h>
int stopnum = 0;
void GetInfoFromFile(FILE* info, char* Sentence1) {
int i = 0;
while (1) {
char c;
c = fgetc(info);
Sentence1[i] = c;
if (Sentence1[i] == '.' || Sentence1[i] == '!' || Sentence1[i] == '?') {
break;
}
i++;
}
Sentence1[i + 1] = '#include <stdio.h>
#include <stdlib.h>
int stopnum = 0;
void GetInfoFromFile(FILE* info, char* Sentence1) {
int i = 0;
while (1) {
char c;
c = fgetc(info);
Sentence1[i] = c;
if (Sentence1[i] == '.' || Sentence1[i] == '!' || Sentence1[i] == '?') {
break;
}
i++;
}
Sentence1[i + 1] = '\0';
}
void RestartPreviousTrainingSession(FILE* info) {
FILE* stop = fopen("PREVIOUSSTOP", "r");
if (stop != NULL) {
char* stopstr = malloc(32);
fgets(stopstr, 32, stop);
int stopint = strtol(stopstr, NULL, 10);
stopnum = stopint;
char dummysentence[400];
for (int i = 0; i != stopint; i++) {
GetInfoFromFile(info, dummysentence);
}
/* 分段错误发生在这里 */
fclose(stop);
} else {
printf("OOPS\n");
}
}
int main() {
FILE* f = fopen("wiki.train.tokens", "r");
RestartPreviousTrainingSession(f);
fclose(f);
}
';
}
void RestartPreviousTrainingSession(FILE* info) {
FILE* stop = fopen("PREVIOUSSTOP", "r");
if (stop != NULL) {
char* stopstr = malloc(32);
fgets(stopstr, 32, stop);
int stopint = strtol(stopstr, NULL, 10);
stopnum = stopint;
char dummysentence[400];
for (int i = 0; i != stopint; i++) {
GetInfoFromFile(info, dummysentence);
}
/* 分段错误发生在这里 */
fclose(stop);
} else {
printf("OOPS\n");
}
}
int main() {
FILE* f = fopen("wiki.train.tokens", "r");
RestartPreviousTrainingSession(f);
fclose(f);
}
名为 "wiki.train.tokens" 的文件可以在以下链接找到:https://huggingface.co/datasets/wikitext/blob/main/wikitext.py
英文:
I am creating a function that when run reads a file and brings another file to the position described in the file "PREVIOUSSTOP" (the file just contains a number) , the number is then used to move the file known as "info" up to the position described in "PREVIOUSSTOP" (if the number in "PREVIOUSSTOP" is x, the info file is moved up x many sentences). When I use fclose() in a certain function I get a Segmentation Fault.
Can someone help fix this, I have no idea on why this occurs as the file is not equal to NULL.
I have tried to use gdb to debug this but that just results in a backtrace with over 600 question marks
#include <stdio.h>
#include <stdlib.h>
int stopnum = 0;
void GetInfoFromFile(FILE* info, char* Sentence1) {
int i = 0;
while (1) {
char c;
c = fgetc(info);
Sentence1[i] = c;
if (Sentence1[i] == '.' || Sentence1[i] == '!' || Sentence1[i] == '?') {
break;
}
i++;
}
Sentence1[i + 1] = '#include <stdio.h>
#include <stdlib.h>
int stopnum = 0;
void GetInfoFromFile(FILE* info, char* Sentence1) {
int i = 0;
while (1) {
char c;
c = fgetc(info);
Sentence1[i] = c;
if (Sentence1[i] == '.' || Sentence1[i] == '!' || Sentence1[i] == '?') {
break;
}
i++;
}
Sentence1[i + 1] = '\0';
}
void RestartPreviousTrainingSession(FILE* info) {
FILE* stop = fopen("PREVIOUSSTOP", "r");
if (stop != NULL) {
char* stopstr = malloc(32);
fgets(stopstr, 32, stop);
int stopint = strtol(stopstr, NULL, 10);
stopnum = stopint;
char dummysentence[400];
for (int i = 0; i != stopint; i++) {
GetInfoFromFile(info, dummysentence);
}
/* segmentation fault occurs here */
fclose(stop);
} else {
printf("OOPS\n");
}
}
int main() {
FILE* f = fopen("wiki.train.tokens", "r");
RestartPreviousTrainingSession(f);
fclose(f);
}
';
}
void RestartPreviousTrainingSession(FILE* info) {
FILE* stop = fopen("PREVIOUSSTOP", "r");
if (stop != NULL) {
char* stopstr = malloc(32);
fgets(stopstr, 32, stop);
int stopint = strtol(stopstr, NULL, 10);
stopnum = stopint;
char dummysentence[400];
for (int i = 0; i != stopint; i++) {
GetInfoFromFile(info, dummysentence);
}
/* segmentation fault occurs here */
fclose(stop);
} else {
printf("OOPS\n");
}
}
int main() {
FILE* f = fopen("wiki.train.tokens", "r");
RestartPreviousTrainingSession(f);
fclose(f);
}
the file known as "wiki.train.tokens" can be found at https://huggingface.co/datasets/wikitext/blob/main/wikitext.py
答案1
得分: 2
-
我同意 @MarkAdler 的观点,你很可能在
GetInfoFromFile()
函数中向dummysentence
写入超过 400 个字节。修复的方法是添加一个长度参数。 -
(未修复) 在当前的实现中,
RestartPreviousTrainingSession()
需要知道是否读取了部分标记,以便不增加i
。也就是说,我建议你编写一个函数来跳过stopint
个标记,将其视为内部事务。然后,你可以通过读取一块数据(比如,4k),查找第stopint
个标记,并使用ftell()
/fseek()
来设置文件位置指示器。 -
(未修复) 尽量避免使用全局变量。共享状态难以测试。
-
fgetc()
返回一个int
;需要检查是否返回了 EOF。重新设计逻辑,使得终止的\0
在循环终止的所有 3 种方式中都处于正确的位置。 -
malloc()
可能返回 NULL。 -
strtol()
可能无法解析PREVIOUSSTOP
中的数字。它还可能返回一个超出你期望的int
范围的值。 -
使用符号常量而不是魔法值。
-
更喜欢将
*
放在变量旁边,而不是类型。FILE* a, b
在你期望它表示FILE *a, *b
时会出错。
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TOKEN_LEN 32
int stopnum = 0;
#define MAX_SENTENCE_LEN 400
void GetInfoFromFile(FILE *info, size_t n, char Sentence1[n]) {
int i = 0;
for (; (!i || !strchr(".!?", Sentence1[i-1])) && i < n - 1; i++) {
int c = fgetc(info);
if (c == EOF)
break;
Sentence1[i] = c;
}
Sentence1[i] = '#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TOKEN_LEN 32
int stopnum = 0;
#define MAX_SENTENCE_LEN 400
void GetInfoFromFile(FILE *info, size_t n, char Sentence1[n]) {
int i = 0;
for (; (!i || !strchr(".!?", Sentence1[i-1])) && i < n - 1; i++) {
int c = fgetc(info);
if (c == EOF)
break;
Sentence1[i] = c;
}
Sentence1[i] = '\0';
}
void RestartPreviousTrainingSession(FILE* info) {
FILE *stop = fopen("PREVIOUSSTOP", "r");
if (!stop) {
printf("OOPS\n");
return;
}
char *stopstr = malloc(TOKEN_LEN);
if (!stopstr) {
printf("malloc failed\n");
goto out;
}
fgets(stopstr, TOKEN_LEN, stop);
char *endptr;
long stopint = strtol(stopstr, &endptr, 10);
if (stopint < 0 || stopint > INT_MAX || stopstr == endptr) {
printf("PREVIOUSSTOP data was invalid at %s", stopstr);
goto out;
}
stopnum = stopint;
char dummysentence[MAX_SENTENCE_LEN];
for (int i = 0; i != stopint; i++) {
GetInfoFromFile(info, MAX_SENTENCE_LEN, dummysentence);
}
out:
fclose(stop);
}
int main(void) {
FILE *f = fopen("wiki.train.tokens", "r");
RestartPreviousTrainingSession(f);
fclose(f);
}
';
}
void RestartPreviousTrainingSession(FILE* info) {
FILE *stop = fopen("PREVIOUSSTOP", "r");
if (!stop) {
printf("OOPS\n");
return;
}
char *stopstr = malloc(TOKEN_LEN);
if (!stopstr) {
printf("malloc failed\n");
goto out;
}
fgets(stopstr, TOKEN_LEN, stop);
char *endptr;
long stopint = strtol(stopstr, &endptr, 10);
if (stopint < 0 || stopint > INT_MAX || stopstr == endptr) {
printf("PREVIOUSSTOP data was invalid at %s", stopstr);
goto out;
}
stopnum = stopint;
char dummysentence[MAX_SENTENCE_LEN];
for (int i = 0; i != stopint; i++) {
GetInfoFromFile(info, MAX_SENTENCE_LEN, dummysentence);
}
out:
fclose(stop);
}
int main(void) {
FILE *f = fopen("wiki.train.tokens", "r");
RestartPreviousTrainingSession(f);
fclose(f);
}
英文:
You did not supply the input files your program relies on, and I didn't feel like search for an example.
-
I concur with @MarkAdler that you are most likely writing more than 400 bytes to dummysentence in
GetInfoFromFile()
. The way to fix that is add a length parameter. -
(Not fixed) In the current implementation
RestartPreviousTrainingSession()
would need to know if partial token was read as not to incrementi
. That said, I suggest you write a function to skipstopint
tokens instead and make it an internal affair. You can then optimize it by reading a block of data (say, 4k), look for thestopint
'th token, and useftell()
/fseek()
to set the file position indicator. -
(Not fixed) Avoid global variables whenever possible. Shared state is hard to test.
-
fgetc()
returns anint
; needed to check if EOF was returned. Reworked logic so the terminating `\0' ends up at the right place for all 3 ways the loop terminates. -
malloc()
may return NULL. -
strtol()
may fail to parse the number inPREVIOUSSTOP
. It may also return a value that is outside the range ofint
you expect. -
Use symbolic constants instead of magic values.
-
Prefer
*
next to variable instead of type.FILE* a, b
is an error when you expect it to meanFILE *a, *b
.
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TOKEN_LEN 32
int stopnum = 0;
#define MAX_SENTENCE_LEN 400
void GetInfoFromFile(FILE *info, size_t n, char Sentence1[n]) {
int i = 0;
for(; (!i || !strchr(".!?", Sentence1[i-1])) && i < n - 1; i++) {
int c = fgetc(info);
if(c == EOF)
break;
Sentence1[i] = c;
}
Sentence1[i] = '#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TOKEN_LEN 32
int stopnum = 0;
#define MAX_SENTENCE_LEN 400
void GetInfoFromFile(FILE *info, size_t n, char Sentence1[n]) {
int i = 0;
for(; (!i || !strchr(".!?", Sentence1[i-1])) && i < n - 1; i++) {
int c = fgetc(info);
if(c == EOF)
break;
Sentence1[i] = c;
}
Sentence1[i] = '\0';
}
void RestartPreviousTrainingSession(FILE* info) {
FILE *stop = fopen("PREVIOUSSTOP", "r");
if (!stop) {
printf("OOPS\n");
return;
}
char *stopstr = malloc(TOKEN_LEN);
if(!stopstr) {
printf("malloc failed\n");
goto out;
}
fgets(stopstr, TOKEN_LEN, stop);
char *endptr;
long stopint = strtol(stopstr, &endptr, 10);
if(stopint < 0 || stopint > INT_MAX || stopstr == endptr) {
printf("PREVIOUSSTOP data was invalid at %s", stopstr);
goto out;
}
stopnum = stopint;
char dummysentence[MAX_SENTENCE_LEN];
for (int i = 0; i != stopint; i++) {
GetInfoFromFile(info, MAX_SENTENCE_LEN, dummysentence);
}
out:
fclose(stop);
}
int main(void) {
FILE *f = fopen("wiki.train.tokens", "r");
RestartPreviousTrainingSession(f);
fclose(f);
}
';
}
void RestartPreviousTrainingSession(FILE* info) {
FILE *stop = fopen("PREVIOUSSTOP", "r");
if (!stop) {
printf("OOPS\n");
return;
}
char *stopstr = malloc(TOKEN_LEN);
if(!stopstr) {
printf("malloc failed\n");
goto out;
}
fgets(stopstr, TOKEN_LEN, stop);
char *endptr;
long stopint = strtol(stopstr, &endptr, 10);
if(stopint < 0 || stopint > INT_MAX || stopstr == endptr) {
printf("PREVIOUSSTOP data was invalid at %s", stopstr);
goto out;
}
stopnum = stopint;
char dummysentence[MAX_SENTENCE_LEN];
for (int i = 0; i != stopint; i++) {
GetInfoFromFile(info, MAX_SENTENCE_LEN, dummysentence);
}
out:
fclose(stop);
}
int main(void) {
FILE *f = fopen("wiki.train.tokens", "r");
RestartPreviousTrainingSession(f);
fclose(f);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论