Setting NULL to struct pointer, but never NULL when checked - c

Given, in the function called,
void callFunct1 (arg_t *q) {
q = NULL;
};
EXPORT_SYMBOL(callFunct1);
returns a null.
Why is the reason that in another function, q is never NULL? How can I correct it?
arg_t qH;
arg_t* q;
//
callFunct1 (&qH);
q = &qH;
if (q == NULL) {
.....
}
arg_t is just a struct.

Pointers are no different than any other non-array variable in C. When passed as a parameter, if you want to modify something as in/out, you have to pass by address. Declare the parameter to be a formal pointer-to-the-type and pass the address of the entity from the caller, using the dereference operator * to access the caller's value.
Just as this:
void foo(int *p)
{
*p = 5;
}
is invoked like this:
int x;
foo(&x); // x will be 5 on return
So it is with pointer-types as well. If you want to modify the pointer by address then the address is precisely what is needed. Declare the parameter as a pointer-to-pointer-to-arg_t and dereference it to set the referenced pointer to NULL:
void foo(arg_t** pp)
{
*pp = NULL;
}
and
arg_t *p;
foo(&p); // p will be NULL on return

void callFunct1 (arg_t *q)
returns nothing as its return type is declared void.
Its argument q is a copy of the value passed as parameter when callFunc1 is called, and this copy lives on callFunc1's stack for as long as callFunc1 runs.
So this line
q = NULL;
assigns NULL to the q existing only locally to callFunc1.

That function returns nothing. You pass a pointer to a struct. That pointer is a copy of the passed pointer, it is not the same variable as in main.
This is what goes on between the lines: if we have a caller like the code below
int main()
{
arg_t some_struct;
arg_t* some_ptr = &some_struct;
callFunct1 (some_ptr)
}
then upon calling callFunct1
some_ptr points at some_struct.
The function parameter arg_t* q is allocated on the stack.
The contents of some_ptr is copied into q.
Both some_ptr and q now point at some_struct.
Then you set q to point to NULL.
Then the function ends. q ceases to exist.
As you have not changed some_ptr, it still points at some_struct.
Now if you had not set some_ptr to point at anything, it would have contained any garbage value. When making a debug build of your program, variables are likely set to NULL by default, but there are absolutely no guarantees for this!
So if some_ptr was uninitialized and happened to contain the value NULL when you called the function, it might have appeared as if you successfully set it to NULL. But in reality, you were just plain lucky that your uninitialized variable contained that value.
To actually set the variable in main to point at NULL, you would have to do
arg_t callFunct1 (void) {
return NULL;
};
arg_t* some_ptr;
some_ptr = callFunct1 ();

Related

Unable to dereference double pointer in c

The output of this code is 20 20 10. The first 20 is easy to understand. But I am unable to understand how function change1 and change2 are accessing the variable b.
#include<stdio.h>
int a = 5, b = 10;
void change1(int *p);
void change2(int **pp);
main( )
{
int x=20, *ptr=&x;
printf("%d ",*ptr);
change1(ptr);
printf("%d ",*ptr);
change2(&ptr);
printf("%d\n",*ptr);
}
void change1(int *p)
{
p = &a;
}
void change2(int **pp)
{
*pp = &b;
}
But I am unable to understand how function change1 and change2 are accessing the variable b.
There is a misunderstanding of what change1 does.
It changes where p points to but that change is local to the function. It does not change where ptr points to in main since the pointer is passed by value. change1 does not have any code that accesses the variable b. It's not clear to me whey you think it does.
In change2, you are changing where the pointer points to, to b. The change affects where ptr points to in main since you are passing the address of ptr to change2 and you are changing where that dereferenced pointer points to.
In change1, p is a pointer to int that is passed by value. Assigning a value to p in change1 therefore has no effect because p is local to change1. This is the reason for the 2nd 20.
In change2, pp is a pointer to a pointer to int. It too is passed by value, but this time dereferencing pp (*pp) gives access to the location of the pointer (ptr), and it is into this location that the address of b (&b) is stored.
void change1(int *p)
{
p = &a;
}
The variable p is assigned with the address of a, but this is only valid within the function. p acts as a local variable within the function change1. After this function terminates, the pointer ptr would still be pointing at x(=20). This is the reason behind the second 20.
void change2(int **pp)
{
*pp = &b;
}
But this, is one of the correct ways to make changes to a pointer variable within the function so that it would still be valid outside. pp acts as a pointer pointing to the original ptr variable. As a result, ptr will end up pointing at b(=10) after change 2 terminates. This is the reason behind your third 10.
When you invoke change1() function, you're passing the pointer ptr as an argument. Let's suppose ptr = 0xcafebabe, and obviously *ptr = 20. Under the hood, you're writing the value 0xcafebabe on the stack, and the change1() function will only overwrite this value with &a on the stack frame corresponding to this function.
In the second case, you're passing a pointer to ptr as an argument. Let's suppose this pointer new_ptr has a value of 0xdeadbeef. In this case, *new_ptr = 0xcafebabe and you overwrite 0xcafebabe with &b (hence you are changing where the pointer is pointing.

Double Pointers in C and their scope

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

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 pointer vs single pointer

Can someone explain / give a reasoning to me on why the value of variable i in main function in below code snippet does not change via function test1 while it does change via test2? I think a single pointer should be sufficient to change the value of i. Why are we supposed to use double pointer?
#include <stdio.h>
void test1(int* pp)
{
int myVar = 9999;
pp = &myVar;
}
void test2(int** pp)
{
int myVar = 9999;
*pp = &myVar;
}
int main()
{
printf("Hej\n");
int i=1234;
int* p1;
p1 = &i;
test1(p1);
printf("does not change..., p1=%d\n",*p1);
test2(&p1);
printf("changes..., p1=%d\n",*p1);
return 0;
}
In C parameters are passed by value. This means that in test1 when you pass pp a copy is made of the pointer and when you change it the change is made to the copy not the pointer itself. With test2 the copy is of a double pointer but when you dereference and assign here
*pp = &myVar;
you are changing what is being pointed to, not changing pp itself. Take note that this behaviour in test2 is undefined as is documented in some of the other answers here
But you're not changing the value of i, you're changing the address that pp points to, if you only want to change the value of i then it's enough to change your test to:
void test3(int* pp)
{
int myVar = 9999;
*pp = myVar;
}
If you want to change the value of a variable of type T you have to use a pointer on that type (T*). Since you want to change a pointer (T = int*), you have to provide a pointer to a pointer (T* = int**), otherwise you're only going to change the copy.
Note that
int myVar = 9999;
*pp = &myVar;
will result in undefined behavior, since pp will now contain the address of a local variable which isn't valid after you exit the function.
Because f(x) can't change the value of x, no matter whether x is an int, a float, or a pointer.
void test1(int* pp)
{
int myVar = 9999;
pp = &myVar;
}
This function is passed a pointer pp. The function modifies that pointer. But since parameters are passed by value, that modification is not seen by the caller.
You need to write the function like this:
void test1(int* pp)
{
*pp = 9999;
}
The caller of this function is expected to pass the address of an int variable. The function then writes an int value, 9999 in this case, to that address. This is the key. You are passed an address, and you then write a value to that address. Your broken version simply modified the address. You were missing the indirection.
When the function returns, the caller can observe the modification to the int variable whose address was passed to the function. The calling code can look like this:
int i = 0;
test1(&i); // pass address of int variable
printf("%d\n", i); // prints the new value, 9999
void test2(int** pp)
{
int myVar = 9999;
*pp = &myVar;
}
Now, this is broken in a very serious way. This function does indeed return a pointer to the caller. But it returns a pointer to an object that goes out of scope as soon as the function returns. That is known as undefined behaviour. Don't do this. Never pass out of a function, a pointer to a local variable defined in that function.
pp = &myVar; assigns the address of myVar to the pointer pp. If you want to change the value that pp points to, use
*pp = myVar;
instead.
In answer to your second question, pass a pointer to a pointer when you want to change the object pointed to rather than changing the value of your existing object.
int* p1;
p1 = &i;
test1(p1); //1st
test2(&p1); //2nd
In simple way , 1st is pass by value and 2nd is pass by address.
Description :
In first case it passing pointer is actually the copy of that p inside test1 so the pp inside test1 is the local to that function and it's created in test1. You assigned the address and when comes out of function it's destroyed.
But in second case you are passing the address of the pointer to test2 function. So the pointer pp in test2 will point to the pointer p in main so assigning a new address to pp using *pp = &myVar will automatically set the value of p(since you are dereferencing the pointer). Hence when test2 terminates still p will point to modified location.

why does this function return garbage value

I was writing a program and facing this problem that the following function used to return garbage values:
int* foo(int temp){
int x = temp;
return &x;
}
When I modified it to this, it worked fine:
int* foo(int *temp){
int *x = temp;
return x
}
What was wrong with the first version?
The first version returns a reference to a local variable x whose storage is limited to the function foo. When the function exits, x can no longer be used. Returning a reference to it is one instance of a dangling pointer.
In the second version, you're really only passing in and returning the same pointer value, which refers to memory which isn't limited by the lifetime of the function. So even after the function exits, the returned address is still valid.
Another alternative:
int *foo(int temp)
{
int *x = malloc(sizeof(int));
*x = temp;
return x;
}
For each function there will be an activation record, which will be created in stack once the execution of that function starts. Activation record holds all the local variables also. And this activation record will be freed once the function execution finishes.
So if we return an address of a local variable means, that will be freed memory of previous function`s activation record. Dereferencing that memrory is an undefined behaviour.
In the below case, function foo is returning the &x that means p will holds the address of func's local variable x. This is valid. But if function func tries to retrun p(address of x) which is not valid.
int* func
{
int x;
int *p;
...
p = foo(&x);
//using p is valid here
...
return p; //This is invalid
}
int* foo(int *temp)
{
int *x = temp;
return x //This is valid
}
In the below case, funciton foo is returning address of its local variable x to function func. So p will holds address of foo's local variable. So deferencing p is invalid because foo functions execution has been completed and its activation record is freed.
int* func
{
int x;
int *p;
...
p = foo(x);
//using p is invalid here
...
return p; //This is invalid
}
int* foo(int temp)
{
int x = temp;
return &x; //This is also invalid
}

Resources