I've been working on some C projects and was wondering if I create a custom structure, for example, Student, define a variable of the custom structure type, and allocate memory to it using malloc, does it also allocate memory for variables' properties separately or are they all kept in the same space? if yes, will there be any difference if I allocate memory using malloc separately for every property?
For example:
typedef struct {
unsigned int ID;
char *first_name;
char *last_name;
int num_grades;
float *grades;
unsigned short int days_absent;
char *memo;
} Student;
int main() {
// Declare students array
Student *students = NULL;
int students_size = 0;
// Allocate memory for students array
students = (Student *) malloc(sizeof(Student));
return 0;
}
That allocates enough memory for the struct, which includes enough memory for ID, first_name, etc and all padding requirements.
Note that while it allocates memory for the pointer first_name, it doesn't allocate a buffer to hold the name. It just allocates memory for first_name, a pointer. If you want memory in which to store the names, you will need to allocate it.
If the struct had a char first_name[40]; field, it would be a different story. To allocate enough memory for first_name, it needs to allocate enough memory for an array of 40 char instead of enough for a pointer. This does provide a space in which a string could be stored.
No, it doesn't. It allocates uninitialized memory for the number of chars you want - which is usually a calculation based on sizeofs.
If you want it to allocate memory to store values that your struct has pointers to, you'll have to add that after having allocated the memory for the struct.
You'll also have to "go backwards" when you free such a struct.
Example:
typedef struct {
char *data;
} foo;
foo *foo_create() {
foo *retval = malloc(sizeof *retval ); // try allocation
if(retval == NULL) return NULL; // check that it worked
retval->data = malloc(10) ; // allocate something for a member
if(retval->data == NULL) { // check that it worked
free(retval); // oh, it didn't, free what you allocated
return NULL; // and return something to indicate failure
}
return retval; // all successful
}
void foo_free(foo *elem) {
if(elem != NULL) { // just a precaution
free(elem->data); // free the member's memory
free(elem); // then the memory for the object
}
}
Does it also allocate memory for variables' properties separately
No. After allocating for students, allocate for students->first_name, students->last_name, etc.
does it also allocate memory for variables' properties separately or are they all kept in the same space?
No. malloc() is given a size to indicate how much contiguous memory to allocate, and it returns a pointer pointing to it... malloc() knows nothing about what you are going to do with the pointer. When you assign it to a pointer variable to Student type is, somehow, dressing a bunch of memory with structure. But the char * fields that you have defined inside (or if you have other fields pointing to other structured data) those have to be allocated separately (or ask for more memory to allocate them all in the same returned segment, but this requires practice and knowledge of the alignment issues that arise from it)
Related
I am struggling to figure out how to allocate memory for my studentContent variable.
struct contactInfo {
char Name[101];
char Assignment[101];
char MarkDescription[101];
char feedBack[12][101];
};
struct contactInfo studentContent
I want to use malloc() to allocate memory for my structure variable. After the structure is filled I would like to reallocate the memory so I am only utilizing as much space within each field as I need to.
The first assignment sets ptr to the address of the local variable studentContent, however the next line overwrites that. It changes ptr to point to a dynamically allocated buffer with space for 2 instances of struct contactInfo.
If what you want is to have an array of struct contactInfo, and have the number of elements of that array increase as you have more instances of struct contactInfo to populate, you pass ptr to realloc with a size of n * sizeof *ptr, where n is the number of elements in the array.
struct contactInfo *tmp_ptr = realloc(ptr, n * sizeof *ptr);
if (tmp_ptr == NULL) {
perror("realloc failed");
exit(1);
}
ptr = tmp_ptr;
Note that you don't have to declare an instance of struct contactInfo (studentContent in your original code), just a pointer to one.
EDIT:
Based on your comment, since you just need a single instance to populate in order to read and write one chuck of data at a time, you don't need to use dynamic memory allocation. Just declare a single instance and overwrite the contents each time.
Let's say I have this student struct defined:
struct student {
char *name;
};
typedef struct student Student
Now I have the following function:
void add_student(const char *student_name) {
// create new student
Student *new_s;
new_s = malloc(sizeof(Student));
strncpy(new_s->name, student_name, sizeof(new_s->name) - 1)
}
I want to add the student_name to the name of the new student struct. However because const char and char are different I have to use strncpy.
I tried it this way, however I get a segmentation fault, what's wrong?
You are only allocating memory for the structure new_s in this line
new_s = malloc(sizeof(Student));
This includes the variable char* name, which is a pointer to a char. Although, you also need memory to which this pointer will point at.
So, you need to allocate memory for the character pointer name inside the structure.
// create new student
Student *new_s;
new_s = malloc(sizeof(Student));
new_s->name = malloc(100); //assuming you need to store a string of len 100
As Johan Wentholt correctly outlined in his answer, you must allocate memory for both the Student structure and the string its member name points to, but you must return the new structure so the caller can do something with it:
Student *add_student(const char *student_name) {
Student *new_s = malloc(sizeof(Student));
if (new_s) {
new_s->name = strdup(student_name);
}
return new_s;
}
You code invokes undefined behavior because you did not allocate memory for the string, worse even, you left the name member uninitialized (malloc does not initialize the memory it returns).
Furthermore, you should not use strncpy. It is not some safe version of strcpy, it is a very error prone function, whose semantics are poorly understood by most programmers. NEVER use this function. If you see it used, there are chances you are either in front of a bug or there is a better method to replace it.
For completeness, your code:
strncpy(new_s->name, student_name, sizeof(new_s->name) - 1);
Would attempt to copy at most sizeof(char*)-1 characters from student_name into the array pointer to by new_s->name.
If the student_name is longer, the destination will not be null terminated,
If it is shorter, the destination will be padded with null bytes upto the given size.
Here the destination pointer is uninitialized and the size information is bogus anyway: you really want to copy all characters in the string plus the null terminator, which is exactly what strcpy does. But you need to allocate enough memory for that. You could use:
new_s->data = malloc(strlen(student_name) + 1);
strcpy(new_s->data, student_name);
The Posix function strdup() does both operations in one call:
new_s->data = strdup(student_name);
Haris gave a good solution. But like Florian Zwoch said in the comments you can also use strdup like so:
void add_student(const char *student_name)
{
Student *new_s = malloc(sizeof(Student));
new_s->name = strdup(student_name);
}
Keep in mind that you have to free new_s->name and than free new_s.
You should also check the return value of malloc and strdup for NULL value. Since it returns NULL if insufficient memory is available.
As side note, you can shorten up the struct and typedef to one statement like so:
typedef struct student {
char *name;
} Student;
I have a struct which contains 2 integers and a pointer to another struct. I allocate memory for struct first and then for the pointer. When I free the memory I free up the pointer first and then I free up the struct.
When I run my program and call the function that frees memory it crashes when the call is made. When I don't call the function that frees memory it works fine, but then I'm not freeing up the memory.
I tried removing the line that frees the memory allocated to the pointer and the program doesn't crash, but I don't think thats right since a "free" is needed for every "malloc/calloc" right? Anyone see anything wrong with the freeing function?
//Define a struct data type
struct q_element
{
//Declaration of struct members
int element;
int priority;
struct q_element *next_element;
};
//Method to allocate memory
struct q_element* allocateStruct()
{
//Declaration of a variable
struct q_element *e;
//Allocate memory for one queue element
e = malloc(sizeof(struct q_element));
//Allocate memory for one pointer to a queue element
e->next_element = calloc(1,sizeof(struct q_element*));
//Initialize integer members of queue element
e->element = 0;
e->priority = 0;
return e;
}
//Method to free memory allocated
void freeStruct(struct q_element* e)
{
//Free up pointer member
free(e->next_element);
//Free up struct
free(e);
}
You don't need to allocate memory for the next_element pointer. The pointer is already there, just like int element for example.
So if you want to allocate just one element, you can set the next_element pointer to NULL and everything is fine.
You are not allocating enough memory for e->next_element in the line:
e->next_element = calloc(1,sizeof(struct q_element*));
// ^^^ remove the *
That should be:
e->next_element = calloc(1,sizeof(struct q_element));
If you used e->next_element as though it were a valid pointer, you most likely ended up accessing memory that you did not allocate. That clobbered some of the bookkeeping information created by calloc, which lead to problems when you called free.
In
//Allocate memory for one pointer to a queue element
e->next_element = calloc(1,sizeof(struct q_element*));
you allocate space for a pointer to a q_element structure, rather than a q_element structure. Do you attempt to write to this structure, because if so, that's probably where it goes wrong.
As a side note you might be better off just doing
e->next_element = 0
inside allocate_struct and then doing e->next_element = allocate_struct() outside the function later.
In addition to what everyone else is mentioning about allocation, you also need a sentinel to check if the next_element was already freed. You may be attempting a double free.
Try the following code:
void freeStruct(struct q_element* e)
{
//Free up pointer member
if(e->next_element != 0){
free(e->next_element);
e->next_element = 0;
}
//Free up struct
free(e);
}
Let's say we have a struct :
struct Person {
char *name;
};
struct Person *Person_create(char *name){
struct Person *who = malloc(sizeof(struct Person));
assert(who != NULL);
who->name = strdup(name);
return who;
}
void Person_destroy(struct Person *who){
assert(who != NULL);
free(who->name);
free(who);
}
And the main function :
int main(int argc,char *argv[]){
struct Person *mike = Person_create("mike");
Person_print(mike);
Person_destroy(mike);
return 0;
}
The above code won't work properly without the strdup() function. Valgrind says that the address you try to free with free(who->name) is not malloc'd. What's the story behind this, didn't I malloc'd that memory when I malloc'd the struct? And what difference does the strdup() make?
In your code each Person object involves two independent blocks of memory: the struct Person object itself and the separate memory block for the name. That separate memory block is pointed by the name pointer inside the struct. When you allocate struct Person by using malloc, you are not allocating any memory for the name. It is, again, an independent block of memory that should be allocated independently.
How you are planning to allocate memory for the name is entirely up to you. If you use strdup (which is essentially a wrapper for malloc) as in your code above, then you will have to free it by free in the end.
You did not explain what you mean by "without the strdup() function". What did you code look like without it? If you simply did
who->name = name;
then you made that who->name pointer to point directly to the string literal memory occupied by literal "mike". String literals reside in static memory. You are not allowed to free them. This is what valgrind is telling you.
Mallocing the struct allocates memory for the pointer name but it doesn't allocate any memory for name to point to. At that point who->name will be some random garbage value so freeing it makes no sense.
strdup uses malloc internally to allocate memory for the string it copies. Once you've got a pointer back from strdup you can, and should, free it when you're done.
strdup do noes call malloc, it is only string operation. you only malloc the pointer to the struct ,not the inner member
I am confused with the usage of free() in regard to data structures in C.
If I have the following data structure:
struct Person {
char *name;
int age;
float weight;
float height;
};
I am allocating memory for the structure via malloc(), likewise: struct Person *me = malloc(sizeof(struct Person));
After I am done with using my structure (right before ending the program), I proceed to freeing the memory allocated, like this:
free(person_pointer->name);
free(person_pointer);
Freeing the memory that the name pointer points to is necessary to my knowledge, because if I only free person_pointer I only free the memory that was allocated to store the data structure and its members but not the memory that is pointed to by pointers-members of the structure.
However with my implementation valgrind seems to suggest that the first free() is invalid.
So my question boils down to: When I free the memory that a struct occupies via a pointer, should I preemptively free the memory that member pointers point to or not?
EDIT: This is my whole code:
#include <stdio.h>
#include <stdlib.h>
struct Person {
char *name;
int age;
float weight;
float height;
};
int main(int argc, char **argv)
{
struct Person *me = malloc(sizeof(struct Person));
me->name = "Fotis";
me->age = 20;
me->height = 1.75;
me->weight = 75;
printf("My name is %s and I am %d years old.\n", me->name, me->age);
printf("I am %f meters tall and I weight %f kgs\n", me->height, me->weight);
free(me->name);
free(me);
return 0;
}
me->name = "Fotis";
/* ... */
free(me->name);
The rule is:
1 malloc = 1 free
You didn't use malloc on me->name, so you don't have to free it.
BTW, me->name should be of const char * type.
When you do
me->name = "Fotis";
The name pointer is not alloced by malloc, it points to a stack variable which is stored in the strings table of your binary file at compile time, hence you can't free it.
The rule of thumb is : Only free what you have malloced.
You can't update this read-only string though.
If you did something like :
me->name = strdup("Fotis");
Since strdup does a malloc (see the manual), you have to free it, and you can update the string after its creation.
Yes you have to free all the memory of pointers inside the structure if you allocated them.
Also make sure you free the members before you free the structure.
A simple way to remember is free them in the reverse order in which you have allocated.
The problem is that you didn't actually malloc'ed the char * name inside your structure.
struct Person *me = malloc(sizeof(struct Person));
me->name = strdup("Fotis");
...
free(me->name);
free(me);
return (0);
When you write this
me->name = "Fotis";
You don't actually malloc, the pointer name points to a stack variable of type const char *, wich is not malloc'ed.