Search code examples
cpass-by-referencepass-by-valuepointer-to-pointer

How to understand secondary pointer?


i want to ask a question about pointer:

void fun(const char** a) {...}

1. 
const char* b = nullptr;
fun(&b);

2. 
const char** b = nullptr;
fun(b);

why use 1 but not 2?

1 is good, 2 donnot work


Solution

  • C uses pass by value for function call arguments. That means a function receives a copy of the passed value, and there's no way for the function to directly change a variable in the caller.

    For example, if you write

    void set_to_5(int x)
    {
        x = 5;
    }
    

    and then write

    int i = 3;
    set_to_5(i);
    printf("%d\n", i);
    

    it prints 3, not 5. Or, if you write

    void set_string(char *str)
    {
        str = "world";
    }
    

    and then write

    char *p = "hello";
    set_string(p);
    printf("%s\n", p);
    

    it prints hello, not world.

    In both cases, the function successfully changes its copy of the passed value — x or str — but that doesn't have any effect on the variable in the caller (i or p).

    When you want to have a function that does change a variable in its caller, one way to do that is to have the function accept a pointer. That looks like this:

    void set_to_5_via_pointer(int *x)
    {
        *x = 5;
    }
    
    void set_string_via_pointer(char **str)
    {
        *str = "world";
    }
    

    Then you can write:

    int i = 3;
    set_to_5_via_pointer(&i);
    printf("%d\n", i);
    
    char *p = "hello";
    set_string_via_pointer(&p);
    printf("%s\n", p);
    

    Now it does print 5 and world, as desired.

    Notice that in each case I made three changes:

    1. I added a * to the parameter type expected by the function (int x to int *x, char *str to char **str)
    2. I added a * before each use of the parameter in the function, that is, where I actually set the new value (5 and "world")
    3. I added a & before the variables where I passed them to the function (set_to_5_via_pointer(&i) and set_string_via_pointer(&p)).

    One more thing. When you see a function declaration like

    void set_string_via_pointer(char **str);
    

    this does not necessarily mean that the right way to call the function is

    char **x;
    set_string_via_pointer(x);
    

    Yes, here x is of type char **, and function set_string_via_pointer expects an argument of type char **, so it's a match. But if you declare and call

    char *y;
    set_string_via_pointer(&y);
    

    that's also a perfectly good way to pass an argument of type char **, and in this case, it's certainly they way that was expected.