Assign the address of local variable to global pointer in C? - 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

Related

Function scope and Pointers [duplicate]

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.

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.

Returning this pointer from a function

I am trying to return a pointer from a function. But I am getting a segmentation fault. Someone please tell what is wrong with the code
#include <stdio.h>
int *fun();
main()
{
int *ptr;
ptr = fun();
printf("%d", *ptr);
}
int *fun()
{
int *point;
*point = 12;
return point;
}
Allocate memory before using the pointer. If you don't allocate memory *point = 12 is undefined behavior.
int *fun()
{
int *point = malloc(sizeof *point); /* Mandatory. */
*point=12;
return point;
}
Also your printf is wrong. You need to dereference (*) the pointer.
printf("%d", *ptr);
^
Although returning a pointer to a local object is bad practice, it didn't cause the kaboom here. Here's why you got a segfault:
int *fun()
{
int *point;
*point=12; <<<<<< your program crashed here.
return point;
}
The local pointer goes out of scope, but the real issue is dereferencing a pointer that was never initialized. What is the value of point? Who knows. If the value did not map to a valid memory location, you will get a SEGFAULT. If by luck it mapped to something valid, then you just corrupted memory by overwriting that place with your assignment to 12.
Since the pointer returned was immediately used, in this case you could get away with returning a local pointer. However, it is bad practice because if that pointer was reused after another function call reused that memory in the stack, the behavior of the program would be undefined.
int *fun()
{
int point;
point = 12;
return (&point);
}
or almost identically:
int *fun()
{
int point;
int *point_ptr;
point_ptr = &point;
*point_ptr = 12;
return (point_ptr);
}
Another bad practice but safer method would be to declare the integer value as a static variable, and it would then not be on the stack and would be safe from being used by another function:
int *fun()
{
static int point;
int *point_ptr;
point_ptr = &point;
*point_ptr = 12;
return (point_ptr);
}
or
int *fun()
{
static int point;
point = 12;
return (&point);
}
As others have mentioned, the "right" way to do this would be to allocate memory on the heap, via malloc.
It is not allocating memory at assignment of value 12 to integer pointer. Therefore it crashes, because it's not finding any memory.
You can try this:
#include<stdio.h>
#include<stdlib.h>
int *fun();
int main()
{
int *ptr;
ptr=fun();
printf("\n\t\t%d\n",*ptr);
}
int *fun()
{
int ptr;
ptr=12;
return(&ptr);
}
To my knowledge the use of the keyword new, does relatively the same thing as malloc(sizeof identifier). The code below demonstrates how to use the keyword new.
void main(void){
int* test;
test = tester();
printf("%d",*test);
system("pause");
return;
}
int* tester(void){
int *retMe;
retMe = new int;//<----Here retMe is getting malloc for integer type
*retMe = 12;<---- Initializes retMe... Note * dereferences retMe
return retMe;
}

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.

Pointer question

Okay I go through 2 layers of functions fun1 calls func2 calls func3 . I pass a pointer all the way down using basically int *ptr, at the lowest "level" of the call stack I also have another function that dynamically allocates memory for an int array. At the top level (func1 level) I always get null back for the passed pointer. I have traced down to func3 and the allocated memory is being filled with values, but as the call stack unwinds func3 -> func2 suddenly the pointer just goes away (0x0000_0000)? I don't understand at func3 level I basically say ptr = allocate_ptr_array, but from that return it goes to NULL! Even though I didn't free the memory, what in the world is going on? I know my question is confusing. I have watched this happen in the debugger though
The pointer is basically passed by value. You need to pass pointer to pointer (int **p) to get the memory allocated back in outer function.
function1(int *p)
{
p = //allocate memory using malloc
}
function2(int **p)
{
*p = //allocate memory using malloc
}
function3()
{
int *p;
function1(p);
// in this case pointer is passed by value.
//The memory allocated will not be available in p after the function call function1.
int **p;
function2(&p);
//in this case pointer to pointer p has been passed.
// P will have the memory allocated even after
//the function call function1
}
}
To illuminate aJ's (completely correct) answer with some code:
void func1(void)
{
int *int_array;
func2(&int_array);
/* Some stuff using int_array[0] etc */
/* ... */
free(int_array);
}
void func2(int **a)
{
/* ... stuff ... */
func3(a);
/* .... stuff ... */
}
void func3(int **a)
{
(*a) = malloc(N * sizeof **a);
}
Here is a good example for future reference bye other people. It makes sense after implementation and thanks to these guys.
#include <memory.h>
#include <stdlib.h>
#include <stdio.h>
void func3(int **ptr)
{
int i;
(*ptr) = (int *)malloc(25*sizeof(int));
for (i=0; i < 25; i++) (**ptr) = i;
printf("func3: %d\n",ptr);
}
void func2(int **ptr)
{
func3(ptr);
printf("func2: %d\n", ptr);
}
void func1(void)
{
int *ptr;
printf("ptr before: %d\n", ptr);
func2(&ptr);
printf("ptr after: %d\n", ptr);
}
void func4(int **ptr)
{
static int stuff[25];
printf("stuff: %d\n",stuff);
*ptr = stuff;
}
int main(void)
{
int *painter;
func1();
func4(&painter);
printf("painter: %d\n", painter);
return 0;
}

Resources