Function scope and Pointers [duplicate] - c

This question already has answers here:
Changing address contained by pointer using function
(5 answers)
Passing pointer to function value not changing [duplicate]
(4 answers)
Closed 1 year ago.
I don't understand the behavior of this program.
By my understanding, pointer in main() should have the original address of the local variable that is, now, destroyed. Because pointer was assigned the valid address at that point.
It should just keep that address. Why is it losing that?
Here's the program
#include <stdio.h>
void fun(int* ptr)
{
int a = 5;
ptr = &a;
printf("address: %p, value: %d\n", &a, a);
// address: 0x7fff1aa00374, value: 5
printf("address: %p, value: %d\n", ptr, *ptr);
// address: 0x7fff1aa00374, value: 5
}
int main(void)
{
int* ptr = NULL;
fun(ptr);
printf("address: %p\n", ptr);
// address: (nil)
printf("address: %p\tvalue: %d\n", ptr, *ptr);
// Segmentation fault (core dumped)
return 0;
}
GCC Version
gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0

Here is a modified example:
#include <stdio.h>
void fun(int p)
{
p = 5;
printf("value: %d\n", p);
}
int main(void)
{
int p = 0;
fun(p);
printf("value: %d\n", p);
return 0;
}
If you understand why this modified example prints 5 then 0, then you also understand why your pointer version doesn't work either. Because pointers too are passed by value.
If you don't understand why this prints 5 then 0, then you need to read a beginner-level C book, functions chapter.

For better understanding of what's happening here, renaming the ptr parameter of fun() function to fun_ptr
void fun(int* fun_ptr)
^^^^^^^
When you call fun() function
int* ptr = NULL;
fun(ptr);
the value of argument ptr will be assigned to fun() function parameter fun_ptr. Its similar to this
fun_ptr = ptr;
ptr is NULL, so the fun_ptr will be assigned NULL. Whatever changes you do in fun_ptr inside fun() function will stay within fun() function block because the scope of identifier within the list of parameter declarations in a function definition has block scope which terminate when function returns.
If you want to make changes to a pointer variable in another function, you have to pass the address of that pointer variable to the calling function. In context of your program, it should be
void fun(int** ptr) {
int a = 5;
*ptr = &a;
// *ptr will be the pointer passed as argument i.e. assign anything
// to *ptr means you are making changes to pointer passed as argument
.....
.....
}
int main(void)
{
int* ptr = NULL;
fun(&ptr);
.....
.....
return 0;
}
Even after making these changes your program will have Undefined Behaviour because it is accessing address of local variable outside of its scope. Variable a is a local(automatic) non-static variable and its lifetime is limited to its scope i.e. the block in which it has been declared. Any attempt to access it outside of its lifetime lead to undefined behaviour.
To resolve this, allocate memory to pointer ptr and assign the value of a to it. Or, you can declare a as static variable. The lifetime of a static variable is entire run of the program. You can do:
#include <stdio.h>
#include <stdlib.h>
void fun1 (int** ptr) {
static int a = 5;
*ptr = &a;
printf("fun1(): address: %p, value: %d\n", (void *)&a, a);
printf("fun1(): address: %p, value: %d\n", (void *)*ptr, **ptr);
}
void fun2 (int** ptr) {
int a = 5;
*ptr = malloc (sizeof (int));
if (*ptr == NULL) {
fprintf (stderr, "Failed to allocate memory\n");
exit (EXIT_FAILURE);
}
**ptr = a;
printf("fun2(): address: %p, value: %d\n", (void *)&a, a);
printf("fun2(): address: %p, value: %d\n", (void *)*ptr, **ptr);
}
int main (void) {
int* ptr1 = NULL;
int* ptr2 = NULL;
fun1(&ptr1);
printf("main(): address: %p\n", (void *)ptr1);
printf("main(): address: %p, value: %d\n", (void *)ptr1, *ptr1);
fun2(&ptr2);
printf("main(): address: %p\n", (void *)ptr2);
printf("main(): address: %p, value: %d\n", (void *)ptr2, *ptr2);
// Once done with dynamic allocated memory, release it
free(ptr2);
return 0;
}

This is because you are passing by value, just like passing an integer, char, etc. You cannot change a parameter passed by value. In this case, the value is the address. To actually change the address of ptr would require passing a passing a double pointer (int **ptr), but that would require more changes to your code.

Related

Index of pointer

In the code below I set the variable var to 20, then the pointer ptr to the address of var. Then the pointer ptrptr to hold the memory address of the pointer ptr.
#include <stdio.h>
void pointers()
{
int var = 20;
int* ptr;
ptr = &var;
int *ptrptr = ptr;
printf("Value at ptrptr[0] = %d \n", ptrptr[0]);
}
// Driver program
int main()
{
pointers();
return 0;
}
Output:
Value at ptrptr[0] = 20
Why does ptrptr[0] return the value stored by val, and not the memory address of the pointer ptr.
I thought that the indexing operator [] returns the value stored by that value.
Here is an example which will, I hope, make it more clear what's going on.
#include <stdio.h>
int main()
{
int var = 20;
int *ptr = &var;
int *ptr2 = ptr;
printf("the value of the variable var is %d\n", var);
printf("the address of the variable var is %p\n\n", &var);
printf("the value of the pointer ptr is %p\n", ptr);
printf("the value pointed to by ptr is %d\n", *ptr);
printf("or, stated another way, it's %d\n\n", ptr[0]);
printf("the value of the pointer ptr2 is %p\n", ptr2);
printf("the value pointed to by ptr2 is %d\n", *ptr2);
}
On my machine this prints:
the value of the variable var is 20
the address of the variable var is 0x7ffeed56992c
the value of the pointer ptr is 0x7ffeed56992c
the value pointed to by ptr is 20
or, stated another way, it's 20
the value of the pointer ptr2 is 0x7ffeed56992c
the value pointed to by ptr2 is 20
Since ptr and ptr2 have the same type (int *), and since they hold the same pointer value (since we said ptr2 = ptr), they behave the same.
And because of the "correspondence between arrays and pointers" in C, *ptr is identical to ptr[0]. Both expressions yield the value pointed to by ptr.
If your intention with ptrptr was to have it be a pointer to a pointer, here's an illustration of that wrinkle. Since ptrptr is a two-level pointer, its pointed-to value is actually another pointer, so you have to be really careful thinking about it.
int **ptrptr = &ptr;
printf("the value of the pointer ptrptr is %p\n", ptrptr);
printf("the value pointed to by ptrptr is %p\n", *ptrptr);
printf("and the value pointed to by that pointer is %d\n", **ptrptr);
This additionally prints:
the value of the pointer ptrptr is 0x7ffeed569920
the value pointed to by ptrptr is 0x7ffeed56992c
and the value pointed to by that pointer is 20
By definition *(ptr + n) === ptr[n]
Why does ptrptr[0] return the value stored by val, and not the memory
address of the pointer ptr.
I thought that the indexing operator [] returns the value stored by
that value.
no ptr[x] dereferences the pointer.
int x = 5;
int *ptr = &x;
int *ptrptr = ptr; //this assigns reference stored in ptr to ptrptr. Now they store the same reference.
printf("Dereferencing pointer - %d\n", ptr[0]);
printf("Reference stored in the pointer - %p\n", (void *)ptr);
printf("Reference of the pointer (its address) - %p\n", (void *)&ptr);
Judging from the name of your second pointer you probably wanted pointer to pointer
int x = 5;
int *ptr = &x;
int **ptrptr = &ptr; //poiter to pointer
printf("Dereferencing pointer to pointer - reference of x %p\n", (void *)ptrptr[0]);
printf("Reference stored in the pointer to pointer - reference of ptr%p\n", (void *)ptrptr);
printf("Reference of the pointer (its address) - %p\n", (void *)&ptrptr);
This
ptrptr[0]
is the same as (because ptrptr and ptr are same type and have same value):
ptr[0]
is the same as (because a[b] == *(a+b)):
*ptr
is the same as var, because ptr points to var, and *ptr is dereferencing the pointer.
The value of var is 20.
ptrptr has the same type as ptr, a pointer to an int. So when you do int *ptrptr = ptr;, now ptrptr and ptr point to the same address (that's why it compiles as well). Also ptrptr[0] is the same as to *ptrptr
You have to define ptrptr to be a pointer to a pointer of an int:
int **ptrptr = &ptr;
printf("Value at ptrptr[0] = %d \n", *ptrptr[0]);
if you wanted ptrptr to point to ptr
Link to Compiler Explorer.
You never set ptrptr to hold the memory address of ptr but to the value of ptr itself. Below is an image for illustration. First ptr is assigned the address of var and then ptrptr is assigned the value of ptr, so it also points to var.
To make ptrptr point to ptr you need to declare it as
int **ptrptr = &ptr;

Pointer is "passed by value"?

After calling f() on ptr, I expect it to point to a single byte with value of A.
But instead ptr is copied by value and it is only available in the f function(?)
What am I doing wrong?
void f(char* ptr) {
ptr = (char*) malloc(1);
*ptr = 'A';
}
int main() {
char* ptr;
f(ptr);
printf("%c\n", *ptr); // Segmentation fault, But it should be 'A'
// free(ptr);
}
Thanks!
Yes, it's passed by value. If you want the changes you make to the pointer to be visible at the call site, you need to pass a pointer to the pointer.
Example:
#include <stdlib.h>
#include <stdio.h>
void f(char **ptr) { // pointer to the pointer
*ptr = malloc(1);
if(*ptr) // precaution if malloc should fail
**ptr = 'A';
}
int main(void) {
char *ptr;
f(&ptr); // take the address of `ptr`
if(ptr) // precaution again
printf("%c\n", *ptr); // now fine
free(ptr); // without this, you have a memory leak
}
Or, f() could simply return the pointer.
Form the habit of testing return values.
#include <stdio.h>
#include <stdlib.h>
char *f(void) {
char *ptr = malloc(1);
if( ptr != NULL )
*ptr = 'A';
return ptr;
}
int main() {
char *ptr = f();
if( ptr != NULL )
printf( "%c\n", *ptr );
free( ptr );
}
You might even be able to save some code if you write main() like this:
int main() {
char *ptr;
if( ( ptr = f() ) != NULL )
printf( "%c\n", *ptr ), free( ptr ), ptr = NULL;
/* more code that will see ptr as NULL */
}
And, that leads to this (being inefficient but valid):
int main() {
for( char *ptr = f(); ptr; free( ptr ), ptr = NULL )
printf( "%c\n", *ptr );
}
You are passing the pointer ptr to the function f() by value.
This essentially means that the pointer variable you passed to f() will be copied locally inside f().
Any changes made to the local copy will only affect the local copy and not the original variable you passed to f().
When a variable is passed by value, it's copy can be referenced by whatever the function argument is called.
In your case, the pointer you pass to f() has been copied inside f() and the local copy can be referenced by ptr, since that is the argument name in:
void f(char *ptr)
Now you know how pass by value works you may now understand why your code is erroneous.
In the code:
void f(char* ptr) {
ptr = (char*) malloc(1);
*ptr = 'A';
}
You modify a local copy of what you passed into f() called ptr. And since it is local, it has something called automatic storage duration.
Automatic storage duration essentially means that after the function ends, all local variables will cease to exist and the memory they occupy will be freed. This means your code actually causes a memory leak because the pointer to the memory you allocated is lost.
Solution:
In order to achieve what you want and to modify the pointer called ptr declared in main() you must pass the address of the pointer you want to modify.
This would look like this:
void f(char **ptr)
{
*ptr = malloc(sizeof(char));
if (*ptr == NULL)
{
fprintf(stderr, "malloc fail");
return;
}
**ptr = 'A';
}
int main()
{
char *ptr;
f(&ptr);
printf("%c\n", *ptr);
return 0;
}
Output:
A
Function parameters are its local variables. Changing a local variable has no effect on the argument expression.
You can imagine the function definition and its call the following way
int main() {
char* ptr;
f(ptr);
printf("%c\n", *ptr); // Segmentation fault, But it should be 'A'
// free(ptr);
}
void f( /*char* p */ ) {
char *p = ptr;
p = (char*) malloc(1);
*p = 'A';
}
That is the function parameter p (I renamed it to distinguish the parameter and argument in the function call) is initialized by the value of the argument expression and within the function the local variable p that occupies its own extent of memory is changed.
To change the original pointer you need to pass it to the function by reference. In C passing by reference means passing an object indirectly through a pointer to it. Thus dereferencing the pointer you get a direct access to the original object.
So the function in your program should be defined the following way
void f(char **ptr) {
*ptr = (char*) malloc(1);
**ptr = 'A';
}
and called like
f( &ptr );
you are passing a address of ptr so this will be copied to the funktion f(),
a smiple solution can be: you make the f(...) return a char* and used in the main: ptr = f(ptr);
Alternatively, you can allocate the memory for ptr where you declare it:
void f(char* ptr) {
*ptr = 'A';
}
int main() {
char* ptr = malloc(1);
f(ptr);
printf("%c\n", *ptr); // Segmentation fault, But it should be 'A'
free(ptr);
}

Assign the address of local variable to global pointer in C?

I'm newbie in C language. If I assign the address of local variable to global pointer, What happens? Like,
#include <stdio.h>
void func();
int *ptr;
int main()
{
func();
}
void func()
{
int i = 0;
ptr = &i;
}
Is it correct way to assign the address of local variable to global pointer?
It just does what you do, there is nothing wrong about it, except that it probably is not what you want.
So it just assigns the address of i to ptr at the point you assign it. When you leave func this pointer gets invalid.
Note This behaviour is fully defined: The address of i at the place you assign it to the global variable is defined, and so you can assign it. The problem only comes into play later, when you try to dereference the variable after you left the function func. As long as you only use the global variable in func there is no problem in this (except that a global variable is really meaningless).
At this point, this variable doesn't exist anymore. And it is very likely that you either get a segfault or at least you get some strange numbers (because you have overwritten the old stack frame with some other values) in this case.
Just as a side note: What I mean with this stack frame thing. You can try this code on most compilers (without optimizations!)
#include <stdio.h>
int *ptr;
void f1() {
int i = 0;
ptr = &i;
}
void f2() {
int i = 1;
}
int main() {
f1();
printf("%d\n", *ptr);
f2();
printf("%d\n", *ptr);
}
Without optimizations, this will most probably print
0
1
Because the variable i will have the same address when calling f1 and f2 from main().
With optimizations, the call to f2() will be optimized.
Still: This is undefined behavior and must not be done.
Your syntax is correct, but the local variable ceases to exist because it belongs within the scope of the function call's code block. To resolve this, one option is to make the local variable static:
#include <stdio.h>
void func();
int *ptr;
int main()
{
func();
}
void func()
{
static int i = 0;
ptr = &i;
}
Another option would be to allocate new memory within the function call, setting the global pointer to the address of that newly allocated memory:
#include <stdio.h>
void func();
int *ptr = NULL;
int main()
{
func();
}
void func()
{
if(ptr != NULL)
free(ptr);
int *i = (int *)malloc(sizeof(int));
ptr = i;
}
What you've got is syntactically correct, and the code as written is semantically valid (but since ptr is never used, it is a bit pointless).
If you access ptr when it contains a pointer that has gone out of scope, you get undefined behaviour.
However, consider a slightly larger code fragment. Here, the code that sets ptr calls a function that uses ptr, and the variable that ptr points to is still defined, so there is no problem using the pointer.
#include <stdio.h>
void func(void);
void use_pointer(void);
int *ptr;
int main(void)
{
func(); // NB: argument not allowed with prototype!
int i = 20;
printf("%s: A %d\n", __func__, i);
ptr = &i;
use_pointer();
printf("%s: B %d\n", __func__, i);
}
void func(void)
{
int i = 0;
printf("%s: A %d\n", __func__, i);
ptr = &i;
use_pointer();
printf("%s: B %d\n", __func__, i);
}
void use_pointer(void)
{
printf("ptr = %p; *ptr = %d\n", (void *)ptr, *ptr);
*ptr = 42;
}
This is legitimate code — though using global variables is something you should generally avoid and perfectly well could avoid.
Sample output:
func: A 0
ptr = 0x7fff55be74ac; *ptr = 0
func: B 42
main: A 20
ptr = 0x7fff55be74cc; *ptr = 20
main: B 42

Understanding Stack Frames in C

I am trying to understand the stack frame in C, so I wrote a simple C code to analyze the stack frame.
First of all the fun1() returns an address of a local variable which is initialized to 10 to ptr which leads to a warning but that's ok... If I print the value of *ptr now it prints 10, even that's fine...
Next fun2() returns an address of a local variable which is not even initialized and if I try to print the value of *ptr now it prints 10 no matter if i'm returning an address of a or b...
To understand what is actually happening here I made use of gdb.
Using gdb, I started step by step debugging and when I reached the line "return &a" in fun2(), I tried to print address of b, print &b but it printed
Can't take address of "b" which isn't an lvalue.
I don't understand when I try to print the address of a, print &a it prints absolutely fine then why not address of b.
* Why isn't b an lvalue when a is?
# include <stdio.h>
int * fun1() {
int a = 10;
return &a;
}
int * fun2()
{
int a;
int b;
return &a; // return &b;
}
int main ()
{
int *ptr;
ptr = fun1();
ptr = fun2();
printf ("*ptr = %d, fun2() called...\n", *ptr);
return 0;
}
The compiler is optimizing away some code in fun2.
If you return &a, it is optimizing away int b;. If you return &b, it is optimizing away int a;. If you add some dummy computation, you will see that the addresses of returned values will be different.
int * fun2()
{
int a;
int b;
int* p = &a;
p = &b;
return p;
}
Change main to print the returned values of fun1 and fun2.
int main ()
{
int *ptr;
ptr = fun1();
printf ("ptr = %p, fun1() called...\n", ptr);
ptr = fun2();
printf ("ptr = %p, fun2() called...\n", ptr);
printf ("*ptr = %d, fun2() called...\n", *ptr);
return 0;
}
When I run this code, I get the following sample output:
ptr = 0x7ffff98c70ec, fun1() called...
ptr = 0x7ffff98c70e4, fun2() called...
*ptr = 32749, fun2() called...
It compiles for me just fine when returning the address to b. But you aren't supposed to return the address of a local variable. Check out this link.

dynamic memory created inside a function [duplicate]

This question already has answers here:
C Programming: malloc() inside another function
(9 answers)
Closed 5 years ago.
I would like to know the technical reason(in terms of memory) why this piece of code will not work:
#include <stdio.h>
#include <stdlib.h>
int* fun(int*);
int main()
{
int a=5;
int* ptr;
// ptr=(int*)malloc(sizeof(int));
fun(ptr);
a=*ptr;
printf("\n the val of a is:%d",a);
return 0;
}
void fun(int* ptr)
{
ptr = (int*)malloc(sizeof(int));
*ptr = 115;
}
Why will this not work? I thought that the heap(more importantly the addresses) is common to all the function's variables in the stack .
Also, why would this work.
If i comment the memory allocation inside the function fun and uncomment the one in main . It works fine.
In C, everything is passed by value.
What you are passing to fun() is a copy of the pointer you have in main().
That means the copy of ptr is aimed at the allocated memory, and that memory set to 115.
The ptr in main() still points at an undefined location because it has never been assigned.
Try passing a pointer to the pointer, so that within fun() you have access to the pointer itself:
#include <stdio.h>
#include <stdlib.h>
int* fun(int**); // <<-- CHANGE
int main()
{
int a=5;
int* ptr;
// ptr=(int*)malloc(sizeof(int));
fun(&ptr); // <<-- CHANGE
a=*ptr;
printf("\n the val of a is:%d",a);
return 0;
}
int* fun(int** another_ptr) // <<-- CHANGE
{
*another_ptr = (int*)malloc(sizeof(int)); // <<-- CHANGE
**another_ptr = 115; // <<-- CHANGE
return *another_ptr;
}
The other option would be to make fun() actually return the updated pointer (as advertised), and assign this to ptr:
#include <stdio.h>
#include <stdlib.h>
int* fun(int*);
int main()
{
int a=5;
int* ptr;
// ptr=(int*)malloc(sizeof(int));
ptr = fun(ptr); // <<-- CHANGE
a=*ptr;
printf("\n the val of a is:%d",a);
return 0;
}
int* fun(int* another_ptr)
{
another_ptr = (int*)malloc(sizeof(int));
*another_ptr = 115;
return another_ptr; // <<-- CHANGE
}
Edit: I renamed the variable in fun() to make it clear that it is different from the one you use in main(). Same name doesn't mean anything here.
The fun() function parameter is a copy of the variable you passed into fun(). So when you do:
ptr = (int*)malloc(sizeof(int));
*ptr = 115;
you only change that copy. You should change the function signature:
int* fun(int** ptr)
{
*ptr = (int*)malloc(sizeof(int));
**ptr = 115;
}
and change how you call it accordingly.
You are confused about several things here, but one easy way of writing the function is:
int * fun()
{
int * ptr = (int*)malloc(sizeof(int));
* ptr = 115;
return ptr;
}
You are now responsible for freeing the memory, so in main():
int * ip = fun();
printf( "%d", * ip );
free( ip );
The alternative is to pass the address of apointer (a pointer to a pointer) to the function:
void fun( int ** pp )
{
* pp = (int*)malloc(sizeof(int));
** pp = 115;
}
then your code in main() looks like:
int * ip;
fun( & ip );
printf( "%d", * ip );
free( ip );
I think you can see that the first function is simpler to use.
You need to pass the address of the pointer in main if you want to change it:
fun(&ptr);
(and change fun appropriately, of course)
At the moment, it's changing the local variable ptr inside the function, and of course that change doesn't magically appear anywhere else.
You're passing the ptr by value to fun. fun will recieve a copy of ptr which will be modified. You need to pass ptr as int**.
void fun(int** ptr)
{
*ptr = (int*)malloc(sizeof(int));
**ptr = 115;
}
and call it with:
fun(&ptr);
(I also removed the return value from fun since it wasn't used)
The variable int* ptr is passed by value to the function fun. So the value assigned to ptr inside the function using ptr = (int*)malloc(sizeof(int)); will not be reflected outside the function. So when you do a = *ptr; in main() you are trying to use an un-initialized pointer. If you want to to reflect the changes done to ptr outside the function then you need to change the signature of fun to fun(int** ptr) and do *ptr = (int*)malloc(sizeof(int));
Remember that if you want a function to modify the value of an argument, you must pass a pointer to that argument. This applies to pointer values; if you want a function to modify a pointer value (not what the pointer points to), you must pass a pointer to that pointer:
void fun (int **ptr)
{
/**
* Do not cast the result of malloc() unless you are
* working with a *very* old compiler (pre-C89).
* Doing so will supress a valuable warning if you
* forget to include stdlib.h or otherwise don't have
* a prototype for malloc in scope.
*
* Also, use the sizeof operator on the item you're
* allocating, rather than a type expression; if you
* change the base type of ptr (say from int to long),
* then you don't have to change all the corresponding
* malloc() calls as well.
*
* type of ptr = int **
* type of *ptr = int *
* type of **ptr = int
*/
*ptr = malloc(sizeof **ptr);
*ptr = 115;
}
int main(void)
{
int *p;
fun(&p);
printf("Integer value stored at %p is %d\n", (void *) p, *p);
return 0;
}
BTW, you have a type mismatch in your example; your initial declaration of fun returns an int *, but the definition returns void.

Resources