So I don't really know how to put the title this time. First of all I'd like to say that I've seen several comments on this page about warning if the question is related to "homework". Mine is, but it's also completed and I just want to further understand what is going on with the code.
I have also read posts and books for some time, but I think I am still missing things.
I have 2 lines of code I don't quite understand in the code I worked with. The work is about getting whatever file is used as argument (if it's 0 files, it read from stdin), and print it on the standard output backwards. All of this, talking about C as I tried to put in the tag.
First problem is this:
array = realloc (array, 0);
Where array is defined as
char **array;
And the problem is that free doesn't work, it does not free the space used (maybe I used it wrong? In other place I have known how to use it, but not this time). With the testing I have done and what I have read, I believe that realloc is doing the same, but I'm no 100%.
Second one is:
char* alloc = malloc (strlen ((char*)string)+1);
Where alloc is used to copy the exact length of the line I am going to put into an array, so I can, after that, just print the text backwards.
And the question is why I have to use that +1. I mean if I don't use for some reason it doesn't work, I tried with different numbers and it works everytime, but if I don't do that +1 it does not work correctly.
I know probably the question is too vague and bad written to really be answered but again, I'm not sure about that and I did my best to explain myself (english no mother tongue as it's probably obvious).
The behavior of
realloc
when the size is 0 is different in C11 (the current version). The standard says (7.20.3.1 for C11, 7.22.3.1 for C1x)So, use
free
and don't rely onrealloc
.When dealing with strings via
char*
always remember to include one extra character for the null terminator\0
. This is the usual way to show where the string ends (the other being an explicit string length).When using
malloc
andfree
remember that they must be matched exactly. You need tofree
the exact pointer (value) returned bymalloc
orrealloc
.The problem lies in char **array !! How is that built? Sounds like it's not a continuous block of mem and it was built like :
If this is the case then each array index has it's individual pointer to random memory blocks! In that case before you cleanup the array, you need to free each individual index!!!
Also with realloc, a NULL can also mean failure, therefore you're dangling the old pointer!. never do
do
If you hope to maintain compatibility,
realloc(p,0)
is never equivalent tofree(p)
, and zero allocations without subsequent frees are memory leaks plain and simple, even on Linux.Regarding the second question:
In C, the string should be terminated by a null character '\0'. When you use strlen, this character is not counted but you need to allocate enough space for it (that's the +1).
If you try to print a string that does not contain a null character, a few "random" characters might be printed, but it can also crash. If you use strcpy, you'll do a buffer overflow.
First question:
realloc(array, 0)
is not equivalent tofree(array)
.The standard (C99, §7.20.3.4 ¶1) says:
and gives no "special case" for asize==0
; so, you are getting a pointer to an object of size zero - but which potentially is still an object, and still has to be freed.Interestingly, I think therealloc
may simply fail in such a circumstance, returningNULL
; in this case, in your code the memory is leaked, since, whenrealloc
fails, it does not free the original memory block you passed to it (which is the reason why you never doarray = realloc(array, size)
but you always use an intermediate variable to check forNULL
in order to avoid memory leaks).Actually, the standard does specify the
size==0
implementation-defined behavior for all the memory allocation functions, not just formalloc
as I remembered; so, the behavior is implementation defined, as desribed below:More intuitively,
realloc
is "conceptually equivalent" to tomalloc
+memcpy
+free
on the other pointer, andmalloc
-ing a 0-byte chunk of memory returns eitherNULL
either a unique pointer, not to be used for storing anything (you asked for 0 bytes), but still to befree
ed. So, no, don't userealloc
like that, it may work on some implementations (namely, Linux) but it's certainly not guaranteed.Also, it's not clear how you deduced that
free
doesn't work. I can think of two ways you may have been convinced of this:array
and of the data it points to is unchanged;top
/whatever doesn't decrease.For the first case, that's normal; when you free a pointer, it doesn't magically get wiped - your pointer still points to where it pointed, but that memory is no longer yours - it's now back to the C runtime, which will probably re-give it away in a future
malloc
. That's why that thing is called a "dangling pointer", and many people after afree
set it toNULL
to avoid writing again in a space of memory that has already been released.As for the second, it's common policy for allocators not to give back memory to the operating system immediately (unless we are talking about really big chunks); the idea is that probably the application will need such memory again soon, and keeping that memory for the current process can avoid continuous system calls to take/give memory from the OS. Since system utilities for monitoring the memory used normally can only see what the OS has given to the process, it's normal that they don't show any memory usage decrease.
By the way, remember that, if you
char ** array
contains pointers to stuff allocated withmalloc
, you have tofree
them first, otherwise you're leaking memory.Second question:
C strings are null-terminated, i.e. the last character of the string is always a
\0
to mark the string ends, whilestrlen
gives you the length of the string excluding the null terminator. So, if you don't add that+1
you are allocating onechar
less than the memory needed to actually store your string.Addendum
As the manpage says,
You probably have some other bug in your code, but without seeing it it's impossible to tell what/where it goes wrong.
Realloc with a size of zero is equivalent to free() on some C implementations, but not all.
Think about what
char **array
means and how it is allocated in your application. Often pointers-to-pointers are used as two-dimensional arrays, expressed as an array of arrays. Most applications allocate these with multiple calls to malloc().array
is simply an array ofchar *
, where each element of that array is an array ofchar
. Simply calling free() on the array ofchar *
will free the array ofchar *
, but not each of the arrays ofchar
.You need to call free() multiple times as described here.
C strings are null terminated, which means that the program keeps track of where the string ends by putting a nul character at the end of the string. That means that a C string of length N needs space for N characters, plus one nul character. The overall length of the memory space is then N+1.