Home > Mobile >  How can I read input from a text file into an array of structs in C? (Segmentation fault occuring)
How can I read input from a text file into an array of structs in C? (Segmentation fault occuring)

Time:10-12

I'm trying to read in a text file, say input.txt, into an array of structs to then print out (and free memory of course). My C coding is a bit scratchy though, and I'm looking for help.

Input.txt contains lines of information about a single person. I want to read in the people, sort by name and print out in sorted order. Before I can do this, I'm just trying to create an array of people, allocate memory to each person, copy in the details from the text file, and then print them out finally. It's not even getting to the print out, as you can see it gives a segmentation fault:

I'm using the following:

gcc -Wall -O2 -o program filename.c

and getting this

Segmentation fault: 11

input.txt contents:

Joan 0212672938 [email protected]
John 0365242939 [email protected]

#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(&line_buf, &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("%s\n", 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(&line_buf, &line_buf_size, f);
    }
    peopleSize = line_count;

    /* Printing all the people out */
    for (i = 0; i < peopleSize; i  ) {
        printf("%s\t", people[i]->name);
        printf("%s\t", 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;
}

CodePudding user response:


In general, when debugging, I would recommend compiling without optimizations and with the debug flag (-g). Then step through your program in GDB and see where it breaks.

Most of the fixes were already mentioned in the comments. See the code below for a line-by-line explanation of the fixes.


#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(&line_buf, &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("%s\n", 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(&line_buf, &line_buf_size, f);
    }
    peopleSize = line_count;

    /* Printing all the people out */
    for (i = 0; i < peopleSize; i  ) {
        printf("%s\t", people[i]->name);
        printf("%s\t", 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;
}

  •  Tags:  
  • c
  • Related