Allocating array on heap in C - c

I'm allocating an array of of "Todo" structs on the heap like so:
struct Todo *todos = malloc(n * sizeof(*todos));
My understanding is that I have now allocated memory for all of my n Todo structs. So if I want to save some values I can just do for example:
todos[i].id = 1;
The problem now is that if I try to free that memory using free(&todos[i]); I get an error telling me that I haven't allocated that pointer.
My question is now, do I just need to free the todos array and not every element on its own?

You have allocated one single block of memory for all your Todo structures. You can not free a single element. Just like you should not free elements of a non-heap allocated array.
Each call to malloc (or calloc) should be matched by a single call to free.

A little bit of background to Some programmer dude's answer
C11 standard, 7.22.3.3 "The free function", paragraph 2:
The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined.
[emphasis by me]
Background (second level...) is that typically, you did not only receive the memory starting at the pointer, but additionally there is some kind of (machine/OS specific) control block right before the pointer's address that is needed to free the memory again.
You might try to peek at this control block by reading some bytes right before the pointer (just out of curiosity), but be aware that this actually is undefined behaviour as well (so don't ever do this in production code!) and might lead to your programme crashing.

As a reference, always that you do:
WhateverTypeInTheWorld *var1 = malloc(whateveryouwanttocompletearray);
then, you have to do
free(var1); /* use the same value you received from malloc() */
to return the memory back... as you did only one malloc(), you can do only one free() and pass to it the same pointer you got from malloc().
When you write:
free(&todos[i].i);
you are passing free the i-esim element field i's address, and not the pointer you received from malloc(). Probably you understood that you can free part of the memory you received... but it doesn't work that way... you get the memory in chunks, and you have to return it in those same chunks you received from malloc.

Related

Calling free on a pointer to an element of an array declared dynamically

When I run the following code:
int main(int* argc, char** argv) {
int* array = malloc(5 * sizeof(int));
free(array + 3);
}
I get the error pointer being freed was not allocated. My intuition is that instead of trying to free the fourth element of array, free tried to free the thing living 3*sizeof(int) bytes after its last element. Is this correct? If so, then why does this happen? And is the behaviour resulting from the execution of this programme always predictable, or is it undefined of implementation-specific?
free expects you to use the very same address returned from malloc or otherwise anything might happen. The malloc call allocates a whole segment per call, in this case 5 int large. It doesn't make sense to free up parts of this segment, that's not how the heap works.
Heaps first allocate a segment header which is internal information that contains size etc. Then after that header, all the data. This header part isn't visible to the programmer and how it is implemented is OS and/or C library specific.
Indeed in your case you pass an address which sits 3*sizeof(int) bytes into the data part of the segment, which isn't a valid address since free needs the initial address used by malloc in order to know where the internal header of that segment starts. When you pass the wrong address to it, it might grab some other part of random data and treat that as the header. The behavior is undefined.
(You can however pass a null pointer to free() and that's guaranteed to be a no-op.)
From specification of free():
Synopsis
#include <stdlib.h>
void free(void*ptr);
Description
The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined.
Thus, what you're trying to do is undefined behavior
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2310.pdf
malloc allocates a block of memory.
You can only de-allocate (free) this block. You cannot free individual elements or a part of the block.
You can re-allocate (realloc) this block to make it larger or smaller.

Calloc(), Structs & C

So I'm new to C and creating some simple programs to help me get a hang of things.
Let's say I have a struct as follows:
typedef struct {
char* field;
} something;
And I dynamically allocate space for 10 of these as follows:
something* stuff = calloc(10, sizeof(something));
Let's say I then want to delete one of these somethings. Would it make sense to do:
free(&stuff[4]);
Or would that only make sense if I had made all of these pointers to somethings instead of a contiguous block of somethings?
If I did that and it worked, would:
stuff[4] = malloc(sizeof(something))
Then be all I need to re-add a "something" to that index?
Or, in general, do we usually deal with such structures as a block of memory that contains pointers to the structs, not the structs themselves?
Thanks.
The rule is very simple. You can and should free precisely that which you allocated. That is, you must only pass pointers to free() which you received as the return value of malloc/calloc/realloc etc.*, or a null pointer. Nothing else may be passed to free().
So, you can free tne entire array, or nothing at all.
(Note also that "freeing a single element from the middle" would be utterly pointless, because you would have no way of iterating over such a "holy" array sensibly.) If you want to deallocate some memory, allocate a new range, copy the desired elements over and free the original array.
*) Some quasi-standard functions may indirectly return dynamically allocated memory which you must fre; check the documentation. Some examples are strdup, GNU's scanf, and GCC's abi::__cxa_demangle.)
According to the man pages
The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs.
You can only free the whole block of data. So do not attempt to free anything else.

realloc() issues: deallocation of old block,new size bigger than old size,and passing static array base address

While reading about realloc() I have stumbled upon some doubts which I need to clarify rather than ignore.Your answers are very much sought.I have put them in a numbered list for clarity.Please don't mind the length of this question.
1) While using realloc(),if the memory block with its contents are moved to a new location,does the orignal address gets deallocated as if we called free() on it?I've read the following from cplusplusreference about realloc,but though they come close to suggesting that the original memory block do get deallocated in such a case,yet I need your confirmation.
->C90 (C++98)C99/C11 (C++11)
Otherwise, if size is zero, the memory previously allocated at ptr is deallocated as if a call to free was made, and a null pointer is returned.
->If the function fails to allocate the requested block of memory, a null pointer is returned, and the memory block pointed to by argument ptr is not deallocated (it is still
valid, and with its contents unchanged).
2) Here's another line that raise questions: "If the new size is larger, the value of the newly allocated portion is indeterminate.".Well,here is what I want to know
i) Is it allowed to write into that newly allocated portion?
ii) Is the newly allocated portion filled using garbage values?
3) And finally,What if pass an array object to realloc()?I ask because,though type will still be char*,it is mentioned in the source site that, the argument should be "Pointer to a memory block previously allocated with malloc, calloc or realloc.Will it be UB here too,as I read in free()'s description that for free() "If ptr does not point to a block of memory allocated with the above functions, it causes undefined behavior."
1) While using realloc(),if the memory block with its contents are moved to a new location,does the orignal address gets deallocated as if we called free() on it?
Yes, if realloc() returns a pointer to a different location, the old location is freed.
It is not freed if realloc fails to obtain a large enough block of memory and returns NULL.
2) Here's another line that raise questions: "If the new size is larger, the value of the newly allocated portion is indeterminate.".Well,here is what I want to know
i) Is it allowed to write into that newly allocated portion?
Yes, sure. That's the entire point of reallocating a larger block of memory.
ii) Is the newly allocated portion filled using garbage values?
Filled with garbage, not filled at all - the contents of the memory block are indeterminate, except for the part that was copied from the old block. You should not care what bits there are, put your own stuff there before reading from it.
3) And finally,What if pass an array object to realloc()? I ask because,though type will still be char*,it is mentioned in the source site that, the argument should be "Pointer to a memory block previously allocated with malloc, calloc or realloc. Will it be UB here too,as I read in free()'s description that for free()
Yes, if you pass an argument (except NULL) to realloc that was not obtained from a previous call to malloc, calloc or realloc (without having been freed since), the behaviour is undefined.
The pointers that may legitimately be passed to realloc are exactly the same that may be passed to free.

How to realloc() in the middle of an array?

I have an array of pointers
char *wordlist[9];
and then I malloc() a block of memory on every of this pointers
for(int i=0; i<9; i++)
wordList[i] = (char*)malloc(someLength);
Lets suppose that every time the someLength is different.
And the problem is now, that I want to realloc() ie. 4th elemet of wordList to a larger size than it is now.
wordList[3] = (char*) realloc(&wordList[3], someBiggerSize);
Since malloc allocates a consistent block of memory, is that operation even possible without colliding with wordList[4]?
There's nothing to worry about this in principle. You just have an array of pointers and each element of the array points to a distinct memory block. Each element of the array, each pointer, can be therefore be reallocated independent of the other elements.
Now, I say in principle because your code does have an error. You should pass wordList[3] rather than &wordList[3] to the realloc.
Just remove the & . wordList[3] = (char*) realloc(wordList[3], someBiggerSize);
wordList[3] is a pointer, and realloc expected to get a pointer that allocated by malloc. not pointer to it.
About your last question: every time you call malloc, it return a consistent block of memory. there is not guarantee that memory, allocated by two calls for malloc, will be consistent. In other words, wordList[3] and wordList[4] are not must be consistent, and you can do whatever you want two one of them (as long as you care about the buffers size) without thinking about the other.
Why should it be colliding? You have declared an array of pointers, each of which points to memory that is allocated elsewhere. When you reallocate you are just changing the size/position of this memory, the pointer returned by realloc is as big as it was.
By the way, you shouldn't be using realloc that way, since, if it fails, you'd be leaking memory; see e.g. here.
---edit---
And, as #asaelr noted, you should remove that &, just reallocing the block pointed by wordList[3], not the memory of wordList.
You have a misunderstanding about what realloc does. It will return a whole new block of memory (if the new size is larger than the old size) instead of increasing the size of the block that was passed into it.
malloc allocates a trunk of memory from heap and that trunk of memory can't be allocated for other malloc until you free them. In other words, malloc succeeds only if there are enough continuous free space in the heap. So this makes sure that the memory allocated would not collide with any others in your words.
Each of your pointers points to a separate and independent block of memory. Inside your array of pointers, each element is simply an address and overwriting one won't affect the others. So, what you are doing is fine and won't cause any problems with other elements of the array. As others mentioned, you should be passing wordList[3] and not &wordList[3]

Instead of just using free() and having the pointer pointing some new block, how to really empty the previously-pointed-at memory block?

I am trying to free dynamically allocated memory using free(), but I found that what it does is to have the argument pointer point to some new location, and leaving the previously-pointed-at location as it was, the memory is not cleared. And if I use malloc again, the pointer may point to this messy block, and it's already filled with garbage, which is really annoying..
I'm kinda new to C and I think delete[] in c++ doesn't have this problem. Any advise?
Thanks
By free the memory is just released from use. It is released from being allocated to you. it is not explicitly cleared. Some old contents might be present at those memory locations.
To avoid this, there are two solutions.
Solution 1:
You will need to do a memset after allocating memory using malloc.
Code Example:
unsigned int len = 20; // len is the length of boo
char* bar = 0;
bar= (char *)malloc(len);
memset(bar, 0, len);
Solution 2:
Or use, calloc() which initiliazes memory to 0 by default.
Code Example:
int *pData = 0;
int i = 10;
pData = (int*) calloc (i,sizeof(int));
I think delete[] in c++ doesn't have this problem.
No
It behaves exactly this same way. Unless you explicitly set the pointer to 0 the delete'd pointer will not be pointing to 0. So do always set the pointer to 0 after you delete it.
When should you use malloc over calloc or vice versa?
Since calloc sets the allocated memory to 0 this may take a little time, so you may probably want to use malloc() if that performance is an issue.(Ofcourse One most profile their usage to see if this really is a problem)
If initializing the memory is more important, use calloc() as it does that explicitly for you.
Also, some OS like Linux have an Lazy Allocation memory model wherein the returned memory address is a virtual address and the actual allocation only happens at run-time. The OS assumes that it will be able to provide this allocation at Run-Time.
The memory allocated by malloc is not backed by real memory until the program actually touches it.
While, since calloc initializes the memory to 0 you can be assured that the OS has already backed the allocation with actual RAM (or swap).
How about realloc?
Yes, similar behavior to malloc.
Excerpt From the documentation:
void * realloc ( void * ptr, size_t size );
Reallocate memory block
The size of the memory block pointed to by the ptr parameter is changed to the size bytes, expanding or reducing the amount of memory available in the block.
The function may move the memory block to a new location, in which case the new location is returned. The content of the memory block is preserved up to the lesser of the new and old sizes, even if the block is moved.If the new size is larger, the value of the newly allocated portion is indeterminate.
In case that ptr is NULL, the function behaves exactly as malloc, assigning a new block of size bytes and returning a pointer to the beginning of it.
In case that the size is 0, the memory previously allocated in ptr is deallocated as if a call to free was made, and a NULL pointer is returned.
You can use calloc( ) instead of malloc( ) to clear the allocated memory to zero.
Why is having newly allocated memory filled with garbage "really annoying"? If you allocate memory, presumably it's because you're going to use it for something -- which means you have to store some meaningful value into it before attempting to read it. In most cases, in well-written code, there's no reason to care what's in newly allocated memory.
If you happen to have a requirement for a newly allocated block of memory you can call memset after calling malloc, or you can use calloc instead of malloc. But consider carefully whether there's any real advantage in doing so. If you're actually going to use those all-bits-zero values (i.e., if all-bits-zero happens to be the "meaningful value" I mentioned above), go ahead and clear the block. (But keep in mind that the language doesn't guarantee that either a null pointer or a floating-point 0.0 is represented as all-bits-zero, though it is in most implementations they are.)
And free() doesn't "have the argument pointer point to some new location". free(ptr) causes the memory pointed to by ptr to be made available for future allocation. It doesn't change the contents of the pointer object ptr itself (though the address stored in ptr does become invalid).

Resources