Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
If I dynamically define an array inside a loop, and give it different values each time, and I also don't need this array after the loop ends, do I need to free the array's space each time?
When I dynamically allocate memory for an array of strings, for example, do I also need to allocate memory for each of its elements (strings)?
Let's say i have these 2 dynamically allocated arrays:
char *** arr = { {....}, {....},{.....},.... };
char ** newArr = { ......... };
can I do this? (x is an index of arr):
arr[x] = newArr;
and if yes, what will happen to the memory of the previous element I just switched?
Your title uses the term dynamic memory allocation, whereas some if your detail questions use different terminology and / or use syntax that suggests automatic or static allocation instead. Dynamic allocation involves directly or indirectly using an allocation function such as malloc(), calloc(), or realloc(), and that is primarily what I will be talking about.
If I dynamically define an array inside a loop, and give it different values each time, and I also don't need this array after the
loop ends, do I need to free the array's space each time?
Yes.
Each dynamic allocation reserves space that is not already allocated at the time of the call, and that space remains allocated until you free it via free() or the program terminates, whichever comes first. Until it frees that memory, then, the program has less available for future allocations, and if it keeps on allocating then it uses ever more memory. Eventually, it will run out, and before then it is likely to cause performance problems or worse not only for itself, but for other processes, too.
The general rule is that every allocation must be paired with a corresponding free, though you can fudge that a bit for allocations that need to be retained until the program terminates anyway.
When I dynamically allocate memory for an array of strings, for example, do I also need to allocate memory for each of its elements
(strings)?
Maybe.
The question is ambiguous. I suspect that by "strings" you mean pointers to char, but it is essential to understand that strings are null-terminated sequences of chars in memory -- thus, not pointers. One accesses strings via pointers to them, but you must not confuse the pointer with the string to which it points.
If you allocate space in which to store pointers to strings, whether dynamically or otherwise, that yields space for the pointers, not for anything for them to point to. You need to provide separately for the strings themselves. That could mean allocating additional space for those dynamically, too, but it could also mean pointing to strings that were already allocated by some other means.
Let's say i have [...]
char *** arr = { {....}, {....},{.....},.... };
char ** newArr = { ......... };
can I do this? (x is an index of arr):
arr[x] = newArr;
and if yes, what will happen to the memory of the previous element I just switched?
Yes and nothing.
Regardless of how arr and newArr were allocated, yes, you can perform that assignment as long as x is a valid index into arr. It replaces the pointer value stored in arr[x] with the pointer value that at that point is stored in newArr, leaving both pointers pointing to the same thing. This has no effect on the data to which either the original value of arr[x] or its new value points. In particular, it does not cause any memory to be freed, so if the original value of arr[x] pointed to dynamically allocated memory, and you have no other pointer to the same dynamically-allocated block, then that block can no longer be freed. This is called a "memory leak".
Related
Since arrays are just contiguous data of the same type, and you don't need to explicitly put [] somewhere (e.g. you can int *p1 = malloc(sizeof(int) * 4);, how is it that when you realloc(p1, ...), it knows to move (if it has to move) exactly 4 ints worth of space, even if potentially there are other ints in memory?
To clarify the question: If you allocate an array in this way, and also just a single, seperate int - does that mean that these 4+1 total ints are never contiguous in memory, or is this "it's an array" information in the memory block somehow (e.g. they have some sort of delimiter?), or does the compiler infer and remember that from the malloc parameter? Or something else?
Basically, how does it ensure it moves only and exactly those 4, even when there are other blocks of memory of the same size that might be also contiguous?
realloc is defined only when passed a pointer to memory allocated by a member of the malloc family of routines (or a null pointer). These routines keep records of the memory they have allocated. When you call realloc, it uses these records to know how long the allocated block is.
Often, the primary record for a block of memory is put into the bytes just before that block, so all realloc has to do is take the pointer you give it, subtract a known number of bytes from it, and look at the data at that new address, where it will find information about the size of the allocated block. However, other methods are possible too.
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.)
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Consider the following C code:
#include <stdio.h>
#include <stdlib.h>
int main() {
int arrSize;
scanf("%d", &arrSize);
printf("%d\n",arrSize);
int *dynArr = (int *)malloc(sizeof(int)*arrSize);
int arr1[arrSize];
return 0;
}
In the code above, arrSize is size of an array taken from the user input. I want to know if the following observations are correct:
dynArr is a dynamic array which is allocated in the memory during runtime on heap. Size of dynArr can be modified using realloc function.
arr1 is also allocated in the memory during runtime but is not dynamic (i.e. their size cannot be modified) and it is allocated on Stack.
i) dynArr is a dynamic array which is allocated memory during runtime
from heap section. Size of dynArr can be modified using realloc
function.
Yes, if realloc can find a big enough block. Although technically, the pointer isn't an array. It points to the first element of an array.
ii). arr1 is also allocated memory during runtime but is not dynamic
i.e. their size cannot be modified. Memory is allocated from the stack
or data section. (Not sure from which section heap or stack/data the
memory is allocated and why).
The size of the array is dynamic, it's lifetime isn't. It will be reclaimed automatically the moment main returns. Variable length arrays are usually allocated on the call stack. And yes, you cannot change it's size once you declared it.
If you are now wondering when to use one over the other there are a few points to consider:
The memory reserved for the call stack is limited (more so than the heap by far). It's easy to overflow if you declare a huge VLA on it.
The memory returned from malloc and its kin can outlive the stack frame where it was allocated.
Generally, allocating VLA's can be faster than allocating memory with malloc. One is a simple progression of the stack frame pointer, while the other involves the heap's memory allocator and its logic.
dynArr is a dynamic array which is allocated memory during runtime from heap section. Size of dynArr can be modified using realloc function.
No, dynArr is a pointer, which is initialized using the returned pointer by malloc(). Remembers, arrays are not pointers and vice-versa. IN some cases, an array name decays to a pointer to the first element of the array, but that does not make both the same.
size of dynArr is the size of the pointer, not the size of the memory location it points to. Using the correct words, in can be represented as, the size of memory it points to can be changed using realloc().
arr1 is also allocated memory during runtime but is not dynamic i.e. their size cannot be modified. Memory is allocated from the stack or data section. (Not sure from which section heap or stack/data the memory is allocated and why).
This is called variable length array. Other points are correct.
Quoting C11, chapter ยง6.7.6.2
If the size is an expression that is not an integer constant expression: if it occurs in a
declaration at function prototype scope, it is treated as if it were replaced by *; otherwise,
each time it is evaluated it shall have a value greater than zero. The size of each instance
of a variable length array type does not change during its lifetime.
It allocates memory from free memory store. Now there is nothing called heap and stack in memory in case of C..it is something logically we consider in case of C.(In implementation of C)]
Only thing we are bothered about whether we need something which you want to be alive even if the scope of where it is declared ends or not.
For heap it is the case .. for stack it is not.
In your case
int arr1[arrSize]; is allocated on the same frame on which this main function local variables are stored.
Dynamic allocation
You control the exact size and the lifetime of these memory
locations. If you don't free it, you'll run into memory leaks, which
may cause your application to crash, since it, at some point cannot
allocation more memory. (dynArr)
Actually...
Heap
The heap is a region of your computer's memory that is not managed
automatically for you, and is not as tightly managed by the CPU. It is
a more free-floating region of memory (and is larger). To allocate
memory on the heap, you must use malloc() or calloc(), which are
built-in C functions.
Once you have allocated memory on the heap, you
are responsible for using free() to deallocate that memory once you
don't need it any more. If you fail to do this, your program will have
what is known as a memory leak. That is, memory on the heap will still
be set aside (and won't be available to other processes).
Stack
It's a special region of your computer's memory that stores temporary
variables created by each function (including the main() function).
The stack is a "LIFO" (last in, first out) data structure, that is
managed and optimized by the CPU quite closely. Every time a function
declares a new variable, it is "pushed" onto the stack. Then every
time a function exits, all of the variables pushed onto the stack by
that function, are freed (that is to say, they are deleted). Once a
stack variable is freed, that region of memory becomes available for
other stack variables.
Resources
Link 1
Actually, the variable length array are not allowed in Google C++ Style Guide. It has a natural-looking syntax and it's efficient, however, because of they allocate a data-dependent amount of stack space, it can trigger serious and mysterious memory overwriting bugs:
Sometimes "It ran fine on my machine, but dies mysteriously in production".
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]
int numbers*;
numbers = malloc ( sizeof(int) * 10 );
I want to know how is this dynamic memory allocation, if I can store just 10 int items to the memory block ? I could just use the array and store elemets dynamically using index. Why is the above approach better ?
I am new to C, and this is my 2nd day and I may sound stupid, so please bear with me.
In this case you could replace 10 with a variable that is assigned at run time. That way you can decide how much memory space you need. But with arrays, you have to specify an integer constant during declaration. So you cannot decide whether the user would actually need as many locations as was declared, or even worse , it might not be enough.
With a dynamic allocation like this, you could assign a larger memory location and copy the contents of the first location to the new one to give the impression that the array has grown as needed.
This helps to ensure optimum memory utilization.
The main reason why malloc() is useful is not because the size of the array can be determined at runtime - modern versions of C allow that with normal arrays too. There are two reasons:
Objects allocated with malloc() have flexible lifetimes;
That is, you get runtime control over when to create the object, and when to destroy it. The array allocated with malloc() exists from the time of the malloc() call until the corresponding free() call; in contrast, declared arrays either exist until the function they're declared in exits, or until the program finishes.
malloc() reports failure, allowing the program to handle it in a graceful way.
On a failure to allocate the requested memory, malloc() can return NULL, which allows your program to detect and handle the condition. There is no such mechanism for declared arrays - on a failure to allocate sufficient space, either the program crashes at runtime, or fails to load altogether.
There is a difference with where the memory is allocated. Using the array syntax, the memory is allocated on the stack (assuming you are in a function), while malloc'ed arrays/bytes are allocated on the heap.
/* Allocates 4*1000 bytes on the stack (which might be a bit much depending on your system) */
int a[1000];
/* Allocates 4*1000 bytes on the heap */
int *b = malloc(1000 * sizeof(int))
Stack allocations are fast - and often preferred when:
"Small" amount of memory is required
Pointer to the array is not to be returned from the function
Heap allocations are slower, but has the advantages:
Available heap memory is (normally) >> than available stack memory
You can freely pass the pointer to the allocated bytes around, e.g. returning it from a function -- just remember to free it at some point.
A third option is to use statically initialized arrays if you have some common task, that always requires an array of some max size. Given you can spare the memory statically consumed by the array, you avoid the hit for heap memory allocation, gain the flexibility to pass the pointer around, and avoid having to keep track of ownership of the pointer to ensure the memory is freed.
Edit: If you are using C99 (default with the gnu c compiler i think?), you can do variable-length stack arrays like
int a = 4;
int b[a*a];
In the example you gave
int *numbers;
numbers = malloc ( sizeof(int) * 10 );
there are no explicit benefits. Though, imagine 10 is a value that changes at runtime (e.g. user input), and that you need to return this array from a function. E.g.
int *aFunction(size_t howMany, ...)
{
int *r = malloc(sizeof(int)*howMany);
// do something, fill the array...
return r;
}
The malloc takes room from the heap, while something like
int *aFunction(size_t howMany, ...)
{
int r[howMany];
// do something, fill the array...
// you can't return r unless you make it static, but this is in general
// not good
return somethingElse;
}
would consume the stack that is not so big as the whole heap available.
More complex example exists. E.g. if you have to build a binary tree that grows according to some computation done at runtime, you basically have no other choices but to use dynamic memory allocation.
Array size is defined at compilation time whereas dynamic allocation is done at run time.
Thus, in your case, you can use your pointer as an array : numbers[5] is valid.
If you don't know the size of your array when writing the program, using runtime allocation is not a choice. Otherwise, you're free to use an array, it might be simpler (less risk to forget to free memory for example)
Example:
to store a 3-D position, you might want to use an array as it's alwaays 3 coordinates
to create a sieve to calculate prime numbers, you might want to use a parameter to give the max value and thus use dynamic allocation to create the memory area
Array is used to allocate memory statically and in one go.
To allocate memory dynamically malloc is required.
e.g. int numbers[10];
This will allocate memory statically and it will be contiguous memory.
If you are not aware of the count of the numbers then use variable like count.
int count;
int *numbers;
scanf("%d", count);
numbers = malloc ( sizeof(int) * count );
This is not possible in case of arrays.
Dynamic does not refer to the access. Dynamic is the size of malloc. If you just use a constant number, e.g. like 10 in your example, it is nothing better than an array. The advantage is when you dont know in advance how big it must be, e.g. because the user can enter at runtime the size. Then you can allocate with a variable, e.g. like malloc(sizeof(int) * userEnteredNumber). This is not possible with array, as you have to know there at compile time the (maximum) size.