There is the following structure:

typedef struct _line_t { char *data; size_t length; size_t lineno; struct _line_t *next; struct _line_t *prev; } line_t; 

As you can guess, it is intended to organize a coherent list of strings (do not ask why I need such a crutch and why I cannot use C ++).

There is a function for creating such a line (it allocates memory for the structure and sets the fields. I will not give it here), as well as the function for deleting (freeing memory).

The last one looks like this:

 void lines_delete(line_t *begin) { if(!begin) return; line_t *cur = begin, *prev; while(cur) { prev = cur; cur = cur->next; if(prev->data) free(prev->data); free(prev); prev->lineno += 1; //Для теста } } 

The above code does not fall, but I have known C not so long ago and decided to check with the debugger:

 Breakpoint 1, lines_delete (begin=0x6032a0) at line.c:21 21 if(!begin) (gdb) n 24 line_t *cur = begin, *prev; (gdb) n 26 while(cur) { (gdb) n 27 prev = cur; (gdb) n 28 cur = cur->next; (gdb) n 30 if(prev->data) (gdb) n 31 free(prev->data); (gdb) n 33 free(prev); (gdb) n 34 prev->lineno += 1; (gdb) n 26 while(cur) { (gdb) 

Those. did you understand, yes? I release the prev , and then calmly turn to the already freed memory. After line 33, the debugger "says" that the memory is not released. It is noteworthy that prev-> data = 0x0, i.e. the data (char array) was freed, but the string (structure) itself was not. I'm confused.

UPD : In the function lines_data passed such a connected list of three nodes (ie, three structures) and accidentally noticed that not all prev-> data are released. See (continuation of output from gdb):

 26 while(cur) { (gdb) print prev->data $1 = 0x0 (gdb) n 27 prev = cur; (gdb) n 28 cur = cur->next; (gdb) n 30 if(prev->data) (gdb) n 31 free(prev->data); (gdb) n 33 free(prev); (gdb) n 34 prev->lineno += 1; (gdb) print prev->data $2 = 0x603290 "" (gdb) 

That is, the data of the first line is released (becomes 0x0), and the data of the second line is not released, but becomes empty (as the debugger says).

Also, gdb allows you to do this (see below), which means that the memory is not 100% freed. Continuing the output:

 (gdb) print prev->data $2 = 0x603290 "" (gdb) set prev->data = "Hello" (gdb) 

Now I'm completely confused, my code lives as it wants and does what it wants?

  • Let's start with the fact that this is: free(prev); prev->lineno += 1; free(prev); prev->lineno += 1; - first freeing the memory, and then accessing it - is strictly forbidden ... And yet - freeing the memory free(prev) does not make prev null pointer. - Harry
  • And yet, free perfectly responds to the null pointer. Additional verification is not required. - αλεχολυτ

1 answer 1

In fact, after the release of memory - UB - you can get anything. Usually the following happens: at the beginning of the memory block, a flag is set that the memory is free, after which it can be reused. Memory reset is not performed due to large overheads (in C, it is accepted that the memory is cleared by the one who asked for it to be allocated). Therefore, with a certain luck (or rather bad luck), you can even read the original value of the memory before deletion.

What happened to you - prev - pointer, its value does not change after calling free (). (signature free(void *) but not free(void**) ). Therefore, you must write prev = NULL yourself if the value of this pointer is important to you.

memory not released

Pointer values ​​are not relevant to freeing memory.

  • I did not know, now I will know. What about the correctness of such a release function? I'm not sure. - wvdroot
  • one
    after calling free will be logical to make NULL all the pointers that referred to it or its part. So the function looks quite right. - pavel
  • And, and more: Why then some prev-> data = 0x0, and some not? free does not change the value of the pointer. - wvdroot
  • there is no pointer, but you delete the prev yourself, for prev it is its field, it may retire, it may not. - pavel
  • and even if(prev->data) you can not check, inside free there is this check. - pavel