I have two structures:
struct product {
char *title; // Name of the product
char code[8]; // Max. 7 characters of product ID
int stock; // Current stock (number of units)
double price; // Price of a single unit
};
struct product_array {
struct product *arr;
unsigned int count;
};
I am adding products to product_array with function:
void add_product(struct product_array *pa, const char *title, const char *code,
int stock, double price) {
pa->count++;
struct product* nProduct = malloc(sizeof (struct product));
if (!nProduct) free(nProduct);
init_product(nProduct, title, code, stock, price);
pa->arr = realloc(pa->arr, (pa->count) * sizeof (struct product));
if (!pa->arr) free(pa->arr);
pa->arr[pa->count - 1] = *nProduct;
}
void init_product(struct product *pr, const char *title, const char *code,
int stock, double price) {
int titleLen = strlen(title);
int codeLen = strlen(code);
char *aTitle = calloc((1 + titleLen) * sizeof (char), 1);
strncpy(aTitle, title, titleLen);
char* codePtr = strncpy(pr->code, code, codeLen);
if (codeLen <= 7)
*(codePtr + codeLen) = 0;
else
*(codePtr + 7) = 0;
pr->title = aTitle;
pr->stock = stock;
pr->price = price;
}
add_product works like this in main.c
struct product_array pa;
pa.count = 0;
pa.arr = NULL;
struct product p;
init_product(&p, "test", "0000", 1, 0.50);
print_products(&pa);
add_product(&pa, "Product 1", "0000", 0, 10);
add_product(&pa, "Long name, isn't it", "1234567890", 10, 100);
add_product(&pa, "Product 3", "9999999", 0, 20);
print_products(&pa);
remove_all(&pa);
When I am trying to free all allocated memory, I run to problems. Here is remove all function:
int remove_all(struct product_array *pa) {
unsigned int i;
unsigned int until = pa->count;
struct product *prdPtr = pa->arr;
struct product *next;
for (i = 0; i < until; i++) {
next = prdPtr + 1;
free(prdPtr->title);
free(prdPtr); // this raises error
prdPtr = next;
}
if (pa->arr != NULL) {
free(pa->arr);
}
pa->count = 0;
return 1;
}
The for-loop overflows, but I am now trying to figure out the logic of memory freeing in this context.
In remove_all function I want to free all memory of product_array. I am iterating through every (struct)product in array and freeing the memory of title. After freeing memory of title I am trying to free the struct product itself. It works in first iteration, but when I come to second element, the title could be freed but free(prdPtr) raises SIGABRT.
What might I be missing? Why am I able to free the titles of products but not products themselves?
Thank you for help in advance.
The pa->arr is struct product * not struct product **.
So you have allocated memory for pa->arr and you should free it only once. pa->arr[i] is not a pointer, but just a structure.
You shouldn't free it, but you should free any memory allocated to its members like title.
So update your for loop as
...
for (i = 0; i < until; i++) {
next = prdPtr + 1;
free(prdPtr->title); //just free members
prdPtr = next;
}
if (pa->arr != NULL) {
free(pa->arr);
}
...
Edit:
Also note that there is an unnecessary malloc in add_product. Suggested fix:
void add_product(struct product_array *pa, const char *title, const char *code,
int stock, double price) {
struct product *pa_tmp;
pa->count++;
pa_tmp = realloc(pa->arr, (pa->count) * sizeof (struct product));
if (pa_tmp == null) {
/* handle out of memory error */
}
pa->arr = pa_tmp;
init_product(&pa->arr[pa->count - 1], title, code, stock, price);
}
You free the same Memory block twice:
// this makes pdrPtr to an alias of pa->arr
struct product *prdPtr = pa->arr;
for (i = 0; i < until; i++) {
...
free(prdPtr); // free prdPtr a.k.a. pa->arr
...
}
// here you free the same oject again.
free(pa->arr);
Remove the last free(pa->arr);.
Related
This simplified version of the program has the task of storing a char string in an array. If the product with the given name is already occupied, I don't store it, otherwise I use malloc to allocate space for the chain.
But I'm getting a segmentation fault and I can't find the fault
Complet program https://onecompiler.com/c/3yqnk3e5s
struct product{
int *regal;
char *name;
}product;
struct product allocList(struct product **list, int *alloc)
{
*list = (struct product*) malloc(sizeof(struct product)*(*alloc));
(*list)->regal = calloc(100, sizeof(int));
}
int isInList(struct product **list, int *listSize, char *item, int *itemIndex)
{
for(int i=0; i< *listSize; i++)
if(! strcmp(item, list[i]->name))
{
(*itemIndex) = i;
return 1;
}
return 0;
}
int insert(struct product **list, int *alloc, int *listSize, char *item, int regalIndex)
{
int itemIndex = 0;
if(isInList(*(&list), *(&listSize), item, &itemIndex))
return 0;
list[(*listSize)]->name = (char*) malloc(sizeof(char)*(strlen(item)+1));
strcpy(list[(*listSize)]->name, item);
(*listSize)++;
return 1;
}
int main()
{
struct product *list = NULL; int listAlloc = 2000; int listSize = 0; allocList(&list, &listAlloc);
char *str = "abcd"; char *str1 = "bcd";
insert(&list, &listAlloc, &listSize, str, 1);
insert(&list, &listAlloc, &listSize, str, 1);
insert(&list, &listAlloc, &listSize, str1, 1);
return 0;
}
Your program segfaults in insert() on the first line and when you fix that the following line:
list[(*listSize)]->name = (char*) malloc(sizeof(char)*(strlen(item)+1));
strcpy(list[(*listSize)]->name, item);
As list is of type struct product **list it means you deference whatever data is stored sizeof(list) * (*listSize) elements after list which is undefined behavior when *listList > 0. Instead you want to dereference list, then access a array element *listSize. I suggest you use strdup() instead of malloc() + strcpy():
(*list)[*listSize].name = strdup(item);
The next step would be to introduce a struct to hold your list implementation details, and pass that around instead of the double pointers.
Heyo,
I have problem allocating memory for my "database"
i have this struct
typedef struct TPrvek {
struct TPrvek *parent1;
struct TPrvek *parent2;
int id;//key
char *name;//value
} TPrvek;
typedef struct Database {
int size;
struct TPrvek **TField;
} DATABASE;
and I am initializing like this :
void init(DATABASE *db) {
DATABASE *newDb = (DATABASE *) malloc(sizeof(DATABASE));
newDb->size = 1000;//initial capacity
newDb->TField = (TPrvek **) calloc(newDb->size, sizeof(TPrvek *));
for (int i = 0; i < db->size; i++) {
newDb->TField[i] = NULL;
}
*db = *newDb;
}
But when i try to insert smth to it, im writing out of allocated memmory and I don't know how to repair it nor what is even wrong
snipet of insertion:
int addPerson(DATABASE *db,
int id,
const char *name,
int id1,
int id2) {
//some checks to make sure ids are in bounds and field for new person is empty
TPrvek *clovek = (TPrvek *) malloc(sizeof(TPrvek));
clovek->name = (char *) malloc(sizeof(name) + 1);
strcpy(clovek->name, name);
clovek->id = id;
//clovek->parent1 = (TPrvek *) malloc(sizeof(TPrvek));
//clovek->parent2 = (TPrvek *) malloc(sizeof(TPrvek));I was desperate, this is wrong I think
clovek->parent1 = db->TField[id1];
clovek->parent2 = db->TField[id2];
db->TField[id] = clovek;
//returns 1 if success
}
and in the main I have simple asserts to check functionality like :
int main(int argc,
char *argv[]) {
DATABASE a;
init(&a);
assert (addPerson(&a, 1, "John", 0, 0) == 1);
assert (addPerson(&a, 2, "Caroline", 0, 0) == 1);
...}
Any ideas?
I'm pretty new to c and memory allocating in general, so I would be glad for every bit of help :)
This line is the problem (at least one I see straight away):
clovek->name = (char *) malloc(sizeof(name) + 1);
Type of name is char *, and sizeof(char *) is size of pointer - always 8.
What you need instead is the length of string, i.e:
clovek->name = (char *) malloc(strlen(name) + 1);
I have a structure:
struct student{
int roll_no;
char *name = malloc(25 * sizeof(char));;
char *phone_no = malloc(10 * sizeof(char));;
char *dob = malloc(10 * sizeof(char));;
}*s1;
int main(){
s1 = malloc(5 * sizeof(student)); //array of student
//.....
}
What is appropriate code for the complete loop for allocating an array of student of size 'n' and then de-allocating it afterwards?
Note: The question here deals with allocation and de-allocation of elements of the instance of a structure.
This...
typedef struct student{
int roll_no; // (the following illegal syntax commented out)
char *name; // = malloc(25 * sizeof(char));;
char *phone_no; // = malloc(10 * sizeof(char));;
char *dob; // = malloc(10 * sizeof(char));;
}*s1;
...from what is being described as the need, (minus the illegal assignment statements) could probably better be formed as:
typedef struct {
int roll_no;
char *name; //needs memory
char *phone; //needs memory
char *dob; //needs memory
}STUDENT;
Then, use the new variable type: STUDENT, to create the instances of the struct as needed. Your OP indicates you need 5:
STUDENT s[5]; //Although this array needs no memory, the
//members referenced by it do
//(as indicated above)
Now, all that is necessary is to create memory for the 3 members that require it, in each of the 5 instances.
for(i=0;i<5;i++)
{
s[i].name = calloc(80, 1); //calloc creates AND initializes memory.
s[i].phone = calloc(20, 1); //therefore safer than malloc IMO.
s[i].dob = calloc(20, 1); //Also, change values as needed to support actual
//length needs for name, phone and dob
}
// Use the string members of s[i] as you would any other string, But do not
// forget to free them when no longer needed.
...
for(i=0;i<5;i++)
{
free(s[i].name);
free(s[i].phone);
free(s[i].dob);
}
Note, because of the way the array s is created in this example, i.e. with memory on the stack instead of the heap, there is no need to free it.
One other note, the example code above focused on a method to create memory for the char * members of your struct array, but when actually coding for keeps, the return of [m][c][re]alloc should always be checked that memory was created before trying to use the variable. For example:
s[i].name = calloc(80, 1);
if(!s[i].name) //checking that memory was created
{
;//if failed, then handle error.
}
...
In addition to ryyker's answer, if you want to do it dynamically:
#include <stdlib.h>
struct student{
int roll_no;
char *name;
char *phone;
char *dob;
};
int main()
{
int i, student_count = 5;
struct student ** s = malloc(sizeof(struct student *) * student_count);
if (s)
{
for (i = 0; i < student_count; ++i)
{
s[i] = malloc(sizeof(struct student));
if (s[i])
{
//set up student's members
}
}
for (i = 0; i < student_count; ++i)
{
//free student's members before the next line.
free(s[i]);
}
free(s);
}
return 0;
}
You must free everything you malloc, and as mentioned in the comments you cannot malloc inside the struct.
#include <stdio.h>
#include <stdlib.h>
#define NUM_STUDENTS 5
struct student{
int roll_no;
char *name;
char *phone;
char *dob;
};
int main(void)
{
int i;
// if this was me, I would simply replace this with
// struct student s[NUM_STUDENTS];, but the goal here is to illustrate
// malloc and free
struct student* s = malloc(sizeof(struct student) * NUM_STUDENTS);
if (s == NULL) // handle error
for (i=0; i<NUM_STUDENTS; i++)
{
// sizeof(char) is guaranteed to be 1, so it can be left out
s[i].name = malloc(25);
if (s[i].name == NULL) // handle error
s[i].phone = malloc(10);
if (s[i].phone == NULL) // handle error
s[i].dob = malloc(10);
if (s[i].dob == NULL) // handle error
}
// do stuff with with the data
....
// time to clean up, free in the reverse order from malloc
for (i=0; i<NUM_STUDENTS; i++)
{
// the dob, phone, name order here isn't important, just make sure you
// free each struct member before freeing the struct
free(s[i].dob);
free(s[i].phone);
free(s[i].name);
}
// now that all the members are freed, we can safely free s
free(s);
return 0;
}
User Abhijit gave an answser that was in the right direction, but not complete. His answer should have been:
typedef struct STUDENT{
int roll_no;
char *name;
char *phone;
char *dob;
}student;
void example(int n_students)
{
student **s;
int i;
s= malloc(n_students * sizeof(student *));
for (i=0; i<n_students; i++)
{
s[i]= malloc(sizeof(student));
s[i]->name= malloc(25);
s[i]->phone= malloc(10);
s[i]->dob= malloc(10);
}
// now free it:
for (i=0; i<n_students; i++)
{
free(s[i]->name);
free(s[i]->phone);
free(s[i]->dob);
free(s[i]);
}
free(s);
}
So I've written this program to represent a car park as a bitset, each space in the car park being one bit. I have a checkSpace function to check if a space is occupied or not and for some reason the pointer to my car park bitset changes or the data changes after I pass it into the function. To test it I set up the car park, I checked a space, then checked it again immediately after and for some reason the return value is changing when it shouldn't be. Any help would be appreciated!
struct carPark{
int spaces, levels;
unsigned char * park;
};
struct carPark * emptyCarPark(int levels, int spaces){
int chars = (spaces*levels)/8;
if((spaces*levels)%8 != 0){
chars++;
}
unsigned char park[chars];
for (int i = 0; i < chars; ++i){
park[i] = 0;
}
unsigned char * ptr = &park[0];
struct carPark * myPark = malloc(sizeof(struct carPark));
myPark->park = ptr;
myPark->spaces = spaces;
myPark->levels = levels;
return myPark;
}
int checkSpace(int level, int spaceNum, struct carPark * carpark){
int charPosition = ((level*carpark->spaces) + spaceNum)/8;
int bitPosition = ((level*carpark->spaces) + spaceNum)%8;
if(carpark->park[charPosition]&&(1<<bitPosition) != 0){
return 1;
}
return 0;
}
int main(int argc, char const *argv[]){
struct carPark * myPark = emptyCarPark(5,20);
printf("1st check: %d\n",checkSpace(1,1,myPark));
printf("Second check: %d\n",checkSpace(1,1,myPark));
return 0;
}
So when I run the program I get:
1st check: 0
Second check: 1
Look at the code below - in emptyCarPark() you are allocating the park array on the stack, and then returning a pointer to it. As soon as the function returns, the park array is no longer allocated and you have a dangling pointer - for more information, see: Cause of dangling pointers (Wikipedia)
unsigned char park[chars];
for (int i = 0; i < chars; ++i){
park[i] = 0;
}
// This is the pointer to an object on the stack.
unsigned char * ptr = &park[0];
struct carPark * myPark = malloc(sizeof(struct carPark));
myPark->park = ptr;
I am trying to make a dynamic array of structs, and I can successfully add one struct to it. But any more structs I add cause a segmentation fault. Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PEOPLE_BLOCK 4
struct Person {
char *first_name;
char *last_name;
unsigned int age;
};
int add_person(struct Person **people, size_t *people_size, size_t *population, struct Person p) {
if ((sizeof(struct Person) * *population) > *people_size) {
return -1;
}
if ((sizeof(struct Person) * (*population + 1)) >= *people_size) {
*people_size = *people_size + sizeof(struct Person) * PEOPLE_BLOCK;
*people = realloc(*people, *people_size);
if (!*people) {
return -1;
}
}
*people[*population] = p;
++*population;
return 0;
}
int main(int argc, char const *argv[]) {
size_t population;
size_t people_size;
struct Person *people, timn, batman;
population = 0;
people_size = sizeof(struct Person) * PEOPLE_BLOCK;
people = malloc(people_size);
timn.first_name = "Timn";
timn.last_name = "Timothy";
timn.age = 38;
add_person(&people, &people_size, &population, timn);
printf("Person 0's first name: %s\n", people[0].first_name);
batman.first_name = "Bat";
batman.last_name = "Man";
batman.age = 42;
add_person(&people, &people_size, &population, batman);
printf("Person 1's first name: %s\n", people[1].first_name);
free(people);
return 0;
}
I'd appreciate any help on why this is happening, thanks!
The problem resides with this line :
*people[*population] = p;
Change it to:
(*people)[*population] = p;
Why are the parenthesis requried?
The compiler has rules of operator precedence. When applying them, it sees your code as this:
*(people[*population]) = p;
which is not what you intended. Given a pointer-to-pointer Type **pp,
*pp[n] = value;
means "take the n'th pointer starting at pp, and assign value at the location dereferenced from the address that pointer holds. In other words, it means essentially this:
Type *p = pp[n];
*p = value;
What you really want is something that does this:
Type *p = *pp;
p[n] = value;
and that is what (*pp)[n], distinguishing the dereference of the pointer to pointer, gives you. Without that, you're using an invalid pointer, leading to your fault.
Not sure whether this answer will help, but anyway.
I don't understand your code, what you are trying to do.
You directly use the number of elements, a pointer to the first person, and the maximum number of elements. You'll probably have a lot of problems passing that all around.
You're storing literal strings directly in your structs, which means that in a real case (using no literals) that would result in memory leaks.
Here is my take. I've made PEOPLE_BLOCK smaller for testing reasons.
Hope this helps.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PEOPLE_BLOCK 2
typedef struct _Person {
char *first_name;
char *last_name;
unsigned int age;
} Person;
typedef struct _VectorPeople {
Person * people;
size_t num;
size_t max;
} VectorPeople;
void init(VectorPeople *v)
{
v->max = PEOPLE_BLOCK;
v->num = 0;
v->people = (Person *) malloc( sizeof(Person) * v->max );
}
void clear(VectorPeople *v)
{
// Clear persons
Person * it = v->people;
while( ( it - v->people ) < v->num ) {
free( it->first_name );
free( it->last_name );
++it;
}
// Clear vector
v->max = v->num = 0;
free( v->people );
v->people = NULL;
}
void add(VectorPeople *v, Person *p)
{
// Reserve
if ( v->num >= v->max ) {
v->max += PEOPLE_BLOCK;
// Realloc
v->people = realloc( v->people, v->max * sizeof(Person) );
if ( v->people == NULL ) {
exit( -1 );
}
}
// Copy strings
p->first_name = strdup( p->first_name );
p->last_name = strdup( p->last_name );
// Insert
v->people[ ( v->num )++ ] = *p;
}
int main(int argc, char const *argv[]) {
VectorPeople vp;
Person timn;
Person batman;
Person bond;
Person superman;
init( &vp );
timn.first_name = "Timn";
timn.last_name = "Timothy";
timn.age = 38;
add( &vp, &timn );
batman.first_name = "Batn";
batman.last_name = "Man";
batman.age = 42;
add( &vp, &batman );
bond.first_name = "James";
bond.last_name = "Bond";
bond.age = 45;
add( &vp, &bond );
superman.first_name = "Super";
superman.last_name = "Man";
superman.age = 45;
add( &vp, &superman );
int i = 0;
for(; i < vp.num; ++i ) {
printf( "Person: %s, %s.\n", vp.people[ i ].last_name, vp.people[ i ].first_name );
}
clear( &vp );
return 0;
}
There were a number of errors in your code. One thing to keep in mind, when you dynamically allocate memory, you are responsible for keeping track of it and freeing it when you no longer need it (otherwise, you will leak memory like a sieve).
In your code, you attempt to create an array of structs holding pointer to an array of characters. The char * pointers are NOT allocated and cannot simply be assigned in the manner you attempt. strdup can help, but you have just allocated memory, so free it when you are done with it.
Attempting to allocate an array of structs with varying (unknown) lengths of first_name and last_name requires that you keep track of every allocation. In some sense, you are better off declaring people as pointer to pointer to Person This allows iteration over your people without having to store the population somewhere allowing you to iterate until the first NULL pointer is encountered.
Likewise, creating a typedef to your struct can greatly cut down on the number of times you write sizeof (struct Person). It keeps the code clean and helps you think though the pointer haze.
Here is an example using a pointer-to-pointer-to-struct of what I think you intended to do. It is followed below by an implementation using only a pointer to struct. Evaluate both and decide which implementation you prefer:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXPOP 128
typedef struct {
char *first_name;
char *last_name;
unsigned char age;
} Person;
Person *add_person (Person ***ppl, Person p, size_t *pop, size_t *max);
Person **realloc_person (Person **ppl, size_t *n);
void free_person (Person *p);
void free_person_names (Person *p);
int main (void) {
size_t population = 0;
size_t maxp = MAXPOP;
size_t i = 0;
Person timn, batman;
Person **people = calloc (MAXPOP, sizeof *people);
if (!people) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1;
}
timn.first_name = strdup ("Timn");
timn.last_name = strdup ("Timothy");
timn.age = 38;
add_person (&people, timn, &population, &maxp);
free_person_names (&timn);
printf("\nPerson 0\n first name: %s\n last name : %s\n age : %hhu\n",
people[0]->first_name, people[0]->last_name, people[0]->age);
batman.first_name = strdup ("Bat");
batman.last_name = strdup ("Man");
batman.age = 42;
add_person (&people, batman, &population, &maxp);
free_person_names (&batman);
printf("\nPerson 1\n first name: %s\n last name : %s\n age : %hhu\n",
people[1]->first_name, people[1]->last_name, people[1]->age);
for (i = 0; i < population; i++)
free_person (people[i]);
free (people);
return 0;
}
/* add a person to an array of pointers to Person */
Person *add_person (Person ***ppl, Person p, size_t *pop, size_t *max)
{
if (*pop == *max)
*ppl = realloc_person (*ppl, max);
if (!((*ppl)[*pop] = malloc (sizeof ***ppl)))
return NULL;
size_t i = (*pop)++;
(*ppl)[i]-> first_name = strdup (p.first_name);
(*ppl)[i]-> last_name = strdup (p.last_name);
(*ppl)[i]-> age = p.age;
return (*ppl)[i];
}
/* realloc an array of pointers to Person setting memory to 0. */
Person **realloc_person (Person **ppl, size_t *n)
{
Person **tmp = realloc (ppl, 2 * *n * sizeof *ppl);
if (!tmp) {
fprintf (stderr, "Error: struct reallocation failure.\n");
// return NULL;
exit (EXIT_FAILURE);
}
ppl = tmp;
memset (ppl + *n, 0, *n * sizeof *ppl); /* memset new ptrs 0 */
*n *= 2;
return ppl;
}
/* free memory for a Person */
void free_person (Person *p)
{
if (!p) return;
if (p->first_name) free (p->first_name);
if (p->last_name) free (p->last_name);
free (p);
}
/* free only names of Person (for temp structs) */
void free_person_names (Person *p)
{
if (!p) return;
if (p->first_name) free (p->first_name);
if (p->last_name) free (p->last_name);
}
Note: updated to correct ppl start address on reallocation.
Using only Array of Person
While not inherently different than using a pointer to pointer to Person using a simple pointer to Person eliminates the ability to iterate over your array until a NULL or (empty) pointer is encountered. The following is an implementation of the same code using only an array of Person:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXPOP 128
typedef struct {
char *first_name;
char *last_name;
unsigned char age;
} Person;
Person *add_person (Person **ppl, Person p, size_t *pop, size_t *max);
Person *realloc_person (Person *ppl, size_t *n);
void free_person_names (Person p);
int main (void) {
size_t population = 0;
size_t maxp = MAXPOP;
size_t i = 0;
Person timn, batman;
Person *people = calloc (MAXPOP, sizeof *people);
if (!people) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1;
}
timn.first_name = strdup ("Timn");
timn.last_name = strdup ("Timothy");
timn.age = 38;
add_person (&people, timn, &population, &maxp);
free_person_names (timn);
printf("\nPerson 0\n first name: %s\n last name : %s\n age : %hhu\n",
people[0].first_name, people[0].last_name, people[0].age);
batman.first_name = strdup ("Bat");
batman.last_name = strdup ("Man");
batman.age = 42;
add_person (&people, batman, &population, &maxp);
free_person_names (batman);
printf("\nPerson 1\n first name: %s\n last name : %s\n age : %hhu\n",
people[1].first_name, people[1].last_name, people[1].age);
for (i = 0; i < population; i++)
free_person_names (people[i]);
free (people);
return 0;
}
/* add a person to an array of pointers to Person */
Person *add_person (Person **ppl, Person p, size_t *pop, size_t *max)
{
if (*pop == *max)
*ppl = realloc_person (*ppl, max);
size_t i = (*pop)++;
(*ppl)[i].first_name = strdup (p.first_name);
(*ppl)[i].last_name = strdup (p.last_name);
(*ppl)[i].age = p.age;
return ppl[i];
}
/* realloc an array Person setting memory to 0. */
Person *realloc_person (Person *ppl, size_t *n)
{
Person *tmp = realloc (ppl, 2 * *n * sizeof *ppl);
if (!tmp) {
fprintf (stderr, "Error: struct reallocation failure.\n");
// return NULL;
exit (EXIT_FAILURE);
}
ppl = tmp;
memset (ppl + *n, 0, *n * sizeof *ppl); /* memset new ptrs 0 */
*n *= 2;
return ppl;
}
/* free only names of Person (for temp structs) */
void free_person_names (Person p)
{
if (p.first_name) free (p.first_name);
if (p.last_name) free (p.last_name);
}
Output
$ ./bin/struct_add_person
Person 0
first name: Timn
last name : Timothy
age : 38
Person 1
first name: Bat
last name : Man
age : 42
One problem is the last argument of add_person() to be specific, the argument '(struct Person) p'. When 'timn' and 'batman' are passed into the add_person() function, they are passed as a copy of the original structure. In the add_person() structure, that data is actually on the stack and is volatile outside the scope of the function. Try changing the last argument to a pointer.