How does malloc work within wrapper function? [duplicate] - c

This question already has answers here:
How do I modify a pointer that has been passed into a function in C?
(7 answers)
Closed 2 years ago.
I have a question dedicated to:
void* malloc (size_t size);
In the regular example that can be found on millions of sites over the internet it's shown that the right way to use malloc is the following:
int main()
{
int* num;
num = malloc(sizeof(int));
*num = 10;
printf("Value = %d\n", *num);
free(num);
return 0;
}
But If I want to allocate memory within a function and use it in main like below, then the only option is to implement the function the following way:
void func_alloc(int** elem, int num_value)
{
*elem = malloc(sizeof(int));
**elem = num_value;
}
int main()
{
int* num;
func_alloc(&num, 10);
free(num);
return 0;
}
I assumed by mistake, that such code as below would work:
void func_alloc(int* elem, int num_value)
{
elem = malloc(sizeof(int));
*elem = num_value;
}
int main()
{
int* num;
func_alloc(num, 10);
free(num);
return 0;
}
Could you please explain or maybe give a link to resource with explanation why does it work only this way?
I really cannot understand why do I need double pointer as an input parameter and why in the other case it comes to "segmentation fault"...
Thank in advance ;)

I assumed by mistake, that such code as below will work.
In C, the arguments are passed by value, when you pass a pointer as an argument of a function, you are passing the value of the pointer, basically a copy of it, not the pointer itself, malloc will change the value of that pointer, but since what you passed was a copy, that is what's changed, not the original pointer, that one remains unchanged.
In the second code snippet, the working code, *elem = malloc(sizeof(int)); broadly means make this pointer elem point to this valid memory address given to me by malloc(assuming it succeeds), the value of the pointer to the pointer elem which you passed as an argument remains unchanged, it being a copy doesn't matter because it's not changed, it's still the same address that was passed as argument, the address of the pointer num which is now pointing to the memory location given by malloc.
**elem = num_value means store num_value in the address stored in the pointer where elem is pointing to, which is where num is pointing to, which is the new memory block previously given by malloc.
That being said, it's not the only option, you can use a local pointer, return it and assign it to another local pointer in the caller side, this is still a copy, but it's a copy of the changed pointer:
int *func_alloc(int num_value)
{
int *elem = malloc(sizeof *elem); //more idiomatic
if(elem == NULL){ // check for allocation errors
perror("malloc" );
exit(EXIT_FAILURE);
}
*elem = num_value;
return elem;
}
int main()
{
int* num = func_alloc(10);
free(num);
return EXIT_SUCCESS;
}
Footnote:
In the third code snippet, freeing num, given that it is uninitialized is a bad idea, I assume you know as much, nonetheless I thought I'd mention it. This may be the reason for the segfault you experienced, whatever garbage value num has will be assumed to be valid memory address, and free will try to deallocate it, doing this will invoke undefined behavior. If it was NULL, it's a different story, it's well defined behavior (execept in some very old standars). Initializing variables when they are declared is, in most cases, a good idea.

A commented explanation :
void func_alloc(int* elem, int num_value)
{
/* elem points to address gave by malloc, let's say 0x12345678 */
elem = malloc(sizeof(int));
/* at address 0x12345678 you have now your num_value */
*elem = num_value;
/* end of the function. Changes made to parameters passed by value are lost */
}
int main()
{
int* num;
/* num is a pointer to an address you could not have write access to, you actually don't know */
func_alloc(num, 10);
/* As C arguments are passed by value, changes made into the function are lost */
/* You try to free num which is still a pointer to an address you potentially have no access to => SEGFAULT */
free(num);
return 0;
}
EDIT:
Not shown in this example, but it is good practice to always check that pointer returned by malloc is not NULL, otherwise you should exit without trying to assign a value to the pointer.

If you have:
#include <stdio.h>
void foo(int x)
{
x = 9;
}
int main(void)
{
int a = 1;
foo(a);
printf("%d\n", a);
}
you probably don't expect the value of a in main() to change just because foo() assigned to x, right? It doesn't change, because parameters are assigned by value. The variables x in foo(), and a in main() are two different variables.
The same applies in your code. elem in func_alloc() is a different variable from num in main(), and assigning to the former doesn't change the value of the latter. The fact that these two are of type int *, and not e.g. just int, makes no difference in this.
That said, you can also return the pointer you got from malloc(), e.g.
int *alloc_int(int value)
{
int *p = malloc(sizeof(int));
*p = value;
return p;
}
(not that it seems to make much sense for a mere int.)

Related

C language Array modification with Malloc

void helperWithoutMalloc(int *arr) {
arr[0] = 18;
arr[1] = 21;
arr[2] = 23;
}
int main() {
int *data;
helperWithoutMalloc(data);
printf("%d\n", data[0]);
return 0;
}
The above method successfully modify the value of data through the method helperWithoutMalloc(); however, when malloc method is applied; similar way doesn't work. Three value in the data array still zero
void helperNotWorking(int *arr) {
arr = malloc(sizeof(int)*3);
arr[0] = 18;
arr[1] = 21;
arr[2] = 23;
}
int main() {
int *data;
helperNotWorking(data);
printf("%d\n", data[0]);
return 0;
}
I'm just wondering what happen when the line arr = malloc(sizeof(int)*3) is implemented; and makes two code so different?
The main confusion is that : first code regardless of its incorrectness, can still modify the array element while second code, can't modify the array elements; since both functions pass the address of array; and we manipulate the array element through address
Any data structure in C as in any other language must be provided with a memory region where it data could be kept. In your first example you failed to do so. The 'data' pointer does not point to any memory and is initialized. It worked by a chance and you just caused your program to write data somewhere, which happened to be writable. you needed something like the following:
int main() {
int data[3]; // allocate an array for data
helperWithoutMalloc(data);
In the above example the memory was provided by the C array of 3 elements.
In a similar fashion you can use malloc:
int main() {
int *data = malloc(sizeof(int) * 3);
helperWithoutMalloc(data);
Note that the space for data was allocated before calling to the function and passed to it. The function can use pointer (memory address) to access the array elements.
In your second example you did a different mistake. You allocated the space, but you assigned the pointer to the parameter of the function. The pointer in your case was passed to your function by value, therefore it is uni-directional. you can pass it to the function but not backwards. It worked perfectly well inside the function but it did not update 'data', so you cannot access the values after returning from the function. There are few ways to work around it. I.e. you can return your pointer from the function:
int *helper() {
int *arr = malloc(sizeof(int)*3);
...
return arr;
}
int main() {
int *data = helper();
...
or you can use a pointer to pointer to pass to the function:
void helper(int **arr) {
*arr = malloc(...)
(*arr)[0] = 0;
...
}
int main () {
int *data;
helper(&data);
In my opinion, the correct way should be
void NoMalloc(int *arr) {
arr[0] = 18;
arr[1] = 21;
arr[2] = 23;
}
int main() {
int *data = (int *)malloc(sizeof(int) * 3);;
NoMalloc(data);
printf("%d\n", data[0]);
free(data);
return 0;
}
The malloc function allocates some memory and returns a pointer to that allocated memory.
Pointer stores addresses in the memory, and when you define a uninitialized pointer (such as the your first piece of code, int * data;) you don't know where the pointer (data) is pointing and therefore accessing the values stored at the location would often cause Access Violations and should never be used.
As with any other type of C variables, pointers are passed by values when serving as an argument of a function. So data itself would not be modified after calling helperWithoutMalloc or helperNotWorking. The second piece of code does not work because after calling helperNotWorking, the data pointer is still an uninitialized pointer. The numbers you though you have stored in data is actually stored in the modified value of arr in the helperNotWorking function, which does not affect does not point to the same address as data anymore.

Passing Null Pointer in Function

This variable num remains at 0. I suspect this is because I am passing in a NULL pointer, but I am constrained to the main (and parameters) as is. How do I adjust the content of the helper function to update num correctly?
int main(void) {
int * num_results = NULL;
int num = 4;
set(num_results, num);
printf(ā€œ%d\nā€, *num_results);
return 0;
}
void set(int * results,num){
num_results = malloc(sizeof(int));
*num_results = num;
}
I'm going to guess what you really mean with your question and try to give a decent answer.
I guess you want to change num_results to be equal to num by passing it to the function set as a pointer, and I can see a few mistakes you've made:
You probably have this in your full code, but don't forget to #include <stdio.h> to use printf() and to #include <stdlib.h> to use malloc()
Your function set() should be declared before main(), you can do this by declaring a prototype before main() or simply defining the set() function before main().
Now let's go to your solution: you want to pass the num_results as a parameter to a function, allocate some memory and assign the address to num_results and then update the value to the one in num.
When you pass an int * as a parameter, I guess you already know that by passing int you are simply giving a copy of what is inside an int variable. This works the same way with an int *, you are not passing a reference to num_results so that you can update the address of the pointer, you are passing a copy of the current address, NULL, which will not be modified. What could be modified is what is inside of the current address, but the current address is NULL, so not can really be modified.
Since you want to allocate memory and assign its address to num_results, you must pass a pointer to a pointer, so you are passing the address of where your int* variable is being kept and where you can actually change it.
This way, your function should look like void set(int ** results, int num) and you should call it with set(&num_results, num), so you are passing a reference to num_results, where you can change the address it points to, currently NULL and then the address returned by malloc().
You'd also have to change the body of your function, because you're now using an int **, you want to assign the new address to *results, because results == &num_results, and assign num to **results, because *results = num_results.
I hope my explanation is not very confusing and hopefully someone can explain it better with another answer or by editing mine. Final code:
#include <stdio.h>
#include <stdlib.h>
void set(int ** results, int num){
*results = malloc(sizeof(int));
**results = num;
}
int main(void) {
int * num_results = NULL;
int num = 4;
set(&num_results, num);
printf("%d\n", *num_results);
return 0;
}
set(num_results, num);
Here NULL is getting passed to results variable in set(), when you allocate memory to results, NULL is getting replaced by valid memory address, but you need to understand it will be held in results variable only as its a local variable to set()
You should either pass address of num_results to set() so that memory allocated in set() is retained in main(), or just allocate memory to num_results in main function then pass it to set() as done below:
#include <stdio.h>
int main() {
int *num_results = NULL;
int num = 4;
num_results = malloc(sizeof(int));
set(num_results, num);
printf("%d\n", *num_results);
return 0;
}
void set(int *results,int num){
*results = num;
}
Another example would be:
#include <stdio.h>
#include <stdlib.h>
void set(int **r, int num);
int main() {
int *num_results = NULL;
int num = 4;
/*num_results = malloc(sizeof(int));*/
set(&num_results, num);
printf("%d\n", *num_results);
return 0;
}
void set(int **results,int num){
*results = malloc(sizeof(int));
*(*results) = num;
}
How do I adjust the content of the helper function to update num correctly?
That seems the wrong question, as your set() function seems intended to copy the value of num elsewhere, not to update num itself.
One of your problems is where to copy it. Presently, you allocate some memory for that dynamically, and copy it there. That's fine as far as it goes, but the pointer to the allocated memory is not conveyed back to the caller. This is because all C functions pass arguments by value, and in particular, your main() passes the first argument of set() by value (a value of type int *). Modifying the function's copy does not affect its caller's copy -- that's what pass-by-value is all about.
You may be overlooking a simple fact: dynamic allocation is not the only way to obtain a valid pointer value, nor even the the most important or common. When you see a pointer, you should not automatically go looking for malloc(). You can very easily get a pointer from an array, but perhaps even more importantly, you can get a pointer value by applying the address-of operator (&).
For your set() function to do work that its caller can see without resorting to global variables or changing its signature, the caller must pass as the first parameter a valid pointer to an object that the caller can access, such as one of its own local variables. The pointer is passed by value so the function gets a copy, but it's a copy: it points to the same object that the caller's pointer did. The set() function can therefore modify the pointed-to object via its copy of the pointer to it.
So suppose your main() declared its own local variable result, an int. What do you suppose it could do with &result?
In your helper function you should refer to the first parameter name results instead of num_results. Your helper function should be like:
void set(int * results, int num){
results = malloc(sizeof(int));
*results = num;
}
Your code won't compile. Compiler error messages will tell you how to fix them. Here is a fixed one.
#include<stdlib.h>
#include<stdio.h>
int * num_results = NULL;
void set(int * results, int num){
num_results = malloc(sizeof(int));
*num_results = num;
}
int main(void) {
int num = 4;
set(num_results, num);
printf("%d\n", *num_results);
return 0;
}
For the sake of learning it, you can look at the compilation error messages here and try to fix it by yourself:https://segfault.stensal.com/a/XWfv8rxCJHVtAuRQ
Disclaimer: I built stensal.io as a tool to catch memory issues.

Double Pointers in C and their scope

I have this code:
void alloc2(int** p) {
*p = (int*)malloc(sizeof(int));
**p = 10;
}
void alloc1(int* p) {
p = (int*)malloc(sizeof(int));
*p = 10;
}
int main(){
int *p;
alloc1(p);
//printf("%d ",*p);//value is undefined
alloc2(&p);
printf("%d ",*p);//will print 10
free(p);
return 0;
}
So, I understand that alloc1 just makes a local copy so it's not effecting outside the function the pointer which is given as a parameter.
But what is happening with alloc2?
tl;dr;
And why this alloc1(&p); won't work?
Update
I think i answered my question. The crucial thing is that & makes you a pointer and then a was built to a double pointer bei dereferencing once. Then the double pointer points to the address given be malloc. Finally the address was filled with 10.
And alloc1(&p); would work, but you couldn't derefence the double pointer since it takes a single pointer.
Thanks to all of you
It didn't become a double pointer, in alloc2() you are passing a pointer containing the address of main()'s p. When you dereference it you are actually modifying the address stored in main()'s p. And that's why it's working.
Since there is no pass by reference in c, the only way you can modify a parameter inside a function is by passing a pointer with it's address, for example if you have to pass an integer to a function and the function needs to modify it then you make a pointer using the address of & operator and pass that pointer to the function, example
void
modify(int *pointer)
{
*pointer += 1;
}
int
main(void)
{
int value;
value = 0;
modify(&value);
printf("%d\n", value);
modify(&value);
printf("%d\n", value);
}
would output
1
2
A double pointer is a pointer to a pointer, so you are making a pointer from p in main() which stores the address of p in main(), the pointer itself is stored somewhere, so you are passing the address where the pointer is stored and hence you can modify it's contents from within alloc2().
Note: It's bad style to cast the return valud of malloc(), read more about it here.
It would be clearer if you gave the variables in different functions different names. Since you have multiple variables and arguments named p, and they are distinct from each other, it is easy to confuse yourself.
void alloc2(int** pa2)
{
*pa2 = (int*)malloc(sizeof(int));
**pa2 = 10;
}
void alloc1(int* pa1)
{
pa1 = (int*)malloc(sizeof(int));
*pa1 = 10;
}
int main()
{
int *p = 0;
alloc1(p);
//printf("%d ",*p);//value is undefined
alloc2(&p);
printf("%d ",*p);//will print 10
free(p);
return 0;
}
Apart from renaming the arguments of functions, I've also initialised p in main() to zero (the NULL pointer). You had it uninitialised, which means that even accessing its value (to pass it to alloc1()) gives undefined behaviour.
With p being NULL, alloc1() also receives the NULL pointer as the value of pa1. This is a local copy of the value of p from main(). The malloc() call then changes the value of pa1 (and has no effect on p in main(), since it is a different variable). The statement *pa1 = 10 sets the malloced int to be 10. Since pa1 is local to alloc1() it ceases to exist when alloc1() returns. The memory returned by malloc() is not free()d though (pa1 ceases to exist, but what it points to doesn't) so the result is a memory leak. When control passes back to main(), the value of p is still zero (NULL).
The call of alloc2() is different, since main() passes the address of p. That is the value of pa2 in alloc2(). The *pa2 = (int *)malloc(sizeof(int)) statement does change the value of p in main() - to be the value returned by malloc(). The statement **pa2 = 10 then changes that dynamically allocated int to be 10.
Note also that the (int *) on the result of malloc() is unnecessary in C. If you need it, it means one of
You have not done #include <stdlib.h>. The type conversion forces the code to compile, but any usage of the int - strictly speaking - gives undefined behaviour. If this is the case, remove the int * and add #include <stdlib.h>.
You are compiling your C code using a C++ compiler.

assign dynamic array in a function and send it back to the caller in C

I have been using java for long time but for some reason I need to use C (ANSI C not C++) to write a simple code. I need to pass the pointer from outside to a function, allocate some memory to the pointer and assign some values also before the function return. I have my code like
#include <stdio.h>
#include <stdlib.h>
void test(int *a)
{
int n=3;
// I have to call another function t determine the size of the array
n = estimatesize(); // n >=3
// I tried fix size n=10 also
a = (int*)malloc(n*sizeof(int));
a[0] = 1;
a[1] = 2;
a[2] = 3;
}
void main(void)
{
int *s=NULL;
test(s);
printf("%d %d %d", s[0], s[1], s[2]);
}
I don't know why the code crashes. I thought at the beginning it is estimatesize() return wrong number but even I fix n to 10, the error still there. So I cannot pass a pointer to a function for memory allocation? If so, how can I dynamically create memory inside a function and pass it out? I know it may be a safe problem in this way but I just want to know if it is possible and how to do that. Thanks.
There are two solutions to this: Either return the pointer from the function, or pass the argument by reference.
For the first one, you simply don't take any arguments, instead you return the pointer:
int *test(void)
{
int *a = malloc(...);
...
return a;
}
int main(void)
{
int *s = test();
...
}
For the second one, you need to pass the address of the pointer, in other words a pointer to the pointer, using the address-of operator &:
void test(int **a)
{
*a = malloc(sizeof(int) * 3);
for (int i = 0; i < 3; ++i)
(*a)[i] = i;
}
int main(void)
{
int *s;
test(&s);
...
}
The reason it doesn't work now, is because the pointer (s in main) is passed by copying it. So the function test have a local copy, whose scope is only in the test function. Any changes to a in the test function will be lost once the function returns. And as s is copied for the argument, that means that s in main never actually changes value, it's still NULL after the function call.

Double pointers are also sometimes employed to pass pointers to functions by reference

" Double pointers are also sometimes employed to pass pointers to functions by reference "
can somebody can explain me the above statement, what exactly does point to function by reference means ?
I believe this example makes it clearer :
//Double pointer is taken as argument
void allocate(int** p, int n)
{
//Change the value of *p, this modification is available outside the function
*p = (int*)malloc(sizeof(int) * n);
}
int main()
{
int* p = NULL;
//Pass the address of the pointer
allocate(&p,1);
//The pointer has been modified to point to proper memory location
//Hence this statement will work
*p=10;
//Free the memory allocated
free(p);
return 0;
}
It means that you have a function that takes a pointer pointer (type int ** for example). This allows you to modify the pointer (what data it is pointing to) much in the way passing a pointer by reference would allow.
void change (int *p) {*p = 7;}
void Really_Change (int **pp) {*pp = null;}
int p = 1;
int *pp = &p;
// now, pp is pointing to p. Let's say it has address 0x10;
// this makes a copy of the address of p. The value of &p is still 0x10 (points to p).
// but, it uses that address to change p to 7.
change(&p);
printf("%d\n", p); // prints 7;
// this call gets the address of pp. It can change pp's value
// much like p was changed above.
Really_Change(&pp);
// pp has been set to null, much like p was set to 7.
printf("%d\n", *pp); // error dereference null. Ka-BOOM!!!
So, in the same way that you can pass a pointer to an int and change the value, you can pass a pointer to a pointer and change its value (which changes what it points to.)
I'll try to explain with both code and plain english :). The explanation may get long, but it will be worth the while.
Suppose we have a program, running its main() function, and we make a call to another function that takes an int parameter.
Conceptually, When you pass a variable as a parameter to a function, you can do so in (roughly speaking) two ways: by value, or by reference.
"By value" means giving the function a copy of your variable. The function will receive its "content" (value), but it won't be able to change the actual variable outside its own body of code, because it was only given a copy.
"By reference", on the other hand, means giving the function the actual memory address of our variable. Using that, the function can find out the variable's value, but it can also go to that specified address and modify the variable's content.
In our C program, "by value" means passing a copy of the int (just taking int as argument), and "by reference" means passing a pointer to it.
Let's see a small code example:
void foo(int n) {
n = 10;
printf("%d\n", n);
}
int main() {
int n = 5;
foo(n);
printf("%d\n", n);
return 0;
}
What will the output of this program be? 10 10? Nope. 10 5! Because we passed a copy of the int, by value and not by reference, foo() only modified the number stored in its copy, unable to reach main()'s copy.
Now, if we do it this way:
void foo(int* n) {
*n = 10;
printf("%d\n", *n);
}
int main() {
int n = 5;
foo(&n);
printf("%d\n", n);
return 0;
}
This time we gave foo() our integer by reference: it's actual memory address. foo() has full power to modify it by accessing it's position in memory, foo() and main() are working with the same copy, and so the output will be 10 10.
As you see, a pointer is a referece,... but also a numerical position in memory. It's similar to an int, only the number contained inside is interpreted differently. Think of it this way: when we pass our int by reference, we're passing an int pointer by value!. So the same by value/by reference logic can be applied to pointers, even though they already are references.
If our actual variable was not an int, but an int reference (pointer), and we wanted main() and foo() to share the same copy of that reference so that foo() can modifiy it, what would we do? Why of course, we'd need a reference to our reference! A pointer to a pointer. That is:
int n; /* integer */
int* n; /* integer reference(pointer). Stores an int's position in memory */
int** n; /* reference to integer reference, or double pointer.
Stores int*'s memory address so we can pass int*s by reference. */
I hope this was useful.

Resources