使用fclose()时出现分段错误

rjee0c15  于 2023-06-05  发布在  其他
关注(0)|答案(1)|浏览(366)

我正在创建一个函数,当运行读取一个文件并将另一个文件带到文件“PREVIOUSSTOP”中描述的位置时(该文件仅包含一个数字),然后使用该数字将称为“info”的文件移动到“PREVIOUSSTOP”中描述的位置(如果“PREVIOUSSTOP”中的数字是x,则信息文件将向上移动x许多句子)。当我在某个函数中使用fclose()时,我会得到一个Segmentation Fault。有人可以帮助解决这个问题,我不知道为什么会发生这种情况,因为文件不等于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] = '\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);
}

名为“wiki.train.tokens”的文件可以在https://huggingface.co/datasets/wikitext/blob/main/wikitext.py找到

iaqfqrcu

iaqfqrcu1#

你没有提供你的程序所依赖的输入文件,我也不想搜索一个例子。
1.我同意@MarkAdler的观点,你很可能在GetInfoFromFile()中向dummysentence写入了超过400个字节。解决这个问题的方法是添加一个长度参数。
1.(不固定)在当前的实现中,RestartPreviousTrainingSession()需要知道是否读取了部分令牌,以便不递增i。也就是说,我建议您编写一个函数来跳过stopint令牌,并使其成为内部事务。然后,您可以通过阅读一个数据块(比如4k)来优化它,查找第stopint个标记,并使用ftell()/fseek()设置文件位置指示符。
1.(未固定)尽可能避免全局变量。共享状态很难测试。

  1. fgetc()返回一个int;需要检查EOF是否已返回。重新设计了逻辑,以便终止“\0”在循环终止的所有3种方式的正确位置结束。
  2. malloc()可能返回NULL。
  3. strtol()可能无法解析PREVIOUSSTOP中的数字。它还可能返回一个超出您预期的int范围的值。
    1.使用符号常量而不是魔术值。
    1.首选变量旁边的*而不是类型。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] = '\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);
}

相关问题