Hello I have a question regarding malloc and free type of things.
suppose I have a structure with another structure inside it
typedef struct All{
int number;
} A;
typedef struct Bet{
A *point;
} B;
Then I create a B.
B* first = malloc(sizeof(B));
first->point=malloc(sizeof(A));
Now lets say I want to make a function that deletes the struct B entirely.
For the delete function I know we have to use
free(first);
So do I also have to free(first->point) or will it disappear automatically if i do free(first);
I want to add more to what #thisisbenmanley said and build an actual explination that will also show how to wrap part of the code you write.
The basics
I'll cover just malloc() and free() here. Whenever you call malloc() there should be a free() also. Let's take this example with a simple int.
int *p = malloc(sizeof(int));
*p = 5;
printf("%d", *p);
free(p);
It is the same for a struct. Another example:
typedef struct Person
{
int Age;
int Height;
}Person;
Person* p = malloc(sizeof(Person));
p->Age = 20;
p->Height = 185;
// do something with it ...
free(p);
Another very important thing you have to know: malloc() can return NULL if the allocation fails. It actually means that there is no space to allocate the block. It is very important to actually check for it. For example:
int* v = malloc(sizeof(int)*999999999);
if (v == NULL)
{
printf("Allocation failed.");
return -1;
}
// Allocation successfull. Do something with the vector ...
Structures in structures and structures with pointers
If structures do not contain pointers just free() will do the job. Example:
typedef struct Point
{
int x;
int y;
}Point;
typedef struct Line
{
Point a;
Point b;
}Line;
// this will allocate actually 4 ints
Line* p = malloc(sizeof(Line));
// this is how you access each point's coordinates.
p->a.x;
// do something ...
// this will free both points (the 4 ints)
free(p);
Now this is where code can get very unclear depending on each situation. If a structure contains one or more pointers if might prove difficult to keep the code simple to read. Suppose the following struct:
typedef struct Person
{
int Age;
int Height;
char* FName;
char* LName;
char* Address;
}Person;
If you want to allocate a Person you need 4 malloc() calls. If you also add error checking it will be quite voluminous. Definetly this should be wrapped inside a function:
Person* AllocPerson()
{
// i'm skipping it now so that my point is clear, but checking
// if malloc returned NULL is recommended
Person* p = malloc(sizeof(Person));
p->FName = malloc(sizeof(char)*30);
p->LName = malloc(sizeof(char)*30);
p->Address = malloc(sizeof(char)*40);
return p;
}
Now whenever you need a Person you can just Person* p = AllocPerson();. Same goes with a FreePerson() function which will take 4 free() calls so that after you finished working with the struct, you simply call FreePerson(p).
void FreePerson(Person* p)
{
free(p->FName);
free(p->LName);
free(p->Address);
free(p);
}
You can evolve the AllocPerson function even further and turn it into a Create function:
Person* CreatePerson(int Age, int Height, char* FirstName, char* LastName, char* Address)
{
// i'm skipping it now so that my point is clear, but checking
// if malloc returned NULL is recommended
Person* p = malloc(sizeof(Person));
p->FName = malloc(sizeof(char)*30);
p->LName = malloc(sizeof(char)*30);
p->Address = malloc(sizeof(char)*40);
p->Age = Age;
p->Height = Height;
strcpy(p->FName, FirstName);
strcpy(p->LName, LastName);
strcpy(p->Address, Address);
return p;
}
Now you can just do this whenever you need a person:
Person* p = CreatePerson(20, 180, "Alex", "Boris", "Street nr. 5");
The CreatePerson() function both allocates and initialises fields of a Person instance. This aproach of making a Create and Delete function to a structure is widely used in C, especially when you have to use an already made API.
Important notes
Always free() memory even though after exiting main() your OS will take care of the blocks still allocated. This is considered good practice.
Try to use dynamic memory as less as possible. The Heap is slower than the Stack!
Try to reuse allocated space whenever possible. Allocating and Freeing are expensive operations!
You would also have to free(first->point). When you free(first), all that will deallocate is the bytes holding the struct first, which only holds a pointer. That alone will not touch the actual memory address pointed to by point; free(first->point) beforehand would cover that.
Related
Here is a quick test C program that I've coded to see how struct memory allocation works...
#include <stdio.h>
#include <stdlib.h>
typedef struct _node {
int kk;
int zz;
} node;
node ** createNode(){
node** res = (node**) malloc(sizeof(node*)*10);
int i,j;
for(i= 0;i<10;i++){
res[i] = (node*) malloc(sizeof(node)*10);
for(j=0;j<10;j++){
res[i][j].kk=33;
}
}
return res;
}
int main(void) {
node ** g = createNode();
printf("%d",g[0][0].kk);
return 0;
}
This program prints the value "33". Now this has become obvious to me, but reflecting on it, I don't understand why...
Now that I think about it, shouldn't the variable g be of type node *** ?
And the print statement look something like printf("%d",g[0][0]->kk); ?
Where in the second version, I've essentially done the same thing as my original code, but I have a pointer to a node instead of the actual node.
What is the difference between the two in terms of the first being statically allocated (I think) and the second being dynamically allocated... and shouldn't the node values I created in my createNode() function be destroyed once outside the scope of that function?
Just a little confused is all :S I need someone to clarify this for me, what is the difference between node** and node***
Let's use a simpler function to make samples. For example we want to create a function which will be allocate memory for integer and assign some value. The function does the same thing as your one.
int* createInt() {
int *res = malloc(sizeof(int));
*res = 5;
return res;
}
This function creates a pointer and allocate dynamic memory for int. After this the function returns an address of memory where the int is but the res pointer won't exist. By the way look at this answer to similar question, it's worth reading.
As you understand in main function you use
int *myInt = createInt();
Because you want to assign an address of allocated memory to pointer to deal with that and free after all.
But you could do this
int** createInt() {
static int *res;
res = malloc(sizeof(int));
*res = 5;
return &res;
}
And in main
int **myInt = createInt();
Here you do the same things as above but create static pointer so it is retained from one call of the function to another. So you can return an address of this pointer. It will point to actual data after function ends.
As mentioned in comments my code isn't safe because if you call this function twice it leads to memory leak. You could do
int* createSingletonInt() {
static int *res;
if (res != NULL) {
return res;
}
res = malloc(sizeof(int));
*res = 5;
return res;
}
That can be useful if you want to deal with the same int. And more useful if you deal with something but not int :>
I think it can be applied to your example.
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.
Am unable to run this code...
#include<cstdio>
int main()
{
struct a{
int b;
struct a *next;
};
typedef struct a no;
no *n;
n->b = 12;
n->next = NULL;
n->next->b = 12;
n->next->next = NULL;
printf("%d %d", n->b, n->next->b);
getchar();
return 0;
}
When you say:
no *n;
you get an uninitialised pointer. When you use that pointer, you get undefined behaviour.
You allocated space for a pointer to a structure, but you didn't allocate space for the actual structure. This means that you don't have a memory address for the structure you are using.
In addition, the pointer points to some random memory address because you didn't initialize it. As a result, you could be trying to read and write to memory that doesn't belong to you, which can cause your program or even your system to crash because of the undefined behavior that results.
As #Neil Butterworth said, you get an uninitialised pointer. This mean that this pointer could point to anywhere, thus giving an access violation error. The way to fix this is simple, just call malloc() before using that pointer. malloc() gives that pointer a valid and usable address, so no one will complain about that.
You're declaring a struct INSIDE a function.
Declare the struct OUTSIDE of the function.
The typedef should be declared outside the function too.
#include<cstdio>
struct a{
int b;
struct a *next;
};
typedef struct a no;
int main()
{
///... your code...
}
try something like this:
no *n = (no*)malloc(sizeof(no));
#include <cstdio>
/* declaring the struct in the function definition may be possible (I'm not sure,
actually, haha). Unless you have a GOOD reason, it's good practice to declare
structs, globals, typedefs, etc... outside the function */
typedef struct a{
int b;
struct a *next;
} no;
int main()
{
no *n;
/* Here, you have a pointer. Remember these are simply (generally) 32-bit values
defined in your stack space used to store a memory location which points to your
ACTUAL struct a! Depending on what USED to be in the stack space, this could
point ANYWHERE in memory, but usually you will find that it points to the NULL
memory location, which is just address "0". To get this to point to something,
you have to allocate empty space on your heap to store your struct... */
n = malloc(sizeof(no));
/* Now your pointer n points to an allocated 'struct a', and you can use it like
normal */
n->b = 12;
n->next = NULL;
/* You just set n->next, which is another 'no' pointer, to NULL. This means that
n->next points nowhere. So, just like above you have to malloc another instance
of the struct! */
n->next = malloc(sizeof(no));
/* NOW you can use n->next with no ill effects! */
n->next->b = 12;
n->next->next = NULL;
printf("%d %d", n->b, n->next->b);
getchar();
/* After you're done with your structs, you want to free them using the POINTERS
that reference them */
free(n->next);
free(n);
return 0;
}
I'm not sure how to explain this but this piece of code bellow can compile perfectly but when you run it, SIGSEV.
Please, can anyone tell precisely where I got things wrong?
The fact is I want to be able to access elements by index as below and at the same time to be able to work with struct.
#include <stdio.h>
#include <stdlib.h>
/* This is a struct describing properties of an element */
struct element{
int age;
char* name;
};
/* This struct contains a pointer to a pointer on a element "struct element" */
struct person{
struct element** p;
int id;
};
/* Thus function initializes a struct person by allocation memory for it */
struct person* init(int size)
{
struct person* sample = (struct person* )malloc(size*sizeof(struct person));
sample->p = NULL;
sample->id = 0;
return sample;
}
/* use this function to insert a new element in the struct */
void insert(struct person* sample, char* _name, int _age)
{
sample->p[sample->id]->name = _name; /* the program crashes here according to the debugger , but why?? */
sample->p[sample->id]->age = _age; /* of course, this will cause trouble too because it has the same construct as the previous one */
sample->id++;
}
/* main entry */
int main()
{
struct person* student = init(10); /* Allocating space for 10 students */
insert(student, "kido", 8);
printf("Your name is %s and your age is %d", student->p[0]->name, student->p[0]->age); /* we can't write student->p->name */
return 0;
}
The problem is in the insert method at the line of code you flagged in the question
sample->p[sample->id]->name = _name;
Nowhere in your program do you allocate memory for the p array inside of the person struct. Hence this value will always be NULL. Attempting to assign to this value will rightfully lead to a crash of your program.
To fix this you need to ensure the p array is large enough to accommodate the index provided by the expression sample->id. Best way to accomplish this is to use the realloc function and add a field to person to store the size of the p array
Here's a quick sample. Note: Error checking and 0 initialization of memory omitted for bevity.
struct person{
struct element** p;
size_t length;
int id;
};
void insert(struct person* sample, char* _name, int _age)
{
if (sample->id >= sample->length) {
sample->p = realloc(sample->p, sizeof(element*) * sample->id);
}
...
}
It does seem odd though that the name and age are always indexed via the sample->id field. This indicates that it's always placed in the same location in which case an array is not needed. Can you elaborate on how this is supposed to function?
In your init() function you set sample->p = NULL. In your insert() function you try to dereference the ->p member sample->p[sample->id]->name . Since you've not pointed ->p to any storage, you can't dereference it.
Starting program: /home/nathan/c/seg
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400597 in insert (sample=0x601010, _name=0x400730 "kido", _age=8)
at seg.c:28
28 sample->p[sample->id]->name = _name; /* the program craches here according to the debugger , but why?? */
(gdb) backtrace
#0 0x0000000000400597 in insert (sample=0x601010, _name=0x400730 "kido",
_age=8) at seg.c:28
#1 0x0000000000400601 in main () at seg.c:38
(gdb) p sample->id
$1 = 0
(gdb) p sample->p
$2 = (struct element **) 0x0
sample->p is not being properly initialized. If you look in init, it is indeed initialized to NULL. sample->p[anything] therefore dereferences a null pointer, causing a segfault.
When you call your init() function, you allocate memory for a number of person structures, and set the 'p' pointer of the first structure to NULL.
Then you try to write the memory pointed by 'p'. Which is, of course, still NULL.
Given your comments, I don't think init() is doing what you want it to do. It's allocating space for a person structure array, rather than a person with a 'p' array. Also, why the double pointer?
Recheck your design :) I usually do it in a whiteboard, or pencil and paper, using boxes for my 'objects' and arrows for my pointers. It will clarify your ideas, and possibly show you mistakes before they ever reach the code.
struct person* init(int size)
{
struct person* sample = (struct person* )malloc(size*sizeof(struct person));
sample->p = NULL; // p is a pointer to a pointer which is initialized to NULL
// So, it cannot be dereferenced with out pointing to a valid
// memory location.
// sample -> p = (struct person**) malloc( sizeof(struct *person) );
// sample[p] = (struct(person*)) malloc( sizeof(struct person) );
// struct** -> struct* -> struct
sample->id = 0;
return sample;
}
And now, these two statements are valid -
sample->p[sample->id]->name = _name;
sample->p[sample->id]->age = _age;
I'm having problem with this small program:
UPDATED (As per some requests, I've included everything here so to make clear what I'm doing. Sorry for it being too long):
Student.h file:
typedef struct Student {
char *name;
int age;
char *major;
char *toString;
} *Student;
extern Student newStudent(char *name, int age, char *major);
Student.c file:
c
har *studentToString(Student s);
static void error(char *s) {
fprintf(stderr,"%s:%d %s\n",__FILE__,__LINE__,s);
exit(1);
}
extern Student newStudent(char *name, int age, char *major) {
Student s;
if (!(s=(Student)malloc(sizeof(*s)))){
error("out of memory");
}
s->name=name;
s->age=age;
s->major=major;
s->toString = studentToString(s);
return s;
}
char *studentToString(Student s) {
const int size=3;
char age[size+1];
snprintf(age,size,"%d",s->age);
char *line=newString();
line=catString(line,"<");
line=catString(line,s->name);
line=catString(line," ");
line=catString(line,age);
line=catString(line," ");
line=catString(line,s->major);
line=catString(line,">");
return line;
}
Students.c file:
static void error(char *s) {
fprintf(stderr,"%s:%d %s\n",__FILE__,__LINE__,s);
exit(1);
}
static StudentList alloc(StudentList students, Student student) {
StudentList p;
if (!(p=(StudentList)malloc(sizeof(*p)))){
error("out of memory");}
p->student=student;
p->students=students;
return p;
}
extern Students newStudents() {
Students p;
if (!(p=(Students)malloc(sizeof(*p)))){
error("out of memory");
}
p->cursor=0;
p->students=0;
return p;
}
extern void addStudent(Students students, Student student) {
StudentList p=students->students;
if (!p) {
students->students=alloc(0,student);
return;
}
while (p->students)
p=p->students;
p->students=alloc(0,student);
}
extern void initStudent(Students students) {
students->cursor=students->students;
}
extern Student currStudent(Students students) {
StudentList cursor=students->cursor;
if (!cursor)
return 0;
return cursor->student;
}
extern void nextStudent(Students students) {
students->cursor=students->cursor->students;
}
And my main method:
int main() {
Students students=newStudents();
addStudent(students,newStudent("Julie",22,"CS"));
addStudent(students,newStudent("Trevor",32,"EE"));
for (initStudent(students);
currStudent(students);
nextStudent(students)) {
char *line=currStudent(students)->toString;
printf("%s\n",line);
free(currStudent(students));
free(line);
}
free(students->students);
free(students);
return 0;
}
I'm using valgrind to check memory leaks, and it is popping following error:
8 bytes in 1 blocks are definitely lost in loss record 1 of 1
==9520== at 0x40054E5: malloc (vg_replace_malloc.c:149)
==9520== by 0x8048908: alloc (Students.c:13)
==9520== by 0x80489EB: addStudent (Students.c:42)
==9520== by 0x804882E: main (StudentList.c:10)
I understand that I need to free the memory allocated for p in alloc function, but where should I call free(p)? Or is there something else I'm doing wrong? Please help!
The question is what do you do when you are finished with a Student or a StudentList and don't need it any more. That's the point where you should call free() for all the allocated things in that structure.
Probably you would want a freeStudents function that walks through a list of students and frees all the Students and all the StudentList items in it. Then you call that function whenever you want to get rid of a list of students.
Sorry, this is tangential, but you could really do a lot to make your code more readable.
You make a struct and then redefine its type to be a pointer to it. Yikes, that's just asking for trouble when it comes to maintainability. It's usually a bad idea to hide the fact that pointers are pointers, because when people see something like this:
Students newStudents()
{
Students p;
// ...
return p;
}
convention forces us to assume that you're returning a struct that was allocated on the stack, which would be obviously incorrect. (Edit: Not necessarily "obviously incorrect", but a wasteful copy.)
Things get even hairier when you add your malloc...
Students p;
if (!(p=(Students)malloc(sizeof(*p))))
{
error("out of memory");
}
For one thing, as mentioned, people assume that with no *, Students is a full structure on the stack. This will make anyone that sees "sizeof(*p)" do a double take. It's not obvious what you're doing.
And while squishing assignments and comparisons into one if statement is perfectly valid C and C++, it's usually not the most readable solution. Much improved:
Students* newStudents ()
{
Students* p = (Students*) malloc (sizeof (Students));
if (p == NULL)
{
// ...
}
// ...
return p;
}
And people enjoy pointing out that casting the return value of malloc isn't necessary in C, but it is in C++.
As for your leak, well... valgrind didn't report your catString usage, but it's still pretty sketchy since you're hiding the memory usage. Using snprintf is a better, more idiomatic way to create the string you want.
The leak valgrind is reporting: it looks like you're just freeing the first "students" node in your list. You need to traverse it and free them all, probably like this:
Students p = students;
while (p)
{
Students next = p->students;
free (p);
p = next;
}
I think you have a problem in alloc.
If you want a pointer it should be
StudentList *p;
p = (StudentList*)malloc(sizeof(StudentList));
I don't ever use sizeof with a variable if I am using malloc(). You should be using malloc(n * sizeof(StudentList)). With that said...
You've got some major concerns. First of all, you don't tell us what Students and StudentList are specifically defined to be. You pass 0 in some cases when I think you meant NULL -- never use 0 when you mean NULL. And if malloc() fails -- meaning, it returned NULL--then you don't call free() on the result. Never, ever free NULL.
You should only free a block of memory that was (a) successfully allocated, and (b) when you don't need it anymore. That doesn't seem to enter into your code here.
There are other issues as well (you assume students in addStudent is non-NULL when you initialize p), but they don't quite address your question concerning the usage of free().
What is this doing:
if (!(p=(StudentList)malloc(sizeof(*p)))){
free(p);
So, if p can't be allocated, free it?
I am assuming that StudentList is typedefined to be some type of pointer to Student. This being the case, this line in your alloc function is a problem.
p=(StudentList)malloc(sizeof(*p))
You are attempting to dereference the pointer before it has been assigned and that is not good.
You should free the memory when you no longer need to use the objects you've allocated.
What are StudentList and Student? It looks to me like your data structure is constructed improperly. Why is your StudentList storing a pointer to another StudentList? You should probably create a StudentList using malloc and return the pointer to that using your newStudents function, and rather than returning a new StudentList struct with a copy of the old one in addStudent, simply modify the structure you created originally.
So it would go something like this:
StudentList *newStudentList() {
//malloc a new StudentList and return the pointer
}
void freeStudentList(StudentList *list) {
//free the list pointer and all its child resources (i.e. the students in the list)
}
Student *newStudent(const char *name, etc) {
//malloc a new Student and return the pointer
}
void addStudentToList(StudentList *list, Student *student) {
//modify the StudentList which has been passed in by adding the student to it.
}
You could consolidate newStudent into addStudent if you don't plan on using them separately, and you may need a freeStudent and removeStudentFromList function if you plan on doing those things separately from freeStudentList as well. You should look at Google for examples of dynamic data structures in C (here is the first result on Google, but there are many others).
You really need to define what your types are. Could you edit your post to include the definitions of Student, StudentList and Students?
Also,
StudentList p;
p = (StudentList) malloc(sizeof(*p);
Unless StudentList is a typedef for a pointer, I'm not sure how that's compiling.
We also have the line:
StudentList p=students->students
With p being defined as a Students. Then Students must be a typedef for a pointer as well.
Also, what I think is your issue in the end, is that when you try to insert a student in the linked list, you end up losing any existing list. What would be interesting for you to try would be to insert 3 students into the list, and then attempt to print the list.