Using malloc with structures in c

So, I'm trying to add malloc to the phone book application that I created, but since I'm a little new to C. I'm not sure what I'm doing is correct. I ran into a small problem, but I read the book of beginners, which I have, and it does not work, although in detail, as I would like, I can’t tell by finding Google if I’m just completely wrong in the way I installed malloc , or if there is anything else that I missed.

Basically, I have 4 arrays in my structure, First_Name , Last_name , home , cell . Each of them has 2 functions, a function that receives information from the user and a function that prints and adds user information to the phone book. What I have now is a small snipit of source code that only adds the first name to the phonebook (so this is not all the code), and in every function that receives user input, I want to add the malloc function. Now I have only the first name and the first malloc setup, but the problem is that when I go to check the phone book to find out if the name was successfully entered, the program quits. If I select malloc, it will work successfully.

 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <conio.h> #define BUFFER 50 //Structure for contacts typedef struct friends_contact { char *First_Name; char *Last_Name; char *home; char *cell; } fr; void menu(fr * friends, int *counter, int user_entry, int i); void setFirst(fr *, int *, int i); char getFirst(fr *, int i); void add_contact(fr * friends, int *counter, int i); void print_contact(fr * friends, int *counter, int i); int main() { int user_entry = 0; fr *friends; int counter = 0; int i = 0; menu(friends, &counter, user_entry, i); getch(); return 0; } //Menu function void menu(fr * friends, int *counter, int user_entry, int i) { do { int result; printf("\nPhone Book Application\n"); printf ("1) Add friend\n2) Delete friend\n3) Show a friend\n4)Showphonebook\n5)Exit\n"); scanf("%d", &user_entry); if (user_entry == 1) { add_contact(friends, counter, i); } if (user_entry == 2) { } if (user_entry == 3) { } if (user_entry == 4) { print_contact(friends, counter, i); } } while (user_entry != 5); } void setFirst(fr * friends, int *counter, int i) { // THE MALLOC FUNCTION! friends = (fr *) malloc(BUFFER * sizeof(fr)); printf("Enter a first name \n"); scanf("%s", friends[*counter].First_Name); if (friends != NULL) { free(friends); } } char getFirst(fr * friends, int pos) { printf("%s ", friends[pos].First_Name); return *friends[pos].First_Name; } void add_contact(fr * friends, int *counter, int i) { setFirst(friends, counter, i); (*counter)++; } void print_contact(fr * friends, int *counter, int i) { for (i = 0; i < *counter; i++) if (strlen(friends[i].First_Name)) { getFirst(friends, i); } } 

Looking to give a big green tick to someone who can help me.

+4
source share
4 answers

It is necessary to allocate memory both for recording as a whole, and separately for each field. For instance:

 void string_realloc_and_copy (char **dest, const char *src) { size_t len = strlen (src); *dest = realloc (*dest, len + 1); memcpy (*dest, src, len + 1); } typedef struct { char *name; char *title; } record; record * record_new () { record *r = malloc (sizeof (record)); r->name = NULL; r->title = NULL; return r; } void record_free (record *r) { free (r->name); free (r->title); free (r); } void record_set_name (record *r, const char *name) { string_realloc_and_copy (&r->name, name); } void record_set_title (record *r, const char *title) { string_realloc_and_copy (&r->title, title); } 

Now create a record and fill it with the values ​​read by the user:

 record *r; char buffer[100 + 1]; r = record_new (); printf("Enter a first name \n"); if (scanf ("%100s", buffer) == 1) { record_set_name (r, buffer); } ... 
+8
source

There are some problems here:

 void setFirst(fr*friends, int* counter, int i) { // THE MALLOC FUNCTION! friends=(fr*) malloc(BUFFER*sizeof(fr)); <-- This is not doing what you're thinking 

sizeof(fr) will be the size needed for 4 pointers per character. For example, if you are on an x86 32-bit platform, a char pointer requires 4 bytes, thus:

 sizeof(fr) == 4 x 4 == 16 bytes 

So, now you are malloc'ing 16 * BUFFER or 16x50 = 800 bytes. This allows you to have an array of 50 'fr' structures.

 fr * friend | +--------> FirstName* | LastName* | home* | cell* +----> FirstName* | LastName* | home* | cell* ... 

So, you have memory for 50 structures, but the contents of these structures still have no memory. You need to assign memory to each member of the structure (and don't forget to free all of these as well), or you can make them static members with arrays instead of pointers.

The second problem:

 if(friends != NULL) <-- if malloc was successful { free(friends); <-- release the memory 

You just lost all your friends. :)
You need to free up memory, but at the end of the program or at the end of where you use it. If you appointed and then immediately released, the memory has disappeared and you will no longer be able to access it.

+1
source

Your structure contains only pointers, not allocated memory. You would better define it to store arrays into which you write names, etc .:

 typedef struct friends_contact{ char First_Name[20]; char Last_Name[20]; char home[20]; char cell[20]; } fr; 

Here I made each field 20 characters long, but you can change it.


Edit: Yes, of course, you can use dynamic memory, but is there any reason to worry? The advantage of dynamic strings is that they can be exactly the right size; you can save several bytes, and you guarantee the possibility of fitting names to fields. But are there many names that are longer than 20 characters and it would be important that they be shortened? With malloc, there are many fictitious distributions (each of which may fail) and, of course, liberation.

As a compromise, you can make a fixed size of phone numbers (they do not change) and the names are dynamic; then assign the names using strdup (which may also fail).

 typedef struct friends_contact{ char *First_Name; char *Last_Name; char home[12]; char cell[12]; } fr; 
0
source

There are a few more things here, but first, consider the following.

In setFirst you are free use your friends buffer, essentially saying, "I don't need it anymore." When you do this, that memory just goes away. If you plan to dynamically allocate structures to the caller, you must either provide a separate release function or inform your user of their responsibility to clear this structure.

In addition, you only change the local copy of the friends index. If you want to point the caller to a new buffer, you need to change the argument type to fr** .

0
source

Source: https://habr.com/ru/post/1445108/


All Articles