This question already has an answer here:
C actions and variables
(1 answer)
Closed 7 years ago.
I have a function f1 which expects void pointer. From the caller I want to have generic logic of passing void pointer to A which modifies the pointer internally.
sample code is pasted below :
#include "stdio.h"
#include "malloc.h"
void f1(void* a)
{
printf("f(a) address = %p \n",a);
a = (void*)(int*)malloc(sizeof(int));
printf("a address = %p \n",a);
*(int*)a = 3;
printf("data = %d\n",*(int*)a);
}
void f(void)
{
void* a1=NULL;
printf("a1 address = %p \n",a1);
f1(a1);
printf("a1 address = %p \n",a1);
printf("Data.a1 = %d\n",*(int*)a1);
}
int main()
{
f();
}
But it causes segmentation fault. Is there any way to make it work without changing prototype of function f1?
C uses pass-by-value for function argument passing. If you have to change the passed variable itself from inside the function, you need to have a pointer to the variable.
In your case, it should be a pointer to pointer.
Otherwise, after the call to f1(a1);, in f(), a is still NULL and dereferencing it invokes undefined behaviour. Segmentation fault is one of the side effects of UB.
That said,
Please see why not to cast the return value of malloc() and family in C.
you don't need #include "malloc.h" to use malloc(), rather use #include <stdlib.h>. It is declared in stdlib.h header file.
You need to modify the pointer, not the ponted to data. So you must pass a pointer to the pointer, like this
void f1(void **a)
{
int *b;
b = malloc(sizeof(*b));
printf("b address = %p \n", b);
if (b != NULL)
{
b[0] = 3;
printf("data = %d\n", *(int *) b);
}
*a = b;
}
The way you do it, the pointer inside f1 is a copy of the passed pointer, they both contain the same initial value NULL, the value you used in f() to initialize a1, but you alter the value of the local pointer only.
You then dereference a1 which is still NULL, and dereferencing a NULL pointer, causes undefined behavior. In your case the behavior is that a segmentation fault happens.
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 3 years ago.
void init(int *a) {
int *b = malloc(sizeof(int));
*b = 4;
a = b;
printf("b address %d\n", b);
printf("a address %d\n", a);
printf("%d\n",*a);
}
int main()
{
int *a = malloc(sizeof(int));
printf("a address %d\n", a);
init(a);
printf("a address %d", a);
return 0;
}
will print the output
a address 32206864
b address 32211008
a address 32211008
4
a address 32206864
Here, the init function is initializing the value for a. However, this is done is incorrect and I am trying to determine why. Observe that once the init function ends the pointer a forgets the address it's supposed to point to. I assume this has something to do with the fact that a is set to b, a pointer that gets popped off the stack once the function ends.
But why does this make sense? Shouldn't a remember what memory address it's been set to? After all, the scope of a is the main function, not the init function.
The a in the function init and the a in main are different objects. The call init(a) only passes the value of a to the function. That value is only a copy of the value in the a in main. The init function does not receive any reference to the a in main.
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
I am attempting to retrieve a pointer via a function in c. If the pointer is a return value from the function then it works. But if I pass the address of the pointer to the function, I can't update the dereferenced pointer value (which should be the address stored in the pointer) from within the function.
Please see the code and the output. Why don't I get the same results with both GetPointer1() and GetPointer2()? What am I missing?
#include <stdio.h>
#include <stdint.h>
uint8_t SrcArray[2][3] = {{11,12,13},{21,22,23}};
uint8_t *p1;
uint8_t *p2;
void GetPointer1(uint8_t *p);
uint8_t* GetPointer2(void);
int main()
{
printf ("&SrcArray[0][0]: %d\n", &SrcArray[0][0]);
GetPointer1(p1);
p2 = GetPointer2();
printf ("p1: %d\n",p1);
printf ("p2: %d\n",p2);
return 0;
}
void GetPointer1(uint8_t *p)
{
p = &SrcArray[0][0];
}
uint8_t* GetPointer2(void)
{
return &SrcArray[0][0];
}
Output:
&SrcArray[0][0]: 6295604
p1: 0
p2: 6295604
That is because the pointer you have in the function signature of GetPointer1(uint8_t *p) is passed by value. If you want to modify the pointer itself, you have to pass a pointer to a pointer:
void GetPointer1(uint8_t **p) {
*p = &SrcArray[0][0];
}
Otherwise, you may modify the piece memory to which the pointer points, but not the pointer itself.
Its is local to function GetPointer1 because it is a local variable which is passed as an value not as an address.
Here is the output details of your code for better understanding
inside main: &SrcArray[0][0]: 6295616
value of pointer p1: 0
address of pointer p1: 6295640
inside GetPointer1: 0
value of pointer p: 0 //which ur taking to a pointer p and modifying p whihc is local to that function.
address of pointer p: 64030024
inside GetPointer1 after assignment:value of pointer p: 6295616
address of pointer p: 64030024
If you want to pass address you need to use & before the variable say &p1.
Also as mentioned in one of the answer by IGarFieldI you can use pointer to a pointer.
void GetPointer1(uint8_t **p) {
*p = &SrcArray[0][0];
}
One more point since P1 is global variable, its accessible to all the functions you can directly use P1=SrcArray; which is allowed and does the same task.
ScrArray is equivalent &ScrArray[][] both gives the address of the array.
You have a variable p1 that is pointing to something. Then you pass it to a function GetPointer1. What happens there is that the value of the variable p1 (this is the address of the value it is pointing to!!!) is copied (!) to the function stack. This means that you can modify the pointed value (*p1), but not the original pointer (p1) itself, as you only have a copy of it. If you want to be able to modify the original pointer, then you have to retrieve the address of the pointer and pass this one to the function, i. e. you need a pointer to the pointer. You get this via the address-of operator &. So you need this:
getPointer1(uint8_t** p) { *p = /*...*/; }
and call it via
getPointer1(&p1);
#include <stdio.h>
#include <stdint.h>
int SrcArray[2][3] = {{11,12,13},{21,22,23}};
int *p1;
int *p2;
void GetPointer1(int **p);
int* GetPointer2(void);
int main()
{
printf ("&SrcArray[0][0]: %d\n", SrcArray[0][0]);
GetPointer1(&p1); /*<-- passing the reference of pointer p1 */
p2 = GetPointer2();
printf ("p1: %d\n",*p1);
printf ("p2: %d\n",*p2);
return 0;
}
void GetPointer1(int **p) /*<-- using double pointer */
{
*p = &SrcArray[0][0];
}
int* GetPointer2(void)
{
return &SrcArray[0][0];
}
o/p
rabi#rabi-VirtualBox:~/rabi/c$ gcc -g stack3.c
rabi#rabi-VirtualBox:~/rabi/c$ ./a.out
&SrcArray[0][0]: 11
p1: 11
p2: 11
rabi#rabi-VirtualBox:~/rabi/c$
" But if I pass the address of the pointer to the function." But you're not passing the address of the pointer, you're passing a copy of the pointer; changing the copy (as you noticed), doesn't change the original. If you actually pass in the &p (address of p) like you intended, you will be able to modify it - I'm unsure of syntax. edit: void GetPointer1(uint8_t **p) maybe?
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.
This question already has an answer here:
Dynamic memory access only works inside function
(1 answer)
Closed 3 years ago.
The following C snippet:
[...]
void f1(void* a){
printf("f(a) address = %p \n",a);
a = (void*)(int*)malloc(sizeof(int));
printf("a address = %p \n",a);
*(int*)a = 3;
printf("data = %d\n",*(int*)a);
}
void f(void){
void* a1=NULL;
printf("a1 address = %p \n",a1);
f1(a1);
printf("a1 address = %p \n",a1);
printf("Data.a1 = %d\n",*(int*)a1);
}
[...]
results in
a1 address = (nil)
f(a) address = (nil)
a address = 0xb3f010
data = 3
a1 address = (nil)
Segmentation fault (core dumped)
Why doesn't a1 keep the address that has been assigned to it in the function?
As this is C, you cannot pass the pointer by reference without passing in a pointer to the pointer (e.g., void ** rather than void * to point to the pointer). You need to return the new pointer. What is happening:
f(a1);
Pushes the value of the pointer (NULL) as the stack parameter value for a. a picks up this value, and then reassigns itself a new value (the malloced address). As it was passed by value, nothing changes for a1.
If this were C++, you could achieve what you want by passing the pointer by reference:
void f(void *&a);
Passing a pointer to a1 to your function, you can't change where a1 points. The pointer is passed by value, so in f1 you're only changing a copy of the address held by a. If you want to change the pointer, i.e. allocate new memory for the pointer passed in, then you'll need to pass a pointer to a pointer:
void f1(void **a)
{
// ...
*a = malloc(sizeof(int));
// ...
To change a variable via a function call, the function needs to have reference semantics with respect to the argument. C doesn't have native reference variables, but can implement reference semantics by means of taking addresses and passing pointers.
Generally:
void mutate_thing(Thing * x) // callee accepts pointer
{
*x = stuff; // callee derefences ("*")
}
int main()
{
Thing y;
mutate_thing(&y); // caller takes address-of ("&")
}
In your case, the Thing is void *:
void f(void ** pv)
{
*pv = malloc(12); // or whatever
}
int main()
{
void * a1;
f(&a1);
}
Based on Kerrek SB's example I came with this to demonstrate void pointer-to-pointer as an argument and how it may be used.
#include <stdio.h>
void test(void ** jeez)
{
*jeez = (void *) (int) 3;
}
int main (int argc, char* argv[])
{
void *a;
test(&a);
int b = *(int *)&a;
printf("value returned = %d\n", b);
return 0;
}