-4

Why should I create a new void** variable when I can simply & to the original variable? Are double-pointer variables useless?

Please note I'm not discussing the double-pointer concept. I'm talking about creating a double-pointer variable instead of just using a reference. I'm about the coding style, not the concept.

void update(char** foo) {
    char* buf = (char*) malloc(32);
    sprintf(buf, "Hello World");
    *foo = buf;
}

int main() {
    
    char* foo = NULL;
    
    // Using a char** variable (The long way)
    char** bar = &foo;
    update(bar);
    printf("Using a new variable -> foo = %s.\n", *bar);
    
    // Using reference (The quick way)
    update(&foo);
    printf("Using a simple reference -> foo = %s.", foo);

    return 0;
}
Albert Shown
  • 230
  • 7
  • 3
    No, they're not useless. In fact, `main` is invoked with a `char **argv` argument. Do you think that's useless? In any case, this is an opinion-based question. Learn more about pointers and arrays and function arguments, then you can make up your own mind. – Tom Karzes Mar 13 '23 at 16:54
  • 3
    Why do I need create `int` variable with value of `5`, if I can use `5` instead? The answer would be similar. – Eugene Sh. Mar 13 '23 at 16:55
  • How would you implement your `update` function without `char **foo`? – Gerhardh Mar 13 '23 at 16:55
  • @TomKarzes - You are talking about `update(char** foo)`, it's the only way to do it. I'm talking about `char** bar = &foo;` :-) – Albert Shown Mar 13 '23 at 16:56
  • Both are using pointers to pointers. If you are well aware that you need this in some situations, how would it ever be useless? – Gerhardh Mar 13 '23 at 16:57
  • @EugeneSh. - That has nothing to do with the double-pointers. – Albert Shown Mar 13 '23 at 17:00
  • @Gerhardh - I'm not talking about update(char** foo), it's the only way to do it. I'm talking about char** bar = &foo; :-) – Albert Shown Mar 13 '23 at 17:01
  • 3
    Are `int` variables useless? Why should I create a new `int` variable when I can simply pass its variable to a function? For example, why write `int x = 3; foo(x);` when we can write `foo(3);`? – Eric Postpischil Mar 13 '23 at 17:03
  • @AlbertShown It has to do with levels of indirection. A "double pointer" is a variable that is storing a value of a pointer to a pointer. An `int` is a variable that is storing a value of an integer constant. The difference is only the level of indirection. UPD: I see Eric clarified it for me... – Eugene Sh. Mar 13 '23 at 17:03
  • Also "instead of just using a reference"? C does not have "references". The unary `&` operator is the "address of" operator. Particulars **matter** when writing code. – Andrew Henle Mar 13 '23 at 17:05
  • You do need to use them at the moment as at your level you write very trivial programs. Your example is too trivial to need more complex data types. – 0___________ Mar 13 '23 at 17:05
  • Assigning to variables whose sole purpose it be the argument of a function *is* useless. The double indirect pointer type isn't. It's what the callee will need to declare the argument type to be if it wants at least *some* pointer typesafety. (Or it could throw pointer type safety away by accepting `void *`, which is kind of special.) – Petr Skocik Mar 13 '23 at 17:06
  • @AndrewHenle: `&x` is a reference to `x`. It refers to `x`, in the ordinary English sense, and the C standard says that a pointer provides a reference to an entity. C++ created a new built-in type and called it a “reference”, but the C++ terminology does not change either common English or the use of “reference” in the context of C code. – Eric Postpischil Mar 13 '23 at 17:07
  • That added paragraph changes the question completely. – Gerhardh Mar 13 '23 at 17:08
  • 2
    It turns into a "why some random guy have chosen to write this random code in this random way if it can be written in some other random way?" question. This becomes a question to that specific random guy. – Eugene Sh. Mar 13 '23 at 17:10
  • @EricPostpischil Well, it *is* the "address of `x`" Nowhere in [this version if the C standard at least](https://port70.net/~nsz/c/c11/n1570.html#6.5.3.2p3) is the word "reference" used with respect to the definition of the `&` address-of operator. I'm surprised you're being this loose with your definitions. – Andrew Henle Mar 13 '23 at 17:14
  • 1
    @AlbertShown In the case of `char **bar = &foo;`, I would probably just use `&foo` directly. It would make more sense if you intended to change `bar`, in which case you'd need a variable, but if you wanted to increment it then you'd need it to point into an array. – Tom Karzes Mar 13 '23 at 17:15
  • `char** bar = &foo; update(bar);` or `update(&foo);` is just a matter of style. It works the same and it's likely that the compiler will produce the same code. – Support Ukraine Mar 13 '23 at 17:24
  • @SupportUkraine, Thank you, sir. Yes, just a matter of style. So I was asking if there is a situation where I definitely need `bar`. But it seems people didn't understand the simplicity of the question. – Albert Shown Mar 13 '23 at 18:26
  • 2
    @AndrewHenle: C 2018 6.5.3.2 3 says the result of `&` is a pointer. 6.2.5 20 says the value of a pointer provides a reference (to the entity it points to). This does not need to be a formal definition in the standard. It is simply how people use English to refer to things in C. It is not wrong because C++ uses the word for something different, so it is not right to correct people who use it this way. – Eric Postpischil Mar 13 '23 at 18:32
  • @AlbertShown I can't come up with an example where **you need to create an extra variable** in order to pass a pointer to an object to a function. Calling the function with `&object` is fine in all cases I can come up with. Notice that it doesn't matter whether it's a pointer-to-pointer to e.g. char or just a pointer to char... same thing. It's a matter of style. If I'm going to pass a pointer to an object located deep down in some struct of struct of struct of .... I often like to create extra variables but that's just my style. – Support Ukraine Mar 13 '23 at 18:39
  • That's it, sir. Here we go, "object located deep down in some struct of struct of struct..." it's then very smart to create a new variable to make the code look clean. So the answer is simple, double-pointer variables are a nice style of coding for a clean code, but there is no mandatory situation where you are forced to create a new variable. Thank you, sir, I got it now :) – Albert Shown Mar 13 '23 at 18:53
  • @EricPostpischil *It is not wrong because C++ uses the word for something different* No it's not wrong, but the fact that C++ uses the term differently but in a very similar context can make it confusing, especially for persons not intimately familiar with the precise technical meaning of the terms. I just seem to be a bit more particular than you are. – Andrew Henle Mar 13 '23 at 19:25

2 Answers2

1

They're not useless. You can't avoid creating double-pointer variables in general. But you can avoid storing the intermediate result of calculations.

Your program features an example of both of these. Let's look at each in detail.


char** foo

You couldn't replace

void update(char** foo) {
    char* buf = (char*) malloc(32);
    sprintf(buf, "Hello World");
    *foo = buf;
}

with

void update(char* foo) {
    char* buf = (char*) malloc(32);
    sprintf(buf, "Hello World");
    foo = buf;           // XXX Uselessly modifies the local variable `foo`.
}

Creating a double-pointer variable is required here.


char** bar

However,

char** bar = &foo;
update(bar);

can indeed be simplified to

update(&foo);

Creating a variable isn't required here, because there's no need to store the intermediate result of the calculation. We do the same thing when we simplify

int sum = a + b;
int result = sum * c;

into

int result = ( a + b ) * c;
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • I'm not discussing the double-pointer concept. I'm talking about creating a double-pointer variable instead of just using a reference. I'm about the coding style, not the concept. – Albert Shown Mar 13 '23 at 17:01
  • And I covered both instances of creating a double-pointer variable in your program. – ikegami Mar 13 '23 at 17:03
  • The `a + b` has nothing to do with the pointers and references. – Albert Shown Mar 13 '23 at 17:03
  • True, but it has everything to do with your question. You ask if you need to store intermediate results, and I said no, and I gave another example of where it's avoided. – ikegami Mar 13 '23 at 17:03
  • 2
    @AlbertShown: Re “The `a + b` has nothing to do with the pointers and references”: It is an [analogy](https://en.wikipedia.org/wiki/Analogy). – Eric Postpischil Mar 13 '23 at 17:04
  • Since it seems I wasn't clear, I have updated my answer to be clearer. – ikegami Mar 13 '23 at 17:11
  • Thank you, sir, but my question is simple, is there a situation where I'm forced to use `char** bar = &foo;`? The answer is "No". – Albert Shown Mar 13 '23 at 18:58
  • What is with the hostility? Please be kinder. – ikegami Mar 13 '23 at 20:28
  • You are mistaken. `char **bar; if ( x ) { bar = &foo; } else { bar = &baz; }` and `void update( char **bar ) { ... } update( &foo );` both assign to a necessary variable of type `char**`. 0___________ also gave an example. – ikegami Mar 13 '23 at 20:37
0

You will need them when you start to solve more complex programming problems.

Example:

typedef struct text
{
    size_t nlines;
    char **lines;
}text_t;


text_t *addline(text_t *lines, const char *str)
{
    if(lines)
    {
        char **tmp = realloc(lines -> lines, sizeof(*lines -> lines) * (lines -> nlines + 1));
        if(tmp)
        {
            lines -> lines = tmp;
            lines -> lines[lines -> nlines] = malloc(strlen(str + 1));
            if(lines -> lines[lines -> nlines])
            {
                strcpy(lines -> lines[lines -> nlines], str);
                lines -> nlines += 1;
            }
        }       
    }
    return lines;
}
0___________
  • 60,014
  • 4
  • 34
  • 74