Reputation: 43
I have a simple struct s_person
and constructor(int number)
that takes the number of s_person
we want to construct and returns a pointer to it.
In this example I have constructed 2 s_person
, and assigned values to their attributes, name. And it works.
#include<stdio.h>
#include<stdlib.h>
#define MAX_NAME 50
typedef struct s_person {
char *name;
double grade;
}s_person;
s_person* construct(int number){
int each;
s_person *person = (s_person*)malloc(sizeof(s_person) * number);
if(person){
for(each=0; each<number; each++){
person[each].name = (char*)malloc(sizeof(char));
}
}
return person;
}
main()
{
s_person *person = construct(2);
person[0].name = "steven";
person[1].name = "michael";
printf("%s %s\n", person[0].name, person[1].name);
// This works
free(&person[0]);
printf("%s %s\n", person[0].name, person[1].name);
//This doesn't work
free(&person[1]); // Crashes here
printf("%s %s\n", person[0].name, person[1].name);
}
When I try to free the element 0 and print values again it works.
But if I try to free the element 1 and print values it crashes.
So, how can I free memory for the specific element in this array of structs?
And is it a valid way to make dynamically allocated memory for array of structs with constructor(int number)
function or is there a better practice?
Upvotes: 0
Views: 1325
Reputation: 310940
Your program has several errors most of which are related to memory allocation and memory leaks.
For example in function construct
you allocte memory for data member name
for(each=0; each<number; each++){
person[each].name = (char*)malloc(sizeof(char));
and then in main you overwrite this values
person[0].name = "steven";
person[1].name = "michael";
Thus you have no access any more to the allocated memory and it can not be freed.
As for this statement
free(&person[1]);
then you did not allocate person[1] separatly. You allocated one extent for two instances of the structure. So you may free only this allocated extent.
You could in function construct allocate each instance of the structure separatly by allocating an array of pointers to structures. In this case the function would look the following way
s_person ** construct( int number )
{
int each;
s_person **persons = ( s_person ** ) malloc( number * sizeof( s_person * ) );
if ( persons != NULL )
{
for ( each = 0; each < number; each++ )
{
persons[each] = ( s_person * )malloc( sizeof( s_person ) );
if ( persons[each] != NULL )
{
persons[each]->name = ( char* )malloc( MAX_NAME );
}
}
}
return persons;
}
And in main you have to use standard C function strcpy
to initialize data member name
of allocated structures with string literals.
#include <string.h>
//...
int main( void )
//^^^^^^^^^^^^^^
{
s_person **persons = construct( 2 );
if ( persons[0] ) strcpy( persons[0]->name, "steven" );
if ( persons[1] ) strcpy( persons[1]->name, "michael" );
//...
In this case you can delete each separate element. For example
free( persons[0]->name );
free( persons[0] );
persons[0] = NULL;
free( persons[1]->name );
free( persons[1] );
persons[1] = NULL;
// and at last
free( persons );
Upvotes: 1
Reputation: 7622
Why malloc personn you can use the stack:
#include<stdio.h>
#include<stdlib.h>
#define MAX_NAME 50
typedef struct s_person {
char *name;
double grade;
}s_person;
main()
{
s_person person[2];
person[0].name = "steven";
person[1].name = "michael";
printf("%s %s\n", person[0].name, person[1].name);
}
Upvotes: 0
Reputation: 3207
You cannot free a part of a memory block.
Within your function construct
you allocate a memory area with the size of sizeof(s_person) * number
bytes. If you try to free the first element you free the entire memory (notice that &person[0]
is equal to the value returned by construct(2);
.
If you try to free &person[1]
you try to free an unknown memory area and free(&person[1])
will fail. Freeing an invalid/unknown memory area does not lead to a crash. But in the code you've posted you free the entire memory area of person
which leads to an access violation when trying to get the address of person[1]
which is the input for your free
call.
If you want to free single persons you may want to use linked lists instead of one huge array... There are numerous examples on the web.
I've seen another issue within your code. Looking at your function construct
I've noticed that you allocate a single byte for the name of the persone (but I guess you want to have a maximum of MAX_NAME
characters for the name). So either modify person[each].name = (char*)malloc(sizeof(char));
to person[each].name = (char*)malloc(sizeof(char) * MAX_NAME);
or change your code into the following:
#define MAX_NAME 50
typedef struct s_person {
char name[MAX_NAME];
double grade;
}s_person;
s_person* construct(int number){
s_person *person = (s_person*)malloc(sizeof(s_person) * number);
return person;
}
I recommend the latter since you cannot forget to free the memory allocated for the name of each person which makes maintaning your code easier.
Upvotes: 0