Double Pointers in C and their scope - c

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.

Related

How does malloc work within wrapper function? [duplicate]

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

In the following program the invocation of change_it() seems to have no effect. Please explain and correct the code? [duplicate]

This question already has answers here:
How to change a variable in a calling function from a called function? [duplicate]
(3 answers)
Closed 4 years ago.
void change_it(int[]);
int main()
{
int a[5],*p=1;
void change_it(int[]);
printf("p has the value %u \n",(int)p);
change_it(a);
p=a;
printf("p has the value %u \n",(int)p);
return 0;
}
void change_it(int[]) {
int i=777, *q=&i;
a = q; // a is assigned a different value
}
For starters, when you initialize p, you're giving a pointer the value of 1, when it needs a memory location. NULL uses 0, but that doesn't mean you can -or should- just assign integer values to pointers.
Just as an fyi, you can cast the value of 1 like this:
int a[5], *p = (int *) 1;
There's like -2 reasons for doing this, though, the -1th reason being that the minimal type safety that C provides should be respected, and the -2th being that it makes the code hard to understand for other people.
I'm going to assume what you meant to do was not declare a pointer with an address value of 1 though, and say you meant to declare a pointer that holds a value of 1. Unless you have another variable that holds the value of 1 already, you're going to have to first dynamically allocate the pointer, then set its value.
int* p = malloc(sizeof(int));
*p = 1;
If you had another variable to use, you could instead create the pointer on the stack rather than dynamically allocating it, like this:
int* q;
q = p;
Now, calling the same print function on both would yield this:
printf("p has the value %d\n", *p);
printf("q has the value %d\n", *q);
Output:
p has the value 1
q has the value 1
Addressing your main problem, you need to name the parameter in the change_it function, for example:
void change_it(int arr[])
Your program needs the parameter to be named, otherwise it has no idea of knowing you're trying to reference the array. The a variable you reference in the function is not bound to anything; the compiler will know be able to deduce what you're talking about.
Also, you don't need to redeclare the function prototype in your main function. The reason this is not a compiler error is that you can have as many declarations as you want, but only one definition. Again though, there's no reason to do this.
Another fyi, you don't have to name the parameters in your function prototypes, but it's good practice to both name them and be consistent with the names between the prototypes and the actual implementations so that people reading your code understand what's going on.
Also, you're using the %u specifier for the printf function, when you're not actually using unsigned decimal numbers. You're using signed decimals so you should use %d.
Lastly, your change_it function commits one crucial error preventing it from correctly changing the value of the passed-in array properly: you're setting the array that you passed in to the value of q.
Look at the function in your original code closely (pretend you named the input array a, as it looks like you mean to). You first declare an integer variable i and set its value to 777. Then, you create an integer-pointer variable q on the stack and correctly set its value to i. Note: You're not setting q to the value of i, but rather the address of i.
Why does this small but significant distinction matter? When you set a to q in the next line, you're changing the address of the array, specifically the first element of a five-element integer array, to point to the address of an integer variable. This is bad for a few reasons. First, the array is five integers long, but now it points to a single element. If and when you try to access elements 2-5, you'll get either meaningless garbage or a segmentation fault for trying to access memory you don't own. Even worse, the variable i is allocated on the stack, so when the function change_it exists, the function's data will be popped off the stack, and trying to access the address of i will yield either garbage or a segmentation fault for trying to access memory you don't own. See a pattern?
I'm not really sure how to correct this code, as I'm not sure what you were trying to accomplish, but correcting the aforementioned errors, your code now looks something like this:
#include <stdio.h>
void change_it(int arr[]);
int main()
{
int a[5];
int *p = a; // Equivalent to int *p = &a[0];
printf("a address: %p\n", a); // Should be equal to p
printf("p address: %p\n", p); // Should be equal to a
a[0] = 1;
printf("a[0] = %d\n", a[0]); // 1
printf("p has the value %d\n", *p); // 1
change_it(a);
p = a;
printf("a address: %p\n", a);
printf("p address: %p\n", p);
printf("a[0] = %d\n", a[0]);
printf("p has the value %d \n", *p);
return 0;
}
void change_it(int arr[])
{
int i=777;
arr[0] = i;
// Could be just:
// arr[0] = 777;
}
Output:
p address: 0x7fffc951e0b0
a[0] = 1
p has the value 1
a address: 0x7fffc951e0b0
p address: 0x7fffc951e0b0
a[0] = 777
p has the value 777
Note: Your memory address can and probably will be different from these, all it matters is that p and a are equal in both.
Anyways, hope this helps. Let me know if you have any questions.
Alright, you I believe do not have basic understanding of a function: First lets start with declaration and definition:
void change_it(int[]); // THIS IS DECLARATION
int main ()
{
void change_it(int[]); // THIS IS DECLARATION (duplicate and unnecessary
....
}
void change_it(int[] a) // THIS IS DEFINITION
{
int i=777, *q=&i;
a = q; // a is assigned a different value
}
declaration of the function only needs (you can put parameter name for readability) a parameter type, where as definition has to have name of the parameter because in definition parameters are local variables.
printf("p has the value %u \n",(int)p);
This will print the address of p not the value of p. So this should be
printf("p has the value %u \n", *p);
And finally we get to the body of a function. Where you are depending on somthing that have been locally assigned and putting it back into parameters
void change_it(int[] a)
{
int i=777, *q=&i;
a = q; // a is assigned a different value
}
so q is pointer and you are assigning address of local variable i to it. Well what happens when your program exists the function? i might disappear thus loosing its values and its address, which is assigned to q which means q is loosing its variable and value, and which is assigned to a which might loos its variable because it is pointing to i in your function.
This part here:
int a[5],*p=1;
void change_it(int[]); // Here, doesn't compile
printf("p has the value %u \n",(int)p);
That statement isn't just valid, as far as I know, you can't declare a function inside another function in C.
Also:
void change_it(int[]) // Here, an error
{
int i = 777, *q = &i;
a = q;
}
This function needs an argument, but you supplied only its type (being int[]),
void change_it(int a[]) fixes the problem
Your program does not compile and produce warnings. It would not work as you intended.
1) p is a pointer. To access value which it points to you have to dereference it using * dereference opearator.
2)
void change_it(int[]);
is not needed in the body of main.
3)
the invocation of change_it() seems to have no effect
If you want to change a[0] element inside the function change_it name the passing parameter to a and dereference the q pointer,
The working program may look as this:
#include <stdio.h>
void change_it(int a[]);
int main()
{
int a[5] = {0}; // init all element of `a` to `0`
int *p; // declare int pointer
p = a; // p point to array `a`
// print the first element of array `a`
printf("a[0] has the value %d \n",(int)*p);
// call function change_it, pass `a` as the argument
change_it(a);
printf("a[0] has the value %d \n",(int)*p);
return 0;
}
// change the value of the first element of array `a` to 777
void change_it(int a[]) {
int i=777, *q; // declare int i and pointer
q = &i; // pointer `q` points to the `i` now
a[0] = *q; // a[0] is assigned value = 777;
}
Output:
a[0] has the value 0
a[0] has the value 777

If p is a pointer to int where would one use &p

In the following code p is pointer to an int. It is quite clear that p points to the address of i. Through my research i know &p points to the address of pointer p. But i don't get why would you need separate address for that. And also when would you use &p.
int main() {
int i = 3, *p = &i;
printf("%p",&p);
printf("%p",p);
return 0;
}
If p is pointer to int then
int **q = &p;
When you want to use pointer to pointer, then use the address of a single pointer to assign it to pointer to pointer.
Just to make a point that pointer is also a data-type and it stored in the memory location and it holds a valid memory location as its value. The address in which this valid memory location is stored is given by &p
Your printf() also needs to be fixed. %p expects void *
printf("%p",(void *)p);
But i don't get why would you need separate address for that
You don't, but there exists the address of operator so you can take the address of a pointer, which is what
printf("%p\n", &p);
is printing.
And also when would you use &p
There are cases where this might be useful, consider for example that you need to pass a pointer to a function which could be reassigned into the function, you can do something like this
int allocateIntegerArray(int **pointerToPointer, size_t someSize)
{
if (pointerToPointer == NULL)
return 0;
*pointerToPointer = malloc(someSize * sizeof(int));
return (*pointerToPointer != NULL);
}
then you could use this funciton the following way
int *pointer;
if (allocateIntergerArray(&pointer, 10) == 0)
{
fprintf(stderr, "Error, cannot allocate integer array\n");
/* do some extra cleanup or recover from this error, or exit() */
exit(0);
}
The pointers themselves are also variables and as such they need to be sotred somewhere, so the address of a pointer tells you where is the pointer stored, it's value tells you where it is pointing to.
By knowing where it is stored you can do things like the one explained above.
A trivial example:
int nochange(int *c, int *val)
{
c = val; // Changes local pointer c to point to val
// Note that C passes copies of the arguments, not actual references.
}
int do_change(int **c, int *val)
{
*c = val; // Accesses the real pointer c at its real location and makes
// that one point to val
// Even though c is a pointer-to-pointer copy, its value is
// copied too, and the value is the address of the real c
}
int main()
{
int a = 1;
int b = 2;
int *c = &a; // A pointer is also a datatype that resides in memory
printf("%d\n", *c); // Will print 1
nochange(c, &b);
printf("%d\n", *c); // Will print 1
do_change(&c, &b);
printf("%d\n", *c); // Will print 2 because c now points to b
}
I have a similar answer with a bit more detail here about pointer vs pointer-to-pointer: pointer of a pointer in linked list append

Passing address, but it is working like call by value in C?

Hello I am a beginner in C programming language. Recently I read about call by value and call by address. I have learned that in call by address changes in the called functions reflects the callee. However the following code does not work like that.
int x = 10,y = 20;
void change_by_add(int *ptr) {
ptr = &y;
printf("\n Inside change_by_add\t %d",*ptr);
// here *ptr is printing 20
}
void main(){
int *p;
p = &x;
change_by_add(p);
printf("\nInside main\t %d", *p);
// here *p is still pointing to address of x and printing 10
}
When I am passing address then why the changes made by called function does not reflect caller?
The function is assigning a new address to the pointer but the pointer itself is being passed by value, as all arguments are in C. To change the value of a pointer variable the address of the pointer itself must be passed:
void change_by_add(int **ptr)
{
*ptr = &y;
}
change_by_add(&p);
See C FAQ Question 4.8.
Passing by reference does not exist in C but can be achieved by passing the address of the variable who's value is to be changed to a function. For example:
void add_to_int(int* a_value, int a_increment)
{
*a_value += a_increment;
}
You are simply setting the value of the pointer in the function, not the value of the pointed to variable. The function should use the following code:
*ptr = y;
This derefences the pointer (exposing the value pointed to), and therefore when you use the equals operator, the memory pointed at is modified, not the pointer itself. I hope this helps to clarify things.
Changes made by called function does not get reflected by the caller because you are overriding the pointer address in the called function i.e ptr = &y;.
Initially, you passed the address of x but you are changing it with the address of y.
If you really want to implement the concept of call by address then change value instead of address.
Example:
void change_by_add(int *ptr) {
*ptr = y; //changing value
printf("\nInside change_by_add\t %d",*ptr);
}
void main(){
int *p;
p = &x;
change_by_add(p);
printf("\nInside main\t %d \n", *p);
return 0;
}
Output
Inside change_by_add 20
Inside main 20
There is no such thing as call by address in C. There is only call by value. What one does when a function needs to modify an argument in a way that is visible to the caller is to have the caller pass a pointer to something, and have the called function write the update though that pointer. Note that the pointer itself is still sent as call-by-value - that is: the called function gets its own copy of the pointer and could change it to point to anything else if it wants to.

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