繁体   English   中英

从文件中读取 192/200 行文本后,第二个 fgets 返回分段错误

[英]2nd fgets returns segmentation fault after reading 192/200 lines of text from file

我正在尝试从文本文件中读取 200 行文本,并将每行的值存储到一个结构中。 这只是不工作部分的一小部分。 在整个代码中,我询问用户是否希望读取不同的文本文件。 它第一次完美运行,但是当用户说是读取不同的文件时,它只读取并存储文本文件的 200 行中的前 192 行,然后返回一个段错误。

我尝试在整个代码的各个部分打印出随机字母,以确定哪一行返回了段错误,并且(根据我发现的内容),这是进入内部的 while 条件,我无法弄清楚为什么它会给出段错误。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

int main(int argc, char *argv[]) {
    FILE *f1;
    int i = 0;
    struct pNames popNames;
    char fileName[20];
    char maleSNumber[20];
    char femaleSNumber[20];
    char string[200];

    fileName[0] = '\0';
    sprintf(fileName, "%d", popNames.year);
    strcat(fileName, "Names.txt");

    if ((f1 = fopen(fileName, "r")) != NULL) {
        while (fgets(string, 200, f1) != NULL) {
            sscanf(string, "%d %s %s %s %s",
                   &popNames.rank[i], 
                   popNames.maleName[i], maleSNumber,
                   popNames.femaleName[i], femaleSNumber);
            printf("%d %s %s %s %s\n", 
                   popNames.rank[i],
                   popNames.maleName[i], maleSNumber,
                   popNames.femaleName[i], femaleSNumber);
            removeCommas(maleSNumber);
            removeCommas(femaleSNumber);
            popNames.maleNumber[i] = atoi(maleSNumber);
            popNames.femaleNumber[i] = atoi(femaleSNumber);
            i++;
        }
    } else {
        printf("Cannot open %s\n", fileName);
        return (-1);
    }
}

结构定义:

#define MAXLENGTH 20
#define ROWS 200

/* Struct definitions */
struct pNames {
    int  year;
    int  rank[ROWS];
    char maleName[ROWS][MAXLENGTH];
    int  maleNumber[ROWS];
    char femaleName[ROWS][MAXLENGTH];
    int  femaleNumber[ROWS];
};

removeCommas()的定义:

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

int removeCommas(char *num) {
    int i;
    int newNum = 0;
    char *pointer;

    pointer = strchr(num, ',');
    while (pointer != NULL) {
        i = (int)(pointer - num);
        strcpy(&num[i], &num[i + 1]);
        newNum += 1;
        pointer = strchr(num, ',');
    }
    return (newNum);
}

它应该读取、存储每行的部分内容并打印出文本文件的所有 200 行,但它仅适用于前 192 行(第二次使用它时,当用户要求更改文本文件时)。 1个文本行的格式应该是:

[rank][maleName][numMaleNameOccurences][femaleName][numFemaleNameOccurences]

(例如1 John 89,950 Mary 91,668

我了解您只发布了代码片段,但这里有一些明显的问题:

  • 您应该采取一切预防措施来避免缓冲区溢出:使用snprintf而不是sprintfstrcat
  • 计算文件名时popNames.year未初始化
  • 将正确的大小传递给fgets
  • 检查sscanf()的返回值
  • 传递sscanf()%s字段的最大字符数。
  • 在将文件内容解析到 arrays 的第i个条目之前测试i的值,如果文件异常大,您将获得未定义的行为

您的removeCommas()具有未定义的行为,因为您使用重叠字符串调用strcpy 这不太可能是您的段错误的原因,但这里有一个简化和更正的版本:

int removeCommas(char *num) {
    int newNum = 0;
    char *p = num;

    while ((*num = *p++) != '\0') {
        if (*num != ',')
            num++;
        else
            newNum++;
    }
    return newNum;
}

这是main() function 的修改版本:

#include <stdio.h>

int main(int argc, char *argv[]) {
    FILE *f1;
    int i;
    struct pNames popNames;
    char fileName[20];
    char maleSNumber[20];
    char femaleSNumber[20];
    char string[200];

    snprintf(fileName, sizeof fileName, "%dNames.txt", popNames.year);

    if ((f1 = fopen(fileName, "r")) == NULL) {
        printf("Cannot open %s\n", fileName);
        return -1;
    }
    i = 0;
    while (i < 200 && fgets(string, sizeof string, f1) != NULL) {
        if (sscanf(string, "%d %19s %19s %19s %19s",
                   &popNames.rank[i], 
                   popNames.maleName[i], maleSNumber,
                   popNames.femaleName[i], femaleSNumber) != 5) {
            printf("invalid input: %s", string);
            continue;
        }
        printf("%d %s %s %s %s\n",
               popNames.rank[i],
               popNames.maleName[i], maleSNumber,
               popNames.femaleName[i], femaleSNumber);
        removeCommas(maleSNumber);
        removeCommas(femaleSNumber);
        popNames.maleNumber[i] = atoi(maleSNumber);
        popNames.femaleNumber[i] = atoi(femaleSNumber);
        i++;
    }
    fclose(f1);
    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM