Memory management during function call - c

I was writing a code that involves handling a 2D array of dimensions [101]X[101] in C. However I am constrained in terms of memory being used at a given point of time.
void manipulate(int grid_recv[101][101])
{
//Something
}
void main()
{
int grid[101][101];
manipulate(grid);
}
So lets say I create an array grid[101][101] in my main() and then pass it for manipulation to another function. Now does the function manipulate() copy the entire matrix grid into grid_recv i.e by this sort of passing am I using twice the amount of memory ( i.e twice the size of grid)?

No. In C, arrays cannot be passed as parameters to functions.
What you actually do is creating a pointer pointing the array. So the extra memory you use it only the size of that pointer created.

Related

Overwriting an existing 2D Array in C

I'm currently writing a project in C, and I need to be able to fill a 2D array with information already stored in another 2D array. In a separate C file, I have this array:
int levelOne[][4] =
{{5,88,128,0},
{153,65,0,0},
{0,144,160,20}}; //First Array
int levelTwo[][4] =
{{5,88,128,0},
{153,65,0,0},
{0,144,160,20}}; //Second Array
And in my main file, I have this variable which I'd like to fill with the information from both of these arrays at different points in my code. (This isn't exactly what I'm doing, but it's the general gist):
#include "arrayFile.c"
void main()
{
int arrayContainer[][4] = levelOne;
while (true)
{
func(arrayContainer);
if(foo)
{
arrayContainer = levelTwo;//Switches to the other array if the conditional is met.
}
}
}
I know this method doesn't work - you can't overwrite items in arrays after they're instantiated. But is there any way to do something like this? I know I'll most likely need to use pointers to do this instead of completely overwriting the array, however there's not a lot of information on the internet about pointers with multidimensional arrays. In this situation, what's best practice?
Also, I don't know exactly how many arrays of 4 there will be, so I wouldn't be able to use a standard 3D array and just switch between indexes, unless there's a way to make a 3D jagged array that I don't know about.
Given the definitions you show, such as they are, all you need is memcpy(arrayContainer, levelTwo, sizeof LevelTwo);.
You should ensure that arrayContainer has sufficient memory to contain the copied data and that LevelTwo, since it is used as the operand of sizeof, is a designator for the actual array, not a pointer. If it is not, replace sizeof LevelTwo with the size of the array.
If you do not need the actual memory filled with data but simply need a way to refer to the contents of the different arrays, make arrayContainer a pointer instead of an array, as with int (*arrayContainer)[4];. Then you can use arrayContainer = levelOne; or arrayContainer = levelTwo; to change which data it points to.
Also, I don't know exactly how many arrays of 4 there will be, so I wouldn't be able to use a standard 3D array and just switch between indexes, unless there's a way to make a 3D jagged array that I don't know about.
It is entirely possible to have a pointer to dynamically allocated memory which is filled with pointers to arrays of four int, and those pointers can be changed at will.

How use local array in function - ANSI C?

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.)

changing fixed size array to dynamic in C

I have an char array of fixed size in C application. I am passing that array to some function and from there I am passing it to multiple functions. So that the array gets filled in some of the functions based on some condition. Since I am sending a fixed size array I am facing problem when I copy data to it if the size is more than the array size. I know that I have to make that char array dynamic but as I said that array gets filled in multiple functions and size will be different. So do I need to dynamically allocate the array wherever it gets filled? Consider the array gets filled in 30+ different functions. Or is there a way to do a minimal modification?
As your question title says C, IMO the best approach will be to decalre a pointer of that particular variable type in your main() function, pass the address of that pointer [essencially a double-pointer] to other functions and allocate memory dynamically.
You can keep on passing the pointer to all other functions. Inside every called functions, measure the amount of memory required to put the data [from that particular function] and use realloc() to increase the available memory.
As mentioned by UncleO, the required pointer should be the pointer to array [i.e, a double pointer]
EDIT
For the very first time allocating memory to that pointer, you can use malloc() or calloc().
From next time onwards, to extend [resize] the amount of memory, you need to use realloc()
You don't pass an array to a function in C, although it appears that way. What gets passed is a pointer to the first element of the array. The pointer is passed by value. That is, the value of the pointer (the memory location) is copied into a local variable. The contents of the array can be changed using this local variable.
If you use malloc() or realloc() with this local variable, then the pointer that was "passed in" won't be affected. realloc() may resize the memory, but it can also free that memory and allocate some new memory to the local variable.
If you want to change the array pointer, then you should pass in a pointer to the pointer. The thing the pointer points to is what is changed. This is a bit more cumbersome. But this way you can allocate more memory is needed.
#include <stdlib.h>
char* arr;
void changeit(char** arrptr)
{
*arrptr = realloc(*arrptr, 20*sizeof(char));
}
void main (void)
{
arr = malloc(10*sizeof(char));
changeit(&arr);
}
To function that do not alter the array, pass the array address and size.
int foo1(const char *array, size_t size, ...)
To each function that does not change the array size, pass array address and array size
int foo2(char *array, size_t size, ...)
To functions that may alter the array size, pass the address of the address of the array and the address of the size.
int foo3(char **array, size_t *size, ...)
Code could put these two variables together
typedef struct {
size_t size;
char array;
} YetAnotherArrayType;
Chux,
There's a little typo at then end of your post. I think you mean:
typedef struct {
size_t size;
char* array;
} YetAnotherArrayType;
You didn't make array a pointer type.
If the poster is handcrafting a container, the classic solution is to track both a size and a capacity.
In that model you allocate the array to some initial a capacity and set size to 0. You then track its population causing it grow by some chunk size or factor each time it fills up.
Frequent reallocation can be a massive performance drain and by the sounds of the program in question such behaviour seems likely.

Is passing a static array to a function efficient?

#define BUFF_SIZE 100000
unsigned char buffer[BUFF_SIZE];
void myfunc(unsigned char[],int,int);
void myfuncinfunc(unsigned char[],int,int);
int main()
{
int a = 10, b = 10;
myfunc(buffer,a,b);
}
void myfunc(unsigned char array[],int a,int b)
{
int m,n;
//blah blah
myfuncinfunc(array,m,n);
}
void myfuncinfunc(unsigned char array[],int a, int b)
{
//blah blah
}
I wish to know the following:
I have created a static array as seen above the 'main' function. Is this efficient? Would it be better if I used a point and malloc instead?
I know it doesn't use the stack, so when I pass the array into inner functions, would it create a copy of the whole array or just send the location of the first entry?
When working on 'array' in the function 'myfunc', am I working directly with the static defined array or some local copy?
Inside the function 'myfunc', when we pass the array into the function 'myfuncinfunc', would it again, send only the first location or a complete copy of the array into the stack?
Thanks for reading the question and would greatly appreciate any help! I'm new to C and trying to learn it off the internet.
I don't see how it would be more or less efficient than an array on the heap.
It decays into a pointer to the first entry.
Therefore it's not a local copy, it's the array itself.
Ditto.
By the way, if a and b are indexes within the array, consider using the size_t type for them (it's an unsigned int guaranteed big enough for indexing arrays).
I have created a static array as seen above the 'main' function. Is this efficient? Would it be better if I used a point and malloc instead?
Define "efficient". Statically allocated arrays are always faster than dynamic ones, because of the runtime overhead for allocation/deallocation.
In this case, you allocate a huge amount of 100k bytes, which might be very memory-inefficient.
In addition, your process might not have that much static memory available, depending on OS. On desktop systems, it is therefore considered best practice to allocate on the heap whenever you are using large amounts of data.
I know it doesn't use the stack, so when I pass the array into inner functions, would it create a copy of the whole array or just send the location of the first entry?
You can't pass arrays by value in C. So a pointer to the first element of the array will be saved on the stack and passed to the function.
When working on 'array' in the function 'myfunc', am I working directly with the static defined array or some local copy?
Directly on the static array. Again, you can't pass arrays by value.
Inside the function 'myfunc', when we pass the array into the function 'myfuncinfunc', would it again, send only the first location or a complete copy of the array into the stack?
A pointer to the first element.

List parameters in recursive calls (C)

I'm designing a recursive algorithm :
int f(int[] a, int[] b){
----changing a here
----changing b here
f(a,b)
----writing a here
----writing b here
}
I know all arrays are pointers so this code should be problematic. It'll write the final values of a and b after all the recursive calls finished. I dont want that to happen.
What should I do to pass that array to recursive calls as regular "pass by value"?
PS: Arrays may be dynamically allocated or resized etc anywhere in recursive calls.
I will assume that int f(int[] a, int[] b) is a typo: it should be int f(int a[], int b[]).
First of all, arrays and pointers are different. Under many circumstances, the name of an array "decays" to a pointer to its first element, but not always. Otherwise, sizeof a, for an array a wouldn't "work".
Secondly, let's ignore recursion for a moment. Let's also make the function prototype simpler:
int g(int *a);
(I changed int a[] to int *a, because in this context, the name of an array is equivalent to a pointer.)
Now, you say that you may "dynamically allocate or resize" the array in the function call. Since everything is passed by value in C, a dynamic allocation or resizing of a inside g() cannot be seen by the caller: the caller would still have the old value of a. But more importantly, if the "original" type of a was an array, i.e., the caller had code like:
int data[SIZE];
g(data);
then trying to resize data in g() is bad, because the parameter specified in the call wasn't dynamically allocated to begin with. You can only dynamically resize something that was the result of malloc(), calloc(), or realloc().
So, there are two problems even with this simple definition:
If g() has to dynamically resize the memory referred to by the address it is given, the value has to come from a dynamic allocation, not an array,
After fixing that, since g() wants to be able to signal the change to the caller, you need to pass a pointer to what needs to be changed. So, the prototype of g() becomes: int g(int **a);.
Hopefully the above will help you get started. If you tell us more about your algorithm, in particular, what you mean by: "changing" and "writing", you will get better responses.
Edit: to answer your question in the comment:
So when I passed an array to a function it decays to a pointer and this pointer is passed by value. If that pointer is pointing a place I allocated before that call...
If you allocated something before the call, it never was an array to begin with. It can be indexed as an array, but that's not the point. So, maybe you are getting confused by the terminology here?
...when my new function changes the pointed value then that value is changed at caller, too.
The pointed-to value is changed, yes.
I dont want it to be like this, so I need a copy of the pointed value in the new function so that my original pointer's pointed value would not change. am I clear now?
It's clearer now, but then that raises more questions:
If you are going to dynamically allocate or resize the data in each call to the function, how are you going to return those new pointers? You can't. And that means you have got yourself a memory leak. Unless you free() the data in the (recursively called) function itself.
How would you resize the pointer? You may not be able to know the size of the data pointed to, unless you use a sentinel value.
Are you using the function to iteratively solve a puzzle or a problem? Are you free()ing your data in each invocation of the function? If you can tell us, exactly what are you trying to do?
All arrays are not pointers.
See these:
http://c-faq.com/aryptr/practdiff.html
http://c-faq.com/aryptr/aryptrequiv.html
http://c-faq.com/aryptr/ptrkindofary.html - specifically this one
Assuming you want the order of the output to be the same as in your original, if you don't want the outer call to see changes to your arrays made in the recursive call, you need to copy them. The easiest way is probably to allocate them on the stack then memcopy from the argument, though that will cause a SO if it gets too big. The second easiest is to malloc and free them. You will probably need to pass the array size around too. You can't pass arrays by value on the stack in C.
Just print them before passing them to the next level of recursion.
Your question isn't terribly clear but what I'm reading is this:
You have a recursive algorithm that operates on two heap-allocated arrays. It is possible that one of the recursive calls will have to reallocate the arrays, and so when it returns to the next level up, the old pointers won't be valid anymore. You want to know how to "pass the arrays by value" in order to avoid this.
First, you cannot pass an array by value in C. Period. Arrays are always passed as pointers to the first element, and there's no way around that.
Second, the answer is always another level of indirection. :)
In order to solve the problem of having to reallocate the arrays during the recursive call, what you want to do is have the function take two pointer-to-pointers (int**), where *a gives the address of the pointer to the first element of the A array, and (*a)[n] gives the nth element of the a array. That way, you can reallocate the array to your heart's content, (changing the value of *a) but the value of a itself always remains the same. By doing this, instances of the function further up the call stack will automatically inherit the reallocations made by the recursive calls because the pointed-to value (*a) of the pointer (a) that they passed to the recursive call was modified to reflect the new location of the actual data.
e.g.
int f(int** a, int** b)
{
/* Do stuff on arrays using (*a)[n] and (*b)[n] */
if (some_condition) {
/* Time to reallocate */
*a = realloc(*a, new_size);
*b = realloc(*b, new_size);
}
/* Do stuff on arrays using (*a)[n] and (*b)[n] */
f(a, b); /* Recursive call */
/* Do more stuff using (*a)[n] and (*b)[n] */
/* a and b are still valid pointers, even though *a and *b might point somewhere new */
return foo;
}
void use_f(void)
{
int* a = malloc(starting_size);
int* b = malloc(starting_size);
f(&a, &b);
}
Given the requirements:
int f(int[] a, int[] b){
----changing a here
----changing b here
f(a,b)
----writing a here
----writing b here
}
What should I do to pass that array to recursive calls as regular "pass by value"?
PS: Arrays may be dynamically allocated or resized etc anywhere in recursive calls.
The code in f() is either authorized to make changes to the arrays (as now), or it is not authorized to make changes. If it is authorized to make changes, then there is nothing much you need to do, except worry about whether you are going to leak memory if you are using dynamic allocation.
If the code is not authorized to change the arrays, then it will have to make copies of the arrays. You can prevent the code from casually modifying them by including appropriate const qualifiers:
int f(const int *a, const int *b) { ... }
Note that you cannot pass arrays by value in C. You could have the caller pass a modifiable copy - or you can have the receiver (callee?) make the copy; one or the other will have to o so if the receiver is going to make modifications when it shouldn't.
The easiest and safest option is to pass a pointer and a size. Say you are working on something like quick-sort:
void sort_range( int* ptr, size_t count )
{
size_t pivot;
assert( ptr ); /* make sure we have memory */
if ( count < 2 ) return; /* terminate recursion */
pivot = partition( count ); /* select a pivot */
assert( pivot < count ); /* make sure we don't overrun the buffer */
sort_range( ptr, pivot ); /* sort left part */
sort_range( ptr + pivot, count - pivot ); /* sort right part */
merge( ptr, count, pivot ); /* merge ranges */
}
Always be conscious about size of the memory chunk you are working with. Unfortunately C doesn't make it easy, so you have to develop a habit of checking your memory ranges.

Resources