Click here to Skip to main content
15,885,366 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Hello guys.
I have a problem reading some information from a file and save them to struct.
I receive: Segmentation fault (core dumped)

I want your help.
Thanks in advance.


My code and the file (read_structs.txt)

read_structs.txt contains:
Nikos hello
21
7839
Mercendes

My brother name
26
4944
Lamporghini


What I have tried:

I changed something, but doesn't work.Same error.
See changes


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


struct human
{
    char *name;
    int age;
    int AM;
    struct car *my_car;
};

struct car
{
    char *car_model;
};

int main()
{
    struct human *the_human = (struct human *)malloc(sizeof(struct human) * 2);
    if(the_human == NULL)
    {
        perror("");
        exit(1);
    }
    
    FILE *fp = fopen("read_structs.txt" , "r");
    if(fp == NULL)
    {
        perror("");
        exit(1);
    }
    
    char *buffer = (char *)malloc(sizeof(char) * 60);
    if(buffer == NULL)
    {
        perror("");
        exit(1);
    }

    int j = 0;
    int k = 0;
    while(fgets(buffer , 100 , fp) != NULL)
    {
        if(k == 0)
        {
            the_human[j].name = (char *)malloc(sizeof(char) * 40);
            if(the_human[j].name == NULL)
            {
                perror("");
                exit(1);
            }
            strcpy(the_human[j].name , buffer);
        }   
        
        if(k == 1)
        {
            the_human[j].age = atoi(buffer);
        }
        
        if(k == 2)
        {
            the_human[j].AM = atoi(buffer);   
        }
                                     
        if(k == 3)
        {
            the_human[j].my_car->car_model = (char *)malloc(sizeof(char) * 40);
            if(the_human[j].my_car->car_model == NULL)
            {
                perror("");
                exit(1);
            }
            strcpy(the_human[j].my_car->car_model , buffer);
            k = 0;
            j++;
        }
        k++;
        
    }

    for(int i = 0; i < 2; i++)
    {
        printf("Name: %s\n" , the_human[i].name);
        printf("Age: %d\n" , the_human[i].age);
        printf("AM: %d\n" , the_human[i].AM);
        printf("Car model: %s\n" , the_human[i].my_car->car_model);
    }
    fclose(fp);
    return 0;
}
Posted
Updated 12-Dec-20 1:33am
v3

1 solution

This is structured incorrectly, pun intended. fgets reads one line from a file : fgets - C++ Reference[^]. Car should not be a separate structure. It should be part of human since there is no more data for it other than the model. The bigger problem is how one line of text is read but four different variables are set from that single line of text. You need to have a counter and switch/case statement so you assign the appropriate variable for each line.

What that means is you read four lines of data for one entry. The first line is the name, then the age, etc. You have to count those lines as you read them. After four lines you have completed one entry so move on to the next one. Remember to skip empty lines and you might want to trim the new lines off the end too. If you do that first then an empty line is easy to catch. You will probably wonder how to trim the new line off. Well, start by figuring out how to determine what the last character of the line is. The function strlen is helpful for this.

Since you're giving it an honest try and not the "Oliver Twist" way we see so often, ("please sir, can I have some code?"), here's one way to trim the new lines off.
C++
int TrimNewLines( char * text )
{
   // abc
   // 012 length is 3 so text[2] is the last character

   int index = (int) strlen( text );
   --index;               // aim at the last character
   while( index >= 0 )
   {
      if( text[ index ] == '\r' )
          text[ index ] = 0;
      else if( text[ index ] == '\n' )
          text[ index ] = 0;
      else
          break;          // not a new line so bail out
      --index;            // step back one
   }
   return index + 1;      // return length of resulting string
}
On the topic of strlen, you should learn how to use it instead of allocating 40-character strings. There is a handy function for that called strdup. You can make your own version of that if you want to - remember to allocate one more than the length of the string so you have room for the null.

One more thing - if you allocate 60 bytes for your buffer then you should not try to read up to 100 characters into it. Here again, remember the null. The way I always do this is to 'hide' it.
C++
#define BUFFER_LENGTH = 99
char buffer[ BUFFER_LENGTH + 1 ] = { 0 };   // +1 for the null

// read text like this :

while( fgets( buffer, BUFFER_LENGTH, fp ) )
{
}
 
Share this answer
 
v3
Comments
CPallini 12-Dec-20 8:46am    
5.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
Top Experts
Last 24hrsThis month


CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900