【问题标题】:Segmentation fault when I copy to binary file复制到二进制文件时出现分段错误
【发布时间】:2015-12-14 19:09:15
【问题描述】:

我有作业。从使用格式的文本文件复制

name    birthday      street
NAME0;DAY/MONTH/YEAR;STREET0;
NAME1;DAY/MONTH/YEAR;STREET1;
NAME2;DAY/MONTH/YEAR;STREET2;

以上信息按年份排序。排序后,必须将所有内容复制到二进制文件中。它一直给我分段错误。我认为问题在于 token 用于从每一行读取所有信息。

编辑: 使用调试器,我发现 i=4 时的第 167 行会导致错误。 strcpy(stud[i].day,token);

编辑: 我认为问题出在输入文件中。我重新创建了,现在可以使用了。

void students_list(FILE *ifp , FILE *b_ifp)
{

    char line[150] ;
    char *token;
    int i = 0 , n , t = 0 ;

    memset(line,0,sizeof(line));

    ifp = fopen("students.txt","r");
    b_ifp = fopen("sorted.bin","wb");

    struct students
    {
        char name[20] , street[50] , year[5] , month[3] , day[3];

    };
    typedef struct students students;

    students stud[32], aux;

    while(fgets(linie,sizeof(line), ifp) != NULL)
    {

        token = strtok(line,";");
        strcpy(stud[i].name,token);

        token = strtok(NULL,"/");
        strcpy(stud[i].day,token);

        token = strtok(NULL,"/");
        strcpy(stud[i].month,token);

        token = strtok(NULL,";");
        strcpy(stud[i].year,token);

        token = strtok(NULL,";");
        strcpy(stud[i].street,token);

        i++;
    }

    n = i;
    while(t == 0)
    {
        t = 1;
        for(i = 0 ; i < n ; i++)
        {
            if(strcmp(stud[i].year,stud[i + 1].year) > 0)
            {
                aux = stud[i];
                stud[i] = stud[i + 1];
                stud[i + 1] = aux;
                t = 0;

            }
        }
    }

    for(i = 0; i < n ; i++)
    {
        fwrite(&stud[i], sizeof(stud[i]), 1, b_ifp);
    }

    fclose(ifp);
    fclose(b_ifp);
}

【问题讨论】:

  • 建议你使用调试器。至少它会立即告诉你哪条线路出现了段错误。
  • 检查文件指针的有效性。
  • 使用strtok_r 而不是strtok
  • 并找出导致段错误的行。您有任意数量的数组引用,这些引用可能会超出数组的末尾。
  • 确定因为代码做了n = i - 1;,最后的for() 应该是for(i = 0 ; i &lt;= n ; i++) 否则最后一条记录不保存。但这并不能解决OP 的更大问题。

标签: c file segmentation-fault token binaryfiles


【解决方案1】:

基本上,问题可能是多方面的。您可以拥有一个包含多个32 学生的条目的文件。首先,您不会检查来自strtok(可以是NULL,如果您没有提供正确的格式并且没有更多字段)的返回代码。如果输入时strtok 返回值为NULL,您可以做所有事情但拒绝添加记录。并检查数组大小(使用while(n &lt; 32 &amp;&amp; fgets(... 之类的内容,就像对该问题的一条评论所暗示的那样)

类似:

char *name, *street, *year, *month, *day;

name   = strtok(line, ";");  if (!name) continue;
year   = strtok(NULL, "/");  if (!year) continue;
month  = strtok(NULL, "/");  if (!month) continue;
day    = strtok(NULL, ";");  if (!day) continue;
/* a line has a \n at the end, so we try to eliminate it if last ; not present */
street = strtok(NULL, ";\n"); if (!street) continue;

然后,您需要遵守可能的长字段,因为strcpy 不会并且可能导致您覆盖它们的末尾。如:

strncpy(stud[i].name, sizeof stud[i].name, name);
strncpy(stud[i].day, sizeof stud[i].day, day);
...

这还将检查是否正确地用空字符完成每个字符串,以防它因空间而不得不截断字段(我认为您没有在stud 结构的字符串字段中为它提供空间)

最后,我建议,当您读取和排序核心内存中的所有数据时,只需执行一次 fwrite 调用,例如:

res = fwrite(stud, sizeof stud[0], n, b_ifp);

而不是遍历所有记录。

另一个要讨论的问题是,如果您希望按数字或字典顺序对年份进行排序,因为年份肯定不会超出范围 1950..2050 没有问题,但假设您必须对范围内的数字进行排序1..1000,按照字典顺序,首先是1,然后是10,然后是100,然后是1000,然后是101,然后是102,...,然后是110111112,...199220200201,...,我想这不是你想要的。最好将数字转换为int 并使用关系运算符进行排序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-15
    • 2014-05-02
    • 1970-01-01
    • 1970-01-01
    • 2016-04-15
    • 2021-11-01
    • 1970-01-01
    相关资源
    最近更新 更多