I have a program in which I need to work with pointer arrays. My problem is that I do not know how to delete element i from pointer p (p[i]). I will detail the problem below.
I have the structure:
struct CuttingLine
{
NxU32 linePoints[150];
NxU32 lineLength;
NxVec3 normal;
};
Then I declare the pointer:
CuttingLine* cuttingLines;
I initialize the pointer like this:
cuttingLines = (CuttingLine*)malloc(sizeof(CuttingLine) * 10);
And then I add some elements to it (please notice that this is just for demonstration purposes, in my program, line is created and given values):
for(int i=0;i<3;i++)
cuttingLines[i] = line;
Then I want to go through the pointer again, and delete the three elements, but not free the pointer (I understand that you can delete the pointer by calling free(cuttingLines)).
How can I do that? I just want to delete the elements inside it, but not deallocate the memory allocated in the beginning.
Because cuttingLines is a pointer to CuttingLine, your loop is actually performing a structure copy of line into each of the three positions. There is no need to delete these deep copies. You just have to not use the information anymore when you are done with it, and note that the cuttingLines variable contains unused data. You can then reuse the cuttingLines variable later (filling it with new lines) at your convenience.
To me it looks like you want to have an array of pointers, and dynamically allocate the elements of the array. In this case you'd want to set the value of the pointer to NULL, which means the pointer doesn't point to anything. Like this:
cuttingLines[i] = NULL;
This means "I have a pointer in my array but it doesn't point to anything".
However if you don't free the memory (by calling free(cuttingLines[i])) you will have a memory leak, so remember to free the memory later in your program. For this you will need to have another pointer somewhere that points to whatever each call to malloc returned.
Just to be pedantic: you can't free a pointer (except in the sense of allocating e.g. sizeof(CuttingLine*) using malloc); you can free memory, so calling free(ptr) frees the memory pointed to by the pointer. Also, you treat cuttingLines like an array of pointers, i.e. pointer of pointers, so its type should be CuttingLine** and you'd declare and allocate it by:
CuttlingLine** cuttingLines;
cuttingLines = (CuttingLine**)malloc(sizeof(CuttingLine*) * 10);
Also, you shouldn't cast the return value of malloc (see here) unless you're writing C++ in which case you shouldn't need to use pointers to pointers in the first place.
If on the other hand you want to have an array of CuttingLines then you're on the right track in the sense that you allocate cuttingLines correctly, and you don't need to free the memory used by individual CuttingLine. However in this case you don't know which elements in the array are valid and which aren't unless you either track the indices in the code or in the elements themselves by e.g. setting lineLength to 0 and checking its value.
Related
I want to add something to the end of the array passed to the function.
Which is better, declaring a new larger array or using alloc ()?
1.
void array_append(int *block, size_t size)
{
int new_block[size + 2];
memcpy(new_block, block, size);
(...append)
}
void array_append(int *block, size_t size)
{
int *new_block = calloc(1, sizeof(int) + 2);
memcpy(new_block, block, size);
(...append)
free(new_block);
}
I am not returning the newly created array anywhere.
I only use new_block inside functions.
Does not modify the original array in the function.
Declaring new_block as static is omitted.
I know how calloc() / malloc() works, I know that this operation has to be validated.
new_block is only meant to live in a function.
I just wonder which solution is better and why ...
regards
You should dynamically allocate an array instead of using a variable length array because in general in the last case the code can be unsafe due to a comparatively big size of the array that can lead to the stack overflow.
I want to add something to the end of the array
But you cannot really. Unless with realloc(). This is how your ...append trick can be done, whatever it means.
If you need a temporary array to work with and then copy into your array (but not at the end!), then all methods for allocation are allowed - it really depends on how often and with which sizes.
If it is called very often with limited sizes, it could be a static array.
There is no easy solution for growing arrays (or for memory management in general). At the extreme you allocate every element individually and link them together: a linked list.
--> avoid reaching the end of your arrays. Define a higher maximum or then implement a linked list.
In certain situations realloc() also makes sense (big changes in size, but not often). Problem is sometimes the whole array has to be memcopied to keep the larger array contiguous: "realloc", not "append". So it is "expensive".
I am not returning the newly created array anywhere.
That is part of the problem. You actually seem to be doing half of what realloc() does: allocate the new space, memcpy() the old contents...and then free the old and return the new array(-pointer) to the caller.
First version can not return the array pointer, because end of function is also end of local auto arrays, VLA or not.
If the append can be done to the existing array (which it can if the caller expects this and the memory of the array has room), you can merely append to the existing array.
Otherwise, you need a new array. In this case, the array must be returned to the caller. You can do this by returning a pointer to its first element or by having the caller pass a pointer to a pointer, and you modify the pointed-to pointer to point to the first element of the new array.
When you provide a new array, you must allocate memory for it with malloc or a similar routine. You should not use an array defined inside your function without static, as the memory for such an array is reserved only until execution of the function ends. When your function returns to the caller, that memory is released for other uses. (Generally, you also should not use an array declared with static, but for reasons involving good design, reducing bugs, and multiple serial or parallel calls to the function.)
I have a function that will add a new position to an array by reallocating new memory every time it is called.
The problem is that, for each call I need it to add one position to the array, starting from 1 at first call, but I understand that I have to mallocate before reallocating.
So my question is, can I initially do something like p = malloc(0) and then reallocate for example using p = (int *)realloc(p,sizeof(int)) inside my function? p is declared as int *p.
Maybe with a different syntax?
Of course I could make a condition in my function that would mallocate if memory hasn't been allocated before and reallocate if it has, but I am looking for a better way.
And the second problem I have is... Once reallocated more positions, I want to know the size of the array.
I know that if, for example, I declare an array a[10], the number of elements would be defined by sizeof(a)/sizeof(a[0]), but for some reason that doesn't work with arrays declared as pointers and then reallocated.
Any advice?
You could initialize your pointer to NULL, so that the first time you call realloc(yourPointer, yourSize), it will return the same value as malloc(yourSize).
For your second problem, you could use a struct that contains your pointer and a count member.
struct MyIntVector {
int * ptr;
size_t count;
}
Then you probably will want to define wrapper functions for malloc, realloc, and free (where you could reset ptr to NULL), that takes your struct as one of the parameters, and updates the struct as needed.
If you want to optimize this for pushing 1 element at a time, you could add a allocatedCount member, and only realloc if count == allocatedCount, with a new allocatedCount equals (for example) twice the old allocatedCount.
You should implement this in a MyIntVector_Push(MyIntVector *, int ) function.
You will then have a simplified c version of c++ std::vector<int> (but without automatic deallocation when the object goes out of scope).
As ThreeStarProgrammer57 said just use realloc.
realloc(NULL, nr_of_bytes) is equivalent to malloc(nr_of_bytes)
so
p = realloc(p, your_new_size)
will work just fine the first time if p is initialized to NULL. But be sure to pass the number of bytes you need after resizing, not the additional space that you want, as you have written your question.
As regarding the size, you have to keep track of it. That's the way C was designed.
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.
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]
I have a question regarding free() in C.
Suppose I have a pointer to some struct (say node *ptr).. after freeing it can i Initialize it to NULL and make it point to some new location using malloc() or realloc()?
For Example:
node *ptr=NULL;
ptr=realloc(ptr,sizeof(node)); //works exactly like malloc
/* Do some operations on ptr */
free(ptr);
ptr=NULL;
ptr=realloc(ptr,sizeof(node));
Is that valid, or will it create a problem.
The reason I used realloc in place of malloc is because all my realloc() calls are in a loop (so instead of sizeof(node) in the second argument it is actually n*sizeof(node) where n keeps on incrementing... and the last location in this resultant array is written with new data) where the memory pointed to by ptr keeps on increasing until the loop ends, at which point I do not require the data in the memory pointed to by ptr, so I think it best to free it. Now, all this is nested in one more bigger(outer) loop.
Thanks a lot for your help
It is ok - you are not really reusing the pointer but just the variable holding the pointer.
ptr doesn't remember that it was once assigned a value, and re-using it again if it was assigned NULL is no different from using it the first time around.
And since realloc() acts like malloc() when it's passed a NULL pointer, it should work just fine.
You should not thinking about it as "freeing the pointer", but freeing whatever the pointer points to. It's perfectly normal that a pointer points first to one object (which may then be freed), and then to another object.