I have been trying to create a pointer variable in the called function and somehow pass the value pointed by it to the main function. I wrote a few sample programs but it i still seem to be missing something out. and the challenge was to achieve this using pointers to pointers to pointers. Here is the code that I wrote and tested. I think am missing something obvious, can you guys point it. Thanks.
int one(int ***ptr)
{
static int *p,**pp,b=10;
p=&b;
pp=&p;
ptr=&pp;
printf("b:%d\tp:%d\tpp:%d\n",b,*p,**pp);
printf("Sub Ptr:%d\n",***ptr);
printf("Address of ***ptr:%d\n",&ptr);
return 32;
}
int main(int argc, char *argv[])
{
static int ***ptr;
int a=200,*b,**c;
b=&a;
c=&b;
ptr=&c;
printf("Main Ptr:%d\n",&ptr);
a=one(ptr);
printf("Main Ptr:%d\n",&ptr);
printf("Main Ptr:%d\n",***ptr);
system("PAUSE");
return 0;
}
I get an output of 32 which is the return value of the function. Is it possible to get the value of 10 which is pointed in the called function.
I also tried global declaration but din work either. I would like to maintain the local declaration and see if its possible...
I think you misunderstood about pointers. The problem of your code is that you didn't realize that pointer is also "pass by value", the pointer in the function is another variable on the stack, instead of the one you declare in the main function.
I would use a more simple example, but the idea is the same.
void changePointerValue (int * ptr)
{
int newValue = 10;
ptr = &newValue;
}
int main ()
{
int x = 20;
int * ptr = &x;
changePointerValue (ptr);
printf ("After Change: %d\n", *ptr);
}
What value do you think it will output in main function? Is that be 10?
But no, in fact, it will output 20.
Why? Let's look what our code does. In the line of chagePointerValue(ptr), the computer copy the value of ptr in the main function to a new varaible on stack, let's call it ptr' and pass it to the changePointerValue function.
So in fact the ptr in the changePointerValue function is ptr', not the one you declare in the main function. The second line of changePointerValue, you assigned a new memory address to ptr', and after that, ptr' is discarded because the function is returned. The ptr in the main function remains the same value, which is the memory address pointed to x.
If you want the output to be 10, you need deference ptr in the changePointerValue, and the assignement will means 'Change the value where the ptr is pointed at'.
void changePointerValue (int * ptr)
{
int newValue = 10;
*ptr = newValue; // Now you are change the content of the memroy cell where ptr is pointed at.
}
int main ()
{
int x = 20;
int * ptr = &a;
printf ("Before Change:%d", x); // 20
printf ("Before Change:%d", *ptr); // 20
changePointerValue (ptr);
printf ("After Change: %d\n", *ptr); // 10
printf ("After Change: %d\n", x); //10
}
Edit:
So, if you want it print 10 in the main function, the correct way to do this is deference ptr in the function. But this will also change the value of variable a in the main function.
int one(int ***ptr)
{
***ptr=10; // Dereference ptr to where it points to. (Varaible a in the main function)
return 32;
}
int main(int argc, char *argv[])
{
static int ***ptr;
int a=200,*b,**c;
int result;
b=&a;
c=&b;
ptr=&c;
printf("Main Ptr:%d\n",&ptr); // The memory address of variable ptr.
result=one(ptr);
printf("Main Ptr:%d\n",&ptr); // the memory address of variable ptr.
printf("Main Ptr:%d\n",***ptr); // 10
printf("Main a:%d\n", a); // 10
printf("Main result:%d\n", result); //32
system("PAUSE");
return 0;
}
You're setting ptr to the address-of-the-address-of-the-address-of a local variable (b), which goes out of scope at the end of the function. This is undefined behaviour. You either need to assign to ***ptr, or malloc something on the heap.
Also, you're passing ptr by value to the function. So any local modifications to it won't be reflected in main. You need to pass by pointer, i.e. you'll need an int **** as an argument.
I really hope this is nothing more than a learning exercise, because any more than two levels of pointers usually indicates that the design really needs to be re-evaluated!
Related
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.)
I noticed that my pointer address is different when it is passed to a function. U am not sure to access the value that exists inside the function? Please don't suggest returning the pointer value from the function. I strictly want to use void function.
output:
&nPtr = 6422300
&Ptr = 6422272
&nPtr = 6422300
See the below code:
#include<stdio.h>
void myFunc(int *Ptr){
printf("&Ptr = %d\n", &Ptr);
};
void main(){
int *nPtr;
printf("&nPtr = %d\n", &nPtr);
myFunc(nPtr);
printf("&nPtr = %d\n", &nPtr);
}
Let me be more clear. Here is the code that I am trying to fix. All what I want is to make the two pointers point to the same address. I want to use the best coding practice.
#include<stdlib.h>
#include<stdio.h>
void myFunc(int *Ptr){
Ptr = malloc(10*sizeof(int));
printf("*Ptr = %d\n", *Ptr);
};
void main(){
int *nPtr;
printf("*nPtr = %d\n", *nPtr);
myFunc(nPtr);
printf("*nPtr = %d\n", *nPtr);
}
In main(), you're getting the address of nPtr in main()'s stack frame; in myFunc(), you're getting the address of the copy of nPtr that is being passed by value to myFunc() as Ptr (so you're actually getting the address of Ptr, which is distinct) and exists on myFunc()'s stack frame.
nPtr and Ptr are separate variables in separate functions, and as such each must necessarily have a different address, i.e. &nPtr == &Ptr will always be false.
But you asked about nPtr == Ptr, i.e. can they contain the same value, and as pointers they can both contain the same pointer value. For example:
#include<stdio.h>
void myFunc(int *Ptr){
printf("Ptr = %p\n", (void *)Ptr);
};
int main(){
int x;
int *nPtr = &x;
printf("nPtr = %p\n", (void *)nPtr);
myFunc(nPtr);
printf("nPtr = %p\n", (void *)nPtr);
}
Output:
nPtr = 0x7ffe9a615104
Ptr = 0x7ffe9a615104
nPtr = 0x7ffe9a615104
For this function
void myFunc(int *Ptr){
printf("&Ptr = %d\n", &Ptr);
};
when you call it, although you are passing a pointer (which is for pointing to an integer) to this function , the system is creating a copy of the pointer and of course they will be at different memory address.
Hence when you return back to the main and retrieve your original pointer address, it will be displaying back the original address
Why in this code the pointer shifts to another location:
#include <stdio.h>
void f(int *p)
{
int j=2;
p=&j;
printf("%d\n%p\n%d\n",*p,&j,p);
}
int main(void)
{
int *q;
int m=98;
q=&m;
f(q);
printf("%p ",q);
return 0;
}
Output:
2
0x7ffff5bf1bcc
0x7ffff5bf1bcc
0x7ffff5bf1bc8
I understand that when the function f() is done with printing value of j and address of j the memory occupied by j goes back to the stack but IMO p should continue pointing that location even after the function is over & it should be printing the same address in main as well. What is wrong with this?
Considering you meant printf("%p ", (void *)q); in the actual code,
No, function argument(s) in C is (are) passed by value. It won't reflect the changes made to the parameter into the actual arguments used (in function call) themselves.
To put it into other words, the function parameters are local to the function (call) scope, any changes made to them won't be reflected to the actual arguments.
So, if you need to change a pointer, you need to pass a pointer to the pointer which needs to be changed.
Consider a rather light-hearted but realistic scenario.
void f (int x) { x = 10; }
int main(void) { f(5); printf ("%d", 5); return 0;}
Now, do you expect it to print 10?
That said, an advice. Always cast the argument to %p conversion specifier to (void *) (if it is not already). printf() is a variadic function and for pointers, no default argument promotion happens, so the supplied argument type needs to match the expected type, explicitly. Otherwise, technically it is undefined behavior.
Learn the difference between Pointers and Pointers to pointers - the pointer passed p is no doubt good to change the value of the variable it is pointing to (m), but to change the memory location it is pointing to - you need a pointer to pointer.
Expanding on top of what #SouravGhosh said, when you pass in a pointer to an int you are making a copy of the pointer. If you wanted to change the pointer you need to be doubly indirect and pass in a pointer to a pointer to an int. The first pointer is copied and you can directly affect the second pointer.
void f(int ** p)
{
int j = 2;
*p = &j;
printf("%d\n%p\n%p\n",*p,&j,p);
}
int main(void)
{
int ** q = (int **)malloc( izeof(int *));
int m = 98;
*q = &m;
f(q);
printf("%p ",q);
free(q);
return 0;
}
And the output is
2
0xffffcbcc
0xffffcbcc
0xffffcbcc
If you do this you'll see that it never changes:
#include <iostream>
#include "Header2.h"
#include "header1.h"
#include <stdio.h>
void f(int *p)
{
int j = 2;
p = &j;
printf("%d\n%p\n%p\n", *p, &j, p);
}
int main(void)
{
int *q;
int m = 98;
q = &m;
printf("Value of pointer q before calling f() =%p ", q);
f(q);
printf("Value of pointer q after calling f() =%p ", q);
return 0;
}
what's happening after clrscr?
#include<stdio.h>
#include<conio.h>
int *call();
void main()
{
int *ptr;
ptr=call();
clrscr();
printf("%d",*ptr);
getch();
}
int*call()
{
int a=25;
a++;
return &a;
}
output:
-10
code works like this:
call() is called, a=25, then a=26. let address of a be 65518. this address is returned to ptr. since return type is int, instead of 65518, (due to cyclic property) -18 is returned.
so ptr=&a=-18. then clrscr clears it....but how *ptr is printed as output? i mean address cannot be negative(-18).
Returning a pointer to local is undefined behavior. Anything could happen - your program could crash, but more likely it is going to print some arbitrary number.
If you need to return a pointer from a C function, you need to either allocate a memory block in the dynamic storage, like this:
int*call()
{
int *a=malloc(sizeof(int));
*a = 25;
*a++;
return a;
}
or use a pointer to a statically allocated block, like this:
int* call()
{
static int a=25;
a++;
return &a;
}
If you choose the dynamic allocation route, the caller must free the pointer returned by your function.
int*call()
{
int a=25; // <--- use malloc here i.e. int a = malloc(sizeof(int)); then you can set a value to a and return the pointer without any problemk, OTHERWISE => it will return an address of some random junks you don't want, its gonna be completely random
a++;
return &a;
}
When call() is called, a new stack frame is created with space for the local variable a, which has its lifetime during the execution of call(). When it returns, the stack frame is removed along with its local variable(s) and data. Trying to use this data outside the function is undefined, because it no longer exists, logically.
If you want to declare a inside a function and use it afterwards, you'll need to allocate it:
...
int *a = malloc(sizeof int);
*a = 26;
return a;
...
Remember to free() this pointer after you're finished using it.
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.