Home > Enterprise >  Function scope and Pointers
Function scope and Pointers

Time:10-05

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

CodePudding user response:

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) {
    static 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;
}

CodePudding user response:

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.

CodePudding user response:

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.

  • Related