1

I was doing some struct exercises and I can't understand the segmentation fault. I've done almost everything all right, the segmentation fault is on the loop for(i = 0;i<2;i++)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<stdint.h>
#define MAX 50
int main(void)
{
    typedef struct {
        char *name;
        char *l_name;
        u_int32_t age;
    }person;
    u_int32_t i;
    person p[2];
    p->name = (char *) malloc(sizeof(char) * MAX);
    p->l_name = (char *) malloc(sizeof(char)* MAX);

    if(p->name == NULL || p->l_name == NULL){
        fprintf(stderr,"Error allocating memory");
        exit(1);
    }

    for(i = 0;i<2;i++){
        if(!fgets(p[i].name,sizeof(p[i].name),stdin)){
            fprintf(stderr,"Error reading string");
            exit(2);
        }
        if(!fgets(p[i].l_name,sizeof(p[i].l_name),stdin)){
            fprintf(stderr,"Error reading string");
            exit(3);
        }

    }
}

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335

2 Answers2

2

You declared an array of two elements

person p[2];

And you initialized data members only of the first element p[0]

p->name = (char *) malloc(sizeof(char) * MAX);
p->l_name = (char *) malloc(sizeof(char)* MAX);

The above statements are equivalent to

p[0].name = (char *) malloc(sizeof(char) * MAX);
p[0].l_name = (char *) malloc(sizeof(char)* MAX);

Data members of the second element p[1] are not initialized and have indeterminate values.

So the for loop invokes undefined behavior when you are trying to use these uninitialized data members of the second element of the array as for example

if(!fgets(p[i].name,sizeof(p[i].name),stdin)){

And moreover you are using an incorrect expression in the call of fgets

sizeof(p[i].name)

Data member name (and also l_name) is a pointer. So the above expression will yield the size of a pointer.

Instead you need to write just MAX as for example

if(!fgets(p[i].name, MAX, stdin )){
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 1
    And `sizeof(char)` is 1 by definition, so `sizeof(char) *` can be omitted everywhere. Then there's the problem of `sizeof(p[i].name)` being the size of the pointer, not the size of the allocation to which it points. – Fred Larson Jul 13 '21 at 20:39
2

Code fails to allocate for all p[i].name.

Wrong size passed to fgets().

Consider allocating after reading. Read into a local buffer and then form a right-sized copy.

for(i = 0; i<2; i++) {
  char buf[MAX + 2];

  if (fgets(buf, sizeof buf, stdin)) {
        fprintf(stderr,"Error reading string");
        exit(2);
    }
  buf[strcspn(buf, "\n")] = 0; // Lop off potential \n
  p[i].name = strdup(buf);     // Common, but non-standard string allocation

  if (fgets(buf, sizeof buf, stdin)) {
        fprintf(stderr,"Error reading string");
        exit(3);
    }
  buf[strcspn(buf, "\n")] = 0;
  p[i].lname = strdup(buf);
}

Sample strdup() if you do not have it in your library.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256