Search code examples
cpointerspass-by-referencepass-by-value

What is the use of a pointer to pointer to struct as an arguments of a function?


The reason for the question is that there seems to be no reason to use a double indirection like "struct **pointer".

To understand the functioning of pointers to structures as arguments of a function I have prepared an example. The aim is to see if the changes made by a function on a structure remain outside the scope of the function, or if they only cause effect inside the function. This is a common problem of passing arguments by value or by reference.

#include <stdio.h>

/* A simple structure is defined to see the effect that the functions 
 * have on it. */
typedef struct est
{
  int val1;
  int val2;
} est_t;

/* These three functions simply assign the values val1 and val2 to the 
 * structure. Each of these functions uses a different way of passing 
 * the parameter to the function referring to the structure. There are 
 * more comments below, in the definition of each function. */
void foo(int, int, est_t);
void bar(int, int, est_t*);
void baz(int, int, est_t**);

/* This is a function to print the values of a structure and make the 
 * code cleaner. It also contains a parameter about a structure! */
void print_est(est_t*);

int main (int argc, char *argv[])
{
  est_t a;

  foo(10, 11, a);
  print_est(&a);
  
  bar(20, 21, &a);
  print_est(&a);
  
  est_t *p = &a;
  baz(30, 31, &p);
  print_est(&a);
  
  return 0;
}

void foo(int v1, int v2, est_t ve)
{
  /* In this case the structure is "directly put" into the function.
   * As the structure already is inside the function, the values of each 
   * element are assigned with the ". " */
  ve.val1 = v1;
  ve.val2 = v2;
  
  /* With these printf you can see what is happening within the 
   * function. */
  printf("[foo] val1 = %d\n", ve.val1);  
  printf("[foo] val2 = %d\n", ve.val2);
}

void bar(int v1, int v2, est_t *ve)
{
  /* In this case the structure is passed into the function using a 
   * pointer. */
  ve->val1 = v1;
  ve->val2 = v2;
  
  printf("\n[bar] val1 = %d\n", ve->val1);  
  printf("[bar] val2 = %d\n", ve->val2);
}

void baz(int v1, int v2, est_t **pp)
{
  /* In this case the structure is passed into the function using a 
   * pointer to a pointer to a struct. */
  (*pp)->val1 = v1;
  (*pp)->val2 = v2;
  
  printf("\n[baz] val1 = %d\n", (*pp)->val1);  
  printf("[baz] val2 = %d\n", (*pp)->val2);
}

void print_est(est_t *addr)
{
  printf("[main] val1 = %d\n", addr->val1);
  printf("[main] val2 = %d\n", addr->val2);
}

And this is the output when you run the program.

foo(10, 11, a);  
[foo] val1 = 10  
[foo] val2 = 11  
[main] val1 = -1238356256  
[main] val2 = 32764

You can see that the values that were assigned within the function, are not kept outside

And let's see the output for bar and baz.

bar(20, 21, &a);    
[bar] val1 = 20  
[bar] val2 = 21  
[main] val1 = 20  
[main] val2 = 21

est_t *p = &a;  
baz(30, 31, &p);  
[baz] val1 = 30  
[baz] val2 = 31  
[main] val1 = 30  
[main] val2 = 31 

It seems that they do the same. I mean in both cases the values are kept outside the function.

Foo and bar are typical cases of by-value and by-reference, and even if the changes are not intended to be permanent, the idea of passing a structure by-reference can be interesting from the point of view of saving resources. See advantage of passing pointer to a struct as argument?

But as bar and baz do the same ¿is there any reason to use a double pointer to pass arguments to a function?


Solution

  • is there any reason to use a double pointer to pass arguments to a function

    Yes. You use a pointer whenever you want to change the argument you're passing. So if you want to change a pointer, then you need a pointer to pointer.

    Simple example:

    void foo(struct bar **ptr)
    {
        *ptr = malloc(10 * sizeof **ptr);
        
        for(int i=0; i<10; i++)
            (**ptr)->x = i;
    }