0

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

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Yeatsflee
  • 23
  • 1
  • That's either a *very* modern C compiler you're using, or you're programming in C++. – Some programmer dude Feb 12 '23 at 10:53
  • As for your problem, what do you mean with "is good" and "donnot work"? Please take some time to read [the help pages](http://stackoverflow.com/help), take the SO [tour], read [ask], as well as [this question checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/). – Some programmer dude Feb 12 '23 at 10:54
  • It depends on what you're trying to do. But if the goal is for function `fun` to make a change to variable `b` in its caller, then you *always* want to pass `&b` to `fun`. That's true regardless of the type of `b`, that is, regardless of whether it's an `int`, a pointer, or some other type. – Steve Summit Feb 12 '23 at 14:13

3 Answers3

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

This passes the pointer b by reference — or emulates pass by reference semantics — i.e. the memory address of where the variable is stored is passed instead of its value. This allows you to access the pointer originally declared in the calling function, and any changes made to that pointer in the called function would be visible in the calling function.


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

Au contraire, this passes b by value. If you change the pointer to point to some other memory location in the called function, that change will not be reflected back in the calling function. Any attempt to dereference it while it is pointing to NULL would result in undefined behaviour as per the following clauses of C11:

If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined.

[...]

Among the invalid values for dereferencing a pointer by the unary * operator are a null pointer, [...]

[6.5.3.2 Address and indirection operators, C11]


why use 1 but not 2?

Why use either of them?


1 is good, 2 donnot work

“There is nothing either good or bad, but thinking makes it so.” — They both serve different purposes. Though, the purpose of the second snippet is rather ambiguous here.

Harith
  • 4,663
  • 1
  • 5
  • 20
1

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.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
0

This code snippet

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

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

means passing the pointer b to the function fun by reference in the C meaning. So dereferencing the pointer to pointer a within the function you can change the original pointer b passed to the function indirectly through a pointer to it.

Here is a demonstration program.

#include <stdio.h>

void fun( const char **a )
{
    *a = "Hello World!";
}

int main( void )
{
    const char *b = NULL;

    fun( &b );

    puts( b );
}

The program output is

Hello World!

As you can see the pointer b is passed to the function indirectly through a pointer to it (by reference in the C meaning). Thus dereferencing the pointer to pointer a

*a = "Hello World!";

you can change the original pointer b defined in main.

In the second case

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

the pointer b is passed by value and if the function fun will dereference the null pointer then undefined behavior will be invoked.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335