The logic behind pass by pointer to pointer in C - c

I learned from this page: FAQ that, if you want to initialize a pointer inside a function, then you should pass a pointer to pointer, i.e, **p as foo1()
void foo1(int **p) {
*p = malloc(100*sizeof(int)); // caller can get the memory
}
void foo2(int *p) {
p = malloc(100*sizeof(int)); // caller cannot get the memory
}
However, a pointer means its value is the address it points to. Where does the memory allocated in foo2() go after leaving its scope?
I still can't figure out the different behavior between passing pointer to value and pointer to pointer? I search through SO but only found the solution or short description. Could anyone help in more detail?

The memory allocated in foo2 is lost. This creates a memory leak because you have no idea where to find and use the allocated memory after foo2 returns.
Consider:
int *mymemory = NULL;
foo2(mymemory);
//mymemory is still NULL here. Memory has been allocated,
//but you don't know at which address
//in particular, you will never be able to free() it
versus:
int *mymemory = NULL;
foo1(&mymemory);
//mymemory is now the address of the memory
//allocated by the function
dostuffwith(mymemory);
free(mymemory);

Maybe it helps if we start with only one level of indirection.
consider this:
void foo1(int *p) {
^^
//this p is local to the foo1 function
//p contains the address of an int
*p = 12;
//now we dereference the pointer, so we set what p points to , to 12
}
void func(void) {
int x;
^^
//here is the x
foo1(&x);
^^
//now we find the location (address of) x, we copy that address
//into the arguments for foo1()
//foo1 sets our x int to 12
}
Let's add one more indiretion:
void foo1(int **p) {
^^
//this p is local to the foo1 function
//p contains the address of a pointer to an int
*p = NULL;
//now we dereferenced the pointer, so we get an int*. We just
//set it to NULL
}
void func(void) {
int *x;
^^
//here is the x.
foo1(&x);
^^
///now we find the location (address of) x, we copy that address
//into the arguments for foo1()
//foo1() sets the x pointer to NULL.
}
In both cases we are able to manipulate the x variable inside func1(), since the location(address of)
the x variable is passed into func1().
In the last case, we did *p = NULL;. Which would make x == NULL. We could have set it
to something that malloc() returned: *p = malloc(100)
But if we alter the first case:
void foo1(int *p) {
^^
//this p is local to the foo1 function
//p contains the address of an int
p = NULL;
//now we just set the local `p` variable to NULL.
//the caller will not see that, since `p` is just our own copy
//of pointer.
}
void func(void) {
int x;
^^
//here is the x
foo1(&x);
//foo1 just set its own copy of the pointer we created by doing `&x` to NULL.
//we will not see any changes here
}
We just set p = NULL; in the last case here. If we used malloc instead:
void foo1(int *p) {
^^
p = malloc(100);
//now we just set the local `p` variable to what malloc returns.
//the caller will not see that, since `p` is just our own local copy
//of the pointer.
//When foo1() returns, noone has any way of knowing the location
//of the memory buffer that malloc returned, so this memory is lost (a memory leak)
}

In your second example the memory allocated is leaked - once foo2 ends, there is no variable left that contains the address that was allocated, so it can't be freed.
You could also consider
void foo3 (int bar) {
bar = 8;
}
int main (int argc, char *argv[]) {
int x = 0;
foo3(x);
printf("%d\n", x);
return 0;
}
when foo3 ends, x is still 0 - the change to the contents of bar in foo3 don't affect the outer variable that was passed in. You're doing exactly the same when you pass in a single pointer - you're assigning the address of some memory to it, but then losing that address when the function exits.

To better understand indirection levels in C, it can be instructive to look at how the compiler organizes its memory.
Consider the following example :
void function1 (int var1, int var2) { ... }
In this case, function1 will receive 2 variables. But how ?
These variables will be put into the call stack memory. This is a linear, LIFO (Last in, First Out) type of allocation strategy.
Before calling function1(), the compiler will put var1 then var2 into the call stack, and increment the position of the call stack ceil. Then it will call function1(). function1() knows it must get 2 arguments, and so it finds them into the call stack.
What happens after function1() finishes ? Well, the call stack is decremented, and all variables into it are simply "disregarded", which is almost the same as "being erased".
So it's pretty clear that whatever you do to these variables during function1() is going to be lost for the calling program. If anything has to remain available to the calling program, it needs to be provided into a memory space that will survive the call stack decrement step.
Note that the logic is the same for any variable inside function1() : it will be unavailable to the calling function after function1() finishes. In essence, any result still stored into function1() memory space is "lost".
There are 2 ways to retrieve a usable result from a function.
The main one is to save the result of the function into a variable of the calling program/function. Consider this example :
int* foo3(size_t n) { return (int*) malloc(n); }
void callerFunction()
{
int* p;
p = foo3(100); // p is still available after foo3 exits
}
The second, more complex, one is to provide as an argument a pointer to a structure which exists into the calling memory space.
Consider this example :
typedef struct { int* p; } myStruct;
void foo4(myStruct* s) { s->p = (int*) malloc(100); }
void callerFunction()
{
myStruct s;
foo4(&s); //p is now available, inside s
}
It is more complex to read, but also more powerful. In this example, myStruct contains a single pointer, but the structure could be a lot more complex. This open the perspective to offer myriad of variables as the result of a function, instead of being limited to basic types, as for the previous example with foo3().
So what happens when you know that your structure is in fact a simple basic type ? Well, you can just provide a pointer to it. And, by the way, pointer is itself a basic type. So if you want to get the result of a modified pointer, you can provide as an argument, a pointer to a pointer. And there we find foo1().
void foo1(int **p) {
*p = (int *) malloc(100); // caller can get the memory
}

The problem with foo2 is that the p which is passed in is only modified inside the foo2 function. This is the same as :
void bar(int x)
{
x = 42;
}
...
int a = 7;
bar(a);
...
In the above code, a doesn't change because of the call to bar. Instead, a copy of a is passed to bar, and the copy is modified in bar.
The exact same thing happens in foo2. The memory is allocated, stored in p, which is a copy of the pointer passed in. When the code returns, the original pointer retains its original value.
By passing the address of a pointer (&ptr) to foo1, we can modify the ORIGINAL pointer, and thus pass the address of the allocation back to the caller of foo1.
Of course, when there is no reference back to the originally allocated memory, as is the case after a call to foo2, it is called a memory leak - generally considered a bad thing.

Passing a pointer to value: A copy of the pointer(i.e. address of the value) is made in the function(on the stack frame). This allows you to modify the value.
Passing a pointer to a pointer: A copy of the pointer to a pointer(i.e. address of the pointer which in turn points to the value) is made in the function(on the stack frame). This allows you to modify the value as well as the pointer to this value.
The memory allocated using malloc, calloc, realloc and new resided on the heap which means that it exists even after a function returns(stack frame destroyed).
void foo2(int *p) {
p = (int *) malloc(100); // caller cannot get the memory
}
However, since the pointer p is lost after the function is returned, this memory cannot be accessed and will result in a leak.

As behaviour of all arguments is the same as local variables (they are passed by value), you can not modify pointer passed by value.
So in foo2() you allocate memory, but you can not use it outside the function, as you actually modify local variable.
The foo() function actually modifies the value pointed by **p, so pointer passed to function will be updated.

Related

Passing struct pointer to two functions and then calling malloc

I have a struct in my main function. I pass that pointer to another function which does some stuff and if conditions are met, it passes it to another function to get filled out. When returning to the main function the t struct contains none of the data mydata that was copied into it.
typedef struct _t {
int one;
int two;
int three;
int four;
} T;
void second(T *t) {
t = malloc(20);
memcpy(t, mydata, 20);
}
void first(T *t) {
second(t);
}
int main() {
T t;
first(t);
}
Do I need to be working with double pointers here? If the address of t was 0x1000 and I passed it to first() then wouldn't referencing t just be 0x1000? And same as if I pass the pointer to second()?
In this answer, I assume that, for reasons not shown, you do in fact need to make a dynamic memory allocation. If that is not the case, the only changes that need to be made are replacing first(t); with first(&t);, and removing t = malloc(20);.
The first problem to fix is that t in main should have the type T *, not T. You are making a dynamic memory allocation, and seem to want to store that pointer in t, so you would need: T *t;.
The second problem is that you want to manipulate the value of t in main, but are passing it by value to first. Instead, you need to pass a pointer to t into first: first(&t);.
Fixing both of these, you now pass a pointer to a pointer to T (the type of &t) into first and second, so you need to change their signatures to be, respectively, void first(T **t) and void second(T **t).
Applying both changes, as well as making some small style tweaks, we get:
typedef struct T {
int one;
int two;
int three;
int four;
} T;
void second(T **t_ptr) {
*t_ptr = malloc(20);
memcpy(*t_ptr, mydata, 20);
}
void first(T **t_ptr) {
second(t_ptr);
}
int main() {
T *t;
first(&t);
}
Another thing that's missing, and needs to be added, is checking for the success of malloc, but I haven't added that to the above code.
Also, what you've shown in the question shouldn't compile; you're passing a struct to a function that accepts a pointer.
Your problems are common to new C developers. And actually you have two of them.
The first problem is that you pass your structure by value.
The first function is declared to receive a pointer to T but you pass t and not &t (which is the address of t - and this is what you want when a function accepts a pointer).
However there is still another problem so that even if you change your code as suggested above it will still not work correctly. second allocates memory using malloc. The function receives T as a pointer T *t. You assign the output of malloc to t in effect overwriting what t points to (and if t was previously allocated you will leak memory here).
Bellow you can see a correct code for what you want.
typedef struct _t {
int one;
int two;
int three;
int four;
} T;
/* Make sure we have some data to initialize */
T mydata = {0};
/*
We take a pointer to a pointer and change what the external pointer points to. */
In our example when this function is called *ppt is NULL
and t is a pointer to t in main()
*/
void second(T **ppt) {
/*
We never calculate the size of structures by hand. It can change depending on
OS and architecture. Best let the compiler do the work.
*/
*ppt = (T*)malloc(sizeof(T));
memcpy(*ppt, &mydata, sizeof(T));
}
void first(T **ppt) {
/* Make sure we don't leave dangling pointers. */
if (NULL != *ppt)
free(*ppt);
second(ppt);
}
int main() {
T *t = NULL; /* A pointer to our data */
/*
We pass a pointer to our pointer so that the function can change the value it
holds
*/
first(&t);
/* Always do an explicit return if the type of the function is not void */
return 0;
}
How to understand what is going on:
First we declare t as a pointer to a memory holding a type T and we make sure we initialize the pointer to point to NULL (which is a convention meaning that the pointer is not initialized).
We have a function that will allocate the memory for us using malloc. malloc allocates memory from the heap and returns the address of that memory. (In reality a pointer is just a variable holding an address in memory). We want to place that address in t declared in main(). To do so we need to pass to the allocating function the address of t so it can be modified. To do this we use the address of operator - &. This is why we call the function like this first(&t).
Our allocating function accepts a pointer to a pointer. This is because we want to change the address t points to. So we declared the parameter as T **ppt. It holds the address of the pointer *t in main. In the function we dereference the pointer to the pointer to get the original pointer we want to assign the address malloc returns.

Pass by reference for pointers in C

I was trying to understand the concept of passing by reference. When I do this,
#include<stdio.h>
int recent (int *a)
{
*a = 20;
return 0;
}
int main()
{
int bee;
bee=5;
int *val = &bee;
printf("Value is %d\n", *val);
recent(val);
printf("Now Value is %d\n", *val);
return 0;
}
Basically I am making the pointer val point to the memory location of bee, and then when I pass it to recent function, and change the value, that change gets reflected in the calling function, so the value changes to 20. But when I do this,
#include<stdio.h>
int check = 20;
int recent (int *a)
{
a = &check;
return 0;
}
int main()
{
int bee;
bee=5;
int *val = NULL;
recent(val);
printf("Now Value is %d\n", *val);
return 0;
}
I get segmentation fault.
Is it because I didn't initialize the pointer to point to any location, and then I passed the value to recent function, and even though I made it point to a memory location (check variable), the calling function didnt catch that because I was passing by value?
Is this completely true or I misinterpreted something and got lucky with the answer?
Your problem is that you are printing the output of dereferencing the pointer val in the main function. The value of the pointer val in the main function is NULL. Thus the program is trying to print the thing at memory location 0, which is inaccessible to your program and results in a segmentation fault.
First you create the val pointer and assign it the value NULL.
int *val = NULL;
Then you call recent, passing it the pointer val, which still holds NULL.
recent(val);
Finally you print *val. val still holds NULL, and the * operator tells the compiler to "dereference" val, meaning to use the value of the thing that val is pointing to.
printf("Now Value is %d\n", *val);
In response to the question of whether your description is correct, the answer is sort of, but your description is imprecise. You made the function's copy of the pointer point to something. When you implement a pass-by-reference function in C using pointers, you are still passing the pointers themselves by value: a copy of the pointer is made, pushed onto the stack, and sent to the function. If you update the value of the pointer in the called function, the value of the pointer in the calling function will not be changed.
The reason has to do with your function recent(). When you pass in "a" you are passing in an int* (i.e. int pointer) which is an address to a location in memory. However, "a" as you have it, is local to this function (the pointer is pass by value).
Thus when you set "a = &check", you are only changing the local pointer value. As soon as recent() returns, "a" goes out of scope. In this context, you are never changing what "a" actually points to.
Thus, you segfault because val is still null, and you are trying to dereference a NULL pointer.
val is still a null pointer after leaving the function. The pointer itself is (as you correctly guessed) only passed by value, not by reference. Inside the function you are only modifying the pointer (which only lives insides the function), not the pointer target.
Besides that, please be careful with passing around memory locations to automatic stack variables. At least coming from a C++ background, it's considered bad style. Since you don't explicitly control the life cycle of a stack variable yourself (as you would do with malloc/free), you can easily shoot yourself in the foot by accidentally dereferencing pointers which have already been cleaned from the stack.
Is it because I didn't initialize the pointer to point to any location,
Code well initialized with int *val = NULL;, yet NULL is not a valid location. It isn't the NULL is a location or not. It is the NULL is the null pointer constant. As a null pointer, it "is guaranteed to compare unequal to a pointer to any object or function."
... and even though I made it point to a memory location (check variable), the calling function didn't catch that because I was passing by value?
Yes. With a = &check;, only the local a was affected, not the val in which a was copied from as the actual augment val was passed by value (copied) to the formal parameter a.
Is this completely true ...
IMO: Yes
... I misinterpreted something and got lucky with the answer?
It appears no misinterpretation. Lucky - hard to rate.
Here is what is going on in your code:
#include<stdio.h>
int check = 20;
int recent (int *a)
{
a = &check;
return 0;
}
int main()
{
// memory is allocated to hold an integer
int bee;
// the number 5 is written into that memory space
bee = 5;
// memory is allocated to hold a memory address
// the value of null (which is a invalid address) is written into it
int *val = NULL;
// more memory is allocated to hold a memory address (int* a)
// the address in val (which is null) is written into it
// the new memory address (a) now points to the address of check
recent(val);
// val is still NULL
// BOOOM!
printf("Now Value is %d\n", *val);
return 0;
}
Long story short, you are correct! :)
It's basically what all have answered. It's because you are passing the address pointed by pointer a using Pass By Value method. That is your sending in a copy of the address. If you want the second code to work you need to change the code to the following,
#include<stdio.h>
int check = 20;
int recent(int **a)
{
*a = &check;
return 0;
}
int main()
{
int bee;
bee = 5;
int *val = NULL;
recent(&val);
printf("Now Value is %d\n", *val);
return 0;
}
That is you have to Pass the address pointed by a by using C version of "Pass By Reference".

Correct way to free memory in C

so I'm trying to understand the whole concept of memory management in C and I was given this code:
int main(int argc, int *argv[]) {
item *x = NULL;
x = (item *) malloc (sizeof(item));
...
free_item(&x);
}
void free_item(item **x) {
free(*x);
*x = NULL;
}
where item is earlier defined structure. The point, where I get confused is free_item(&x); because when I write free_item(x); and change the function to:
void free_item(item *x) {
free(x);
x = NULL;
}
the code seems to work the same way as the previous one.
So, is there any difference? And if not, is there any reason, why would someone send an adress on a pointer of a structure to a function, which frees this structure?
Yes. First, I think there's a typo in your modified function. It should be:
void free_item(item *x) {
free(x);
x = NULL;
}
Now, for the differences. The free call will succeed, as all it expects is a "pointer-to-type" variable for data which is allocated dynamically on the heap.
The second part, x = NULL, will not work as expected. Remember, in C, when passing an argument to a function, we pass by value always, never by reference. You are being passed a copy of a variable, so x = NULL just sets a temporarily automatically allocated copy of x to NULL, not the actual variable passed as an argument.
The original function which you changed does both parts correctly.
In the first case, to modify the content of pointer variable x, you need to pass on using a reference. That's why the &x and the double pointer is being used to free() the memeory which has been allocated from main(). This is correct.
in second case, a function-local copy of x will be created and passed on to free_item() which will have no impact on the x present in main(). The x = NULL; will have the scope only inside free_item().
In your first example you are calling free_item with argument of type pointer to pointer to item (assuming item **x argument).
In second example point value (main::x) is copied to free_item::x (different scope) and that copied value is set to NULL (and value is discarded afterwards).
Add printf("%p\n", x); to the end of main() (after free_item).
With first example you will see NULL and with second x will still be set to address previously stored there.
In first example, lets say your pointer is on address 0x00400000 and it points to memory allocated at 0x00410000.
0x00400000 0x00410000 <- x is stored here
0x00400004 0x00400000 <- tmp described later; point to x
...
0x00410000 .......... <- x points here; start of item - returned by malloc
When you call item **tmp = &x you will see that it will contain the address 0x00400000 (and tmp itself would be stored on different memory address).
Then in free_item():
free(*tmp); // The same as free(0x00410000)
*tmp = NULL; // Modifies data at 0x00400000 = NULL
When you use free ,you pass the pointer ,not the value of the pointer.
So, if you use
item *x
, you should use
free(x)
x = (item *) malloc (sizeof(item)); is unnecessary. x = malloc(sizeof(item)); will suffice.
2.
void free_item(item *data){
free(data);
}
Is the correct way to do it.
Write idiomatic C code. There is no difference perse but its hard do debug and maintain.
I would write free_item(x); rather than free_item(&x) and have free_item(item **x)

Initializing struct in C

OK, this is the definition of the struct:
typedef struct {
int first;
int last;
int count;
char * Array [50];
} queue;
and I use another function to initialize it
void initialize(queue * ptr){
ptr=malloc(sizeof(queue));
ptr->first=0;
ptr->last=0;
ptr->count=0;
}
Then I use printf to print out first, last and count. All three should be zero. However, what I actually get is, count is 0 as I expected, but first&last are two very large strange numbers and they change every time I run the program. Can anybody tell me what's wrong here? Thank you.
You are passing your pointer by value. The function changes a copy of the argument it receives, but the caller's pointer is not modified and is probably unintialized.
You need to change your function to take a queue** and pass the address of the pointer you want to initialize.
Alternatively you could return a pointer instead of passing it in as an argument. This is a simpler approach.
Given:
void initialize(queue * ptr);
Pass it like this:
queue q; // caller allocates a queue
initialize(&q);
// now q is initialized
Also, it's allocated by the caller -- don't malloc it.
// bad
void initialize_bad(queue * ptr){
ptr=malloc(sizeof(queue)); << nope. already created by the caller. this is a leak
ptr->first=0;
ptr->last=0;
ptr->count=0;
}
// good
void initialize_good(queue * ptr){
ptr->first=0;
ptr->last=0;
ptr->count=0;
// ptr->Array= ???;
}
If you prefer to malloc it, then consider returning a new allocation by using this approach:
queue* NewQueue() {
// calloc actually works in this case:
queue* ptr = (queue*)calloc(1, sizeof(queue));
// init here
return ptr;
}
Ultimately, what is 'wrong' is that your implementation passes a pointer by value, immediately reassigns the pointer to a new malloc'ed allocation, initializes the malloc'ed region as desired, without ever modifying the argument, and introducing a leak.
Here is the smallest alteration to your program which should correct your problem:
void initialize(queue * * pptr) {
queue * ptr;
ptr=malloc(sizeof(queue));
if (ptr) {
ptr->first=0;
ptr->last=0;
ptr->count=0;
}
/* The assignment on the next line assigns the newly allocated pointer
into memory which the caller can access -- because the caller gave
us the address of (i.e. pointer to) such memory in the parameter
pptr. */
*pptr = ptr;
}
The most important change is to pass a queue ** to your initialize function -- otherwise you are changing a copy of the queue * supplied as the actual parameter when you call initialize(). By passing a pointer to the pointer, you can access the original variable which stores the pointer in your caller.
I couldn't resist and also added a check for NULL returned from malloc(). That doesn't address your problem, but I couldn't bring myself to post code that didn't do it.

Need an explanation of how pointers work when passing in as function args

I thought I understood the basics of pointers, but after checking out some documentation on some sqlite3 methods I got thrown, so now I am unsure if my understanding is correct.
Here is a call to an sqlite3 method:
char* dataFilePath = "foobar.sqlite";
if (sqlite3_open(dataFilePath, &database) != SQLITE_OK) {...}
And here is the function header declaration:
int sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
Why is it that &database suddenly becomes a pointer to a pointer?
Another method call to close the database connection is:
sqlite3_close(database);
With the following at the function header:
int sqlite3_close(sqlite3 *);
Why is this just a pointer, when I pass in a pointer? Would this not be a pointer to a pointer?
From all examples I have seen it always seemed the inverse of the functions above, ie.
// function
void foo(someDataType *bar) { ... }
// function call
foo(&bar);
Thanks for the help.
Most likely, sqlite3_open is allocating memory for the database handle. For this reason the function needs a pointer to a pointer to the database handle (sqlite3) so that it can modify the pointer to the database handle. For example:
typedef struct { /*...*/ } sqlite3;
int sqlite3_open(const char *filename, sqlite3 **ppDb) {
/* ... */
// Allocate memory for the database handle.
*ppDb = (sqlite3 *)malloc(sizeof(sqlite3));
/* ... */
return 0;
}
However, sqlite3_close only needs a single pointer to free the memory:
int sqlite3_close(sqlite3 *pDb) {
/* ... Cleanup stuff ... */
free(pDb);
return 0;
}
I think the short explanation for what you're asking is that using "&" essentially means "a pointer to this"
int value = 0;
int *pointer = &value;
int **doublePointer = &pointer;
A pointer is the address of a variable.
Assuming that database is declared as sqlite3* database;, &database is the address of (or, a pointer to) the database pointer.
sqlite3_open takes a pointer to a pointer so that it can set the value that the pointer points to. It makes a sqlite value, and changes your pointer to point to it. sqlite3_close doesn't change what the pointer points to, so all it needs is the pointer itself.
As usual, the C FAQ List contains relevant information. See I have a function which accepts, and is supposed to initialize, a pointer: and Does C even have "pass by reference"?.
i don't know what you want to do with sqlite function. But using pointers makes you to keep changes in functions.
When you pass a variable to a function, the variable will be duplicated.
for example
int var1=0;
in *ptr1=&var1;
func(var1, ptr1);
the value of var1=5
the adress of var1 = 0xff2200 (something like that)
the value of ptr1 = 0xff2200 (the adress of var1)
the adress of ptr1 = 0xff0022 (something different)
Lets write a function which uses these two var as arg
void func1(int x, int *p){
x+=5;
(*p)-=5;
}
after u use this function;
func(var1, ptr1);
var1 will not equal to 0!!! İt will be -5
Because;
in function func1
the value of x = 0 (the value of var1)
the adress of x = 0xaabbcc (something different then var1!!! this is why x+=5 is not effective on var1. It happens in another part of memory! When u return, this memory will be free again. And you'll lose your changes...)
the adress of p = 0xcccccc (something different too)
the value of p = 0xff2200 (the value of ptr1 and the adress of var1! This operation will be done in the var1's adress so you will not lose your changes)
İf we have to keep our changes of variables -in functions-, we have to use pointers for those var.
İf our variable keep an adress, it means; it is a pointer. And if we want to keep changes of pointer -in functions- then we have to use pointer to pointer.
This is my first message and i hope this will be helpfull...
And "pass by reference" means "pass by pointer" other languages don't use pointers. so you have to pass by reference sometimes. But in C, pointers will do its job...

Resources