Home > Blockchain >  How to allocate a struct dynamically in C to avoid a segmentation fault?
How to allocate a struct dynamically in C to avoid a segmentation fault?

Time:08-17

I'm having a problem to allocate a structure dynamically. I'm making a program that works as a contact book, but I'm getting the following error: Segmentation fault (core dumped).

The structure declaration, following the functions to add a contact and print all contacts:

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


typedef struct contact{
    int number;
    char name[80];
}contact;

void addContact(contact **contacts, int position){
    int aux=position;
    printf("Enter the name: ");
    setbuf(stdin, 0);
    fgets(contacts[position]->name,80,stdin);
    

    printf("Enter the telephone number: ");
    scanf("%d",&contacts[position]->number);
    return;
}

void printAllContacts(contact **contacts, int size){
    for(int i;i<size;i  ){
        printf("Contact %d:\n",i);
        printf("Name: %s\n",contacts[i]->name);
        printf("Telephone number: %d \n",contacts[i]->number);
    }
}


// Main function:

int main(){
    int size;
    printf("Enter the list size: ");
    scanf("%d",&size);

    contact *contacts= (contact*)malloc(sizeof(contact)*size);
    int counter=0;
    int x;

    do{
        printf("------------MENU-----------\n");
        printf("1-Add contact\n");
        printf("2-Print contacts list\n");
        printf("0-Exit\n");
        printf("----------------------------\n");
        printf("Enter an option: ");
        scanf("%d",&x);

        switch (x){
            case 1:
                addContact(&contacts,counter);
                counter  ;
                break;
            case 2:
                printAllContacts(&contacts,counter);
                break;
            case 0:
                break;        
        }
    }while(x!=0);


    return 0;

}

Can anyone help?

CodePudding user response:

The basic problem is that you're allocating an array of struct contact objects, but your addContact and printAllContacts expect an array of pointers to struct contact. You need to choose one or the other.

The easiest fix is probably to change the functions -- change the argument type to contact * instead of contact **, remove the & at the call site in main, and change the -> to . in the functions where needed.

CodePudding user response:

  1. Pass in a pointer (contacts *) instead of pointer to pointer (contacts **) to addContact() & printAllContacts(). Updated caller, and partially updated called code which already assumed it was operating on an array.
  2. Initialize i in printAllContacts().
  3. Removed the unnecessary cast of malloc() return value.
  4. Removed the name of the struct as you use only use the typedef.
  5. Introduced a NAME_LEN macro instead of the magic 80 value.
  6. Minor reformatting for readability & consistency.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define NAME_LEN 80

typedef struct {
    int number;
    char name[NAME_LEN];
} contact;

void addContact(contact *contacts, int position) {
    printf("Enter the name: ");
    setbuf(stdin, 0);
    fgets(contacts[position].name, NAME_LEN, stdin);

    printf("Enter the telephone number: ");
    scanf("%d", &contacts[position].number);
    return;
}

void printAllContacts(contact *contacts, int size) {
    for(int i=0; i<size;i  ) {
        printf("Contact %d:\n", i);
        printf("Name: %s\n", contacts[i].name);
        printf("Telephone number: %d\n", contacts[i].number);
    }
}

int main() {
    int size;
    printf("Enter the list size: ");
    scanf("%d", &size);

    contact *contacts = malloc(sizeof(contact)*size);
    int counter=0;
    int x;
    do {
        printf("------------MENU-----------\n");
        printf("1-Add contact\n");
        printf("2-Print contacts list\n");
        printf("0-Exit\n");
        printf("----------------------------\n");
        printf("Enter an option: ");
        scanf("%d", &x);

        switch (x) {
            case 1:
                addContact(contacts, counter  );
                break;
            case 2:
                printAllContacts(contacts, counter);
                break;
            case 0:
                break;
        }
    } while(x!=0);
    return 0;
}

CodePudding user response:

I would add additional structure holding all the contacts and also keeping the number of contacts stored. You do not need to know the size of the list - it will grow with any added contact.

When you test the idea I would advise you to not use user input functions, only fixed data. It makes debugging and testing faster and easier. Especially function which adds data should not communicate with the external world. Caller is the correct place to do it

Also use function return values to return result or status codes. You tend to use void everywhere - it is not a good idea.

typedef struct contact{
    unsigned number;
    char name[80];
}contact;

typedef struct
{
    size_t size;
    contact contacts[];
}constactList;

constactList *addContact(constactList *list, const char *name, const unsigned number)
{
    size_t newsize = list ? list -> size   1 : 1;
    list = realloc(list, sizeof(*list)   sizeof(list -> contacts[0]) * newsize);
    if(list)
    {
        strncpy(list -> contacts[list -> size].name, name, sizeof(list -> contacts[0].name));
        list -> contacts[list -> size].name[sizeof(list -> contacts[0].name) - 1] = 0;  
        list -> contacts[list -> size].number = number;
        list -> size = newsize;
    }
    return list;
}

void printContacts(const constactList *list)
{
    if(list)
    {
        for(size_t i = 0; i < list -> size; i  ) printf("[%3zu] %s, %u\n", i, list -> contacts[i].name, list -> contacts[i].number);
    }
}

int main(void) 
{
    constactList *list = NULL;

    list = addContact(list, "James Bond", 7);
    if(!list) {/* error handling*/}
    list = addContact(list, "Mata Hari", 99);
    if(!list) {/* error handling*/}
    list = addContact(list, "Wladymir Putin", 666);
    if(!list) {/* error handling*/}
    printContacts(list);
    free(list);
}
  •  Tags:  
  • c
  • Related