【问题标题】:Segmentation fault (core dumped) when reading file读取文件时出现分段错误(核心转储)
【发布时间】:2018-12-09 14:30:05
【问题描述】:

我正在做一个简单的项目来读取input.txt 文本文件并显示一些关于它的基本统计信息。该文件应该是关于公司大楼入口的。文件是这样的:

1 ; Visitor ; 10 ; 19 ; 2
2 ; 1 ; Worker ; 8 ; 0
3 ; 2 ; Director ; 12 ; 19
4 ; 5 ; Worker ; 18 ; 22
5 ; Visitor ; 8 ; 0 ; 3

格式为 = ID ;同伴(如果是雇员);类型 ;入场时间;退出时间;服务(如果访客)

我让程序正确读取文件(我猜),它正确读取了第一个工作人员,但是当它到达第二个工作人员时,它读取 ID 并突然以Segmentation fault (core dumped) 退出。

如果有更多知识的人可以提供帮助,我将非常感激,因为我不知道发生了什么,而其他具有相同错误的问题也没有帮助。

代码如下:

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

typedef enum { false, true } bool;

char * removeSpaces(char *line) {
    int counter = 0,i=0;

    while (line[i]!='\0'){
        if (line[i] == ' '){
            i++;
        } else{
            line[counter] = line[i];
            counter++;
            i++;
        }
    }
    return(line);
    line[counter] = '\0';
}

int main (int argc, char *argv[]){
    FILE * fp;
    char * line = NULL;
    char field[30];
    size_t len = 0;
    ssize_t read;
    bool flag = false;
    int i=0,j=0,k=0,counter=0; //variables to count on loops

    fp = fopen("input.txt", "r");
    if (fp == NULL)
        exit(EXIT_FAILURE);

    while ((read = getline(&line, &len, fp)) != -1) {
        printf("%s", line);
        if(strstr(line, "Worker") != NULL) { //determine the entrance type
            line = removeSpaces(line);

            printf("\nWORKER READ\n");
            i = 0;
            while(line[i] != ';'){ //Read ID
                field[i] = line[i]; //saves the content of the field (all between ';')
                i++;
            }
            field[i] = '\0';
            printf("\nID: ");
            for(i=0;field[i] != '\0';i++){
                printf("%c",field[i]);
            }
            //memset(field,0,strlen(field));
            i = 0; j = 0;
            while(flag != true){ //Read Companions
                if(line[i] == ';'){
                    flag = true; //keeps skipping the string till it finds the right field
                }
                if(flag == true){
                    j = i+1;
                    while(line[j] != ';'){
                        field[k] = line[j]; //saves the content of the field (all between ';')
                        j++; k++;
                    }
                }
                i++;
            }
            field[k] = '\0';
            printf("\nCOMPANIONS: ");
            for(i=0;field[i] != '\0';i++){
                printf("%c",field[i]); //prints what the number of companions read
            }
            //memset(field,0,strlen(field));
            i = 0; j = 0; k = 0; flag = false;
            while(flag != true){ //Read Type
                if(line[i] == ';'){
                    counter++;
                    if(counter == 2){
                        flag = true; //keeps skipping the string till it finds the right field
                    }
                }
                if(flag == true){
                    j = i+1;
                    while(line[j] != ';'){
                        field[k] = line[j]; //saves the content of the field (all between ';')
                        j++; k++;
                    }
                }
                i++;
            }
            field[k] = '\0';
            printf("\nTIPO: ");
            for(i=0;field[i] != '\0';i++){
                printf("%c",field[i]); /prints the type of entrance read
            }
            //memset(field,0,strlen(field));
            i = 0; j = 0; k = 0;  flag = false; counter = 0;
            while(flag != true){ //Read Entrance Time
                if(line[i] == ';'){
                    counter++;
                    if(counter == 3){
                        flag = true; //keeps skipping the string till it finds the right field
                    }
                }
                if(flag == true){
                    j = i+1;
                    while(line[j] != ';'){
                        field[k] = line[j]; //saves it
                        j++; k++;
                    }
                }
                i++;
            }
            field[k] = '\0';
            printf("\nENTRANCE: ");
            for(i=0;field[i] != '\0';i++){
                printf("%c",field[i]);
            }
            i = 0; j = 0; k = 0;  flag = false; counter = 0;
            while(flag != true){ //Read Exit Time
                if(line[i] == ';'){
                    counter++;
                    if(counter == 4){
                        flag = true;
                    }
                }
                if(flag == true){
                    j = i+1;
                    while(line[j] != ';'){
                        field[k] = line[j];
                        j++; k++;
                    }
                }
                i++;
            }
            field[k] = '\0';
            printf("\nSAIDA: ");
            for(i=0;field[i] != '\0';i++){
                printf("%c",field[i]);
            }
            printf("\n\n");

            i = 0; j = 0; k = 0;  flag = false;
            memset(field,0,strlen(field));
        } else if(strstr(line, "Director") != NULL){
            //TODO
        } else if(strstr(line, "Visitor") != NULL){
            //TODO
        }
    }

    return 0;
}

标签: c string file segmentation-fault


【解决方案1】:

sscanf 可用于解析来自line 的值。

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

int main (int argc, char *argv[]){
    FILE * fp;
    char * line = NULL;
    char id[30];
    char companions[30];
    char type[30];
    char entrance[30];
    char depart[30];
    size_t len = 0;
    ssize_t read;

    fp = fopen("input.txt", "r");
    if (fp == NULL)
        exit(EXIT_FAILURE);

    while ((read = getline(&line, &len, fp)) != -1) {
        printf("%s", line);
        if(strstr(line, "Worker") != NULL) { //determine the entrance type
            printf("\nWORKER READ\n");
            if ( 5 == sscanf ( line, "%29s ; %29s ; %29s ; %29s ; %29s"
            , id, companions, type, entrance, depart)) {
                printf("\nID: %s", id);
                printf("\nCOMPANIONS: %s", companions);
                printf("\nTIPO: %s", type);
                printf("\nENTRANCE: %s", entrance);
                printf("\nSAIDA: %s", depart);
                printf("\n\n");
            }
            else {
                printf ( "problem parsing Worker\n");
            }

        } else if(strstr(line, "Director") != NULL){
            //TODO
        } else if(strstr(line, "Visitor") != NULL){
            //TODO
        }
    }

    return 0;
}

【讨论】:

  • 你是说这消除了段错误?
  • 您确定了原始段错误的位置吗?
  • 哇,感谢很多用户 3121023,我想这就是体验的样子,因为我什至不知道 sscanf 的存在......这段代码也没有对我造成段错误,这很难相信它可以做到这么简单。
  • @Skepller,您仍然需要了解代码出错的原因。未能追查到这一点将是一个重大的学习机会。
  • 我明白你的意思,因为我实际上不知道我的原始代码出了什么问题,但我不知道是否值得深入研究,因为我无意中真的过于复杂了它!因为我,现在,知道它可以做得更简单,我不会再回来写那样的......
【解决方案2】:

虽然我推荐 sscanffscanf 而不是编写复杂的解析代码,但学习如何编写解析器对您的编码技能也有好处。在调整您的代码以使用 fgets 而不是 getline 以便我可以编译后,我在这个循环中遇到了一个错误:

while ( flag != true )
{ //Read Type
    if ( line[i] == ';' ) // <<<< Fault when i = 2488
    {
        counter++;
        if ( counter == 2 )
        {
            flag = true; //keeps skipping the string till it finds the right field
        }
    }
    if ( flag == true )
    {
        j = i + 1;
        while ( line[j] != ';' )
        {
            field[k] = line[j]; //saves the content of the field (all between ';')
            j++; k++;
        }
    }
    i++;
}

你在增加 i 时没有参考实际行的长度,所以在某些时候你正在访问一个你不拥有的内存地址。

您应该在编译代码时启用所有警告。你的编译器应该警告你一些错误。您应该看到的重要内容之一是 removeSpaces 函数中第 27 行的“无法访问的代码...”:

return(line);
line[counter] = '\0'; // This never executed.

http://pubs.opengroup.org/onlinepubs/009696699/functions/fgets.html

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-27
    • 1970-01-01
    相关资源
    最近更新 更多