Home > OS >  Pointer is "passed by value"?
Pointer is "passed by value"?

Time:08-24

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!

CodePudding user response:

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
}

CodePudding user response:

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

CodePudding user response:

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

CodePudding user response:

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 );

CodePudding user response:

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);

CodePudding user response:

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);
}
  • Related