Как я могу считывать входные данные из текстового файла в массив структур на языке Си? (Возникает ошибка сегментации)

#c

Вопрос:

Я пытаюсь прочитать в текстовом файле, скажем input.txt, в массив структур, чтобы затем распечатать (и, конечно, освободить память). Хотя мое кодирование на C немного корявое, и я ищу помощи.

Input.txt содержит строки информации об одном человеке. Я хочу прочитать в людях, отсортировать по имени и распечатать в отсортированном порядке. Прежде чем я смогу это сделать, я просто пытаюсь создать массив людей, выделить память каждому человеку, скопировать данные из текстового файла, а затем распечатать их окончательно. Это даже не доходит до распечатки, как вы можете видеть, это приводит к ошибке сегментации:

Я использую следующее:

 gcc -Wall -O2 -o program filename.c
 

и получить это

 Segmentation fault: 11
 

input.txt содержание:

Джоан 0212672938 joan@gmail.com
Джон 0365242939 john@yahoo.com

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

struct person {
    char *name;
    char *phone;
    char *email;
};

int main(void) {
    int i;
    int peopleSize = 0;
    char * pch;
    FILE *f = fopen("input.txt", "r");
    if (f == NULL) return EXIT_FAILURE;
    struct person** people = malloc(100 * (sizeof (people[0])));
    /* Create 100 people */
    char *nameTmp = malloc(30 * sizeof nameTmp[0]);
    char *phoneTmp = malloc(30 * sizeof phoneTmp[0]);
    char *emailTmp = malloc(30 * sizeof emailTmp[0]);

    /* Open the file for reading */
    char *line_buf = NULL;
    size_t line_buf_size = 0;
    int line_count = 0;
    ssize_t line_size;

    /* Get the first line of the file. */
    line_size = getline(amp;line_buf, amp;line_buf_size, f);

    while (line_size >= 1) {
        line_count  = 1;
        people[line_count-1] = malloc(sizeof (people[line_count-1]));
        /* if fgets returns an empty space or new line, no more people to add, break loop */
        /* Within str, use strtok to divide strings up into name, phone and email */
        strcpy(pch, line_buf);
        pch = strtok (pch, " ");
        strcpy(nameTmp, pch);
        printf("%sn", nameTmp); 
        if (pch != NULL) {
            pch = strtok (NULL, " ");
            strcpy(phoneTmp, pch);
        }
        if (pch != NULL) {
            pch = strtok (NULL, " ");
            strcpy(emailTmp, pch); 
        }
        /* Allocate enough memory to person->name and person->phone and person->email as required */
        people[line_count-1]->name = malloc((strlen(nameTmp)   1) * sizeof (people[line_count-1]->name[0]));
        people[line_count-1]->phone = malloc((strlen(phoneTmp)   1) * sizeof (people[line_count-1]->phone[0]));
        people[line_count-1]->email = malloc((strlen(emailTmp)   1) * sizeof (people[line_count-1]->email[0]));
        /* Now copy values from temporary variables into actual person */
        strcpy(people[line_count-1]->name, nameTmp);
        strcpy(people[line_count-1]->phone, phoneTmp);
        strcpy(people[line_count-1]->email, emailTmp);
        /* Get the next line */
        line_size = getline(amp;line_buf, amp;line_buf_size, f);
    }
    peopleSize = line_count;

    /* Printing all the people out */
    for (i = 0; i < peopleSize; i  ) {
        printf("%st", people[i]->name);
        printf("%st", people[i]->phone);
        printf("%s", people[i]->email);
        printf("n");
    }
    

    /* Freeing all of the memory */
    for (i = 0; i < peopleSize; i  ) {
        free(people[i]->email);
        free(people[i]->phone);
        free(people[i]->name);
        free(people[i]);
    }
    free(people);
    
    
    return EXIT_SUCCESS;
}
 

Комментарии:

1. pch не инициализируется, но вы пытаетесь strcpy() это сделать. Вы проверяли сбой с помощью какого-либо отладчика, например gdb ? Также вместо people[line_count-1] = malloc(sizeof (people[line_count-1])); того, чтобы пытаться people[line_count-1] = malloc(sizeof (struct person));

2. @яно Вупс, вот что я хотел сказать, извините, неправильно набрал в отправке вопроса, отредактирую это.

3. Пожалуйста, разделите это на две отдельные проблемы «Как читать из текстового файла?» и «Как хранить в массиве?». Затем сосредоточьте этот вопрос только на одном из них. Разделение проблем-полезный инструмент для разработки, тестирования, отладки и для того, чтобы задавать здесь вопросы.

4. @kuro Потрясающе, я пробовал это, и все заканчивается тем, что я распечатываю двух человек, спасибо. Я не очень хорошо разбираюсь в C, Java-мой обычный язык выбора, указатели и структуры все еще немного сбивают с толку.

Ответ №1:


В общем, при отладке я бы рекомендовал компилировать без оптимизации и с флагом отладки (-g). Затем просмотрите свою программу в GDB и посмотрите, где она ломается.

Большинство исправлений уже упоминались в комментариях. Смотрите код ниже для пошагового объяснения исправлений.

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

typedef struct { // now you can use "person" type rather than "struct person"
    char *name;
    char *phone;
    char *email;
} person;

int main(void) {
    int i;
    int peopleSize = 0;
    char * pch = malloc(30); // Must be initialized before use
    FILE *f = fopen("input.txt", "r");
    if (f == NULL) return EXIT_FAILURE;

    person** people = malloc(100 * (sizeof(person*))); //This is an array of 100 pointers to person so you want sizeof(person*)
        /* Create 100 people */
    char *nameTmp = malloc(30); // These are char arrays. Each char occupys a byte and malloc allocates byte by default.
    char *phoneTmp = malloc(30);
    char *emailTmp = malloc(30);
    

    /* Open the file for reading */
    char *line_buf = malloc(30); // MUst be initialized before use;
    size_t line_buf_size = 0;
    int line_count = 0;
    ssize_t line_size;

    /* Get the first line of the file. */
    line_size = getline(amp;line_buf, amp;line_buf_size, f);

    while (line_size >= 1) {
        line_count  = 1;
        people[line_count-1] = malloc(sizeof(person)); // You are allocating memory for a single person, so you want sizeof(person)
        /* if fgets returns an empty space or new line, no more people to add, break loop */
        /* Within str, use strtok to divide strings up into name, phone and email */
        strcpy(pch, line_buf);
        pch = strtok (pch, " ");
        strcpy(nameTmp, pch);
        printf("%sn", nameTmp); 
        if (pch != NULL) {
            pch = strtok (NULL, " ");
            strcpy(phoneTmp, pch);
        }
        if (pch != NULL) {
            pch = strtok (NULL, " ");
            strcpy(emailTmp, pch); 
        }
        /* Allocate enough memory to person->name and person->phone and person->email as required */
        people[line_count-1]->name = malloc(strlen(nameTmp)   1); // As above these are char arrays so there is no need for sizeof
        people[line_count-1]->phone = malloc(strlen(phoneTmp)   1);
        people[line_count-1]->email = malloc(strlen(emailTmp)   1);
        /* Now copy values from temporary variables into actual person */
        strcpy(people[line_count-1]->name, nameTmp);
        strcpy(people[line_count-1]->phone, phoneTmp);
        strcpy(people[line_count-1]->email, emailTmp);
        /* Get the next line */
        line_size = getline(amp;line_buf, amp;line_buf_size, f);
    }
    peopleSize = line_count;

    /* Printing all the people out */
    for (i = 0; i < peopleSize; i  ) {
        printf("%st", people[i]->name);
        printf("%st", people[i]->phone);
        printf("%s", people[i]->email);
        printf("n");
    }
    

    /* Freeing all of the memory */
    for (i = 0; i < peopleSize; i  ) {
        free(people[i]->email);
        free(people[i]->phone);
        free(people[i]->name);
        free(people[i]);
    }
    free(people);
    
    
    return EXIT_SUCCESS;
}