Sparkas
Sparkas

Reputation: 175

Use or purpose of a pointer to a pointer (C)

I understand what a pointer is, but I am struggling to understand what they are used for. I could think of situations where you COULD use a pointer, but these situations I can think of, could also be solved in a different way without much more work. Anyway, what I really do not understand, is the use of pointers to pointers. For example I came across this simple C-code:

#include <stdlib.h>

int main(int argc, char** argv)
{
    ...
}

From what I understood, this is meant to be a program that can be called by the commandline with infinite parameters and is sort of a convention. What exactly is the purpose of char** argv? Why use a pointer to a pointer to a char here? I'm sorry if this is a trivial question, but I seem to really struggle to get the big picture here.

Thank you in advance, Sparkas

Upvotes: 1

Views: 194

Answers (3)

John Bode
John Bode

Reputation: 123558

Pointers to pointers show up in a number of situations. Probably the most common is when you need a function to write to a pointer argument.

Consider the following:

void foo( T *p ) // for any type T
{
  *p = new_value(); // write to the thing p points to
}

void bar( void )
{
  T var;
  foo( &var ); // foo updates value of var
  ...
}

Here the function foo is updating the variable var defined in bar through the pointer p.

Now let's replace type T with the pointer type Q *:

void foo( Q **p )
{
  *p = new_pointer_value(); // write to the thing p points to
}

void bar( void )
{
  Q *var;
  foo( &var );  // foo updates the value of var
  ...
}

The semantics are exactly the same; we're writing a new value to var. The only difference is that var has a pointer type, so we need to use multiple levels of indirection in foo.

A second common situation is when you have an array of pointers, and you pass that array to another function. For example:

void foo( char **s )
{
  while ( *s )
    puts( *s++ );
}

void bar( void )
{
  char *strings[] = { "blurga", "bletch", "blah", NULL };
  foo( strings );
}

strings is an array of pointers to char; each element of the array is the address of a string literal (or NULL). In the call to foo the array expression strings is converted ("decays") to an expression of type "pointer to pointer to char", and the value of the expression is the address of the first element of the strings array1. Since the first element of the array is a pointer, then the address of the first element is a pointer to a pointer.

The third case is when you're allocating memory for a 2D array by pieces:

T **arr = malloc( sizeof *arr * rows );
if ( arr )
{
  for( size_t i = 0; i < rows; i++ )
  {
    arr[i] = malloc( sizeof *arr[i] * cols );
  }
}


1. Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.

Upvotes: 1

rcgldr
rcgldr

Reputation: 28921

There are examples of C where argv is alternately declared as an array of pointers:

char *argv[]

The pointer to pointer syntax:

char **argv

declares a pointer to what could be the first pointer in an array of pointers. Another common usage is for passing a pointer to a pointer to a linked list:

node *head; /* pointer to linked list */
/* ... */
/* pass a pointer to head */
list_function(&head);
/* ... */
/* use and update head */
list_function(node **head){ ... }

Upvotes: 1

Jack
Jack

Reputation: 133609

A pointer to a pointer (to a pointer..) is useful in all the situations in which you need more than one level of indirection.

In the specific circumstance of char** args you have an array of strings which are the arguments, each string in C is a char* so basically you have some thing like

char** args
        |
         ->  | char* | char* | char* | char* |
                 |       |
                 v       |
                |f|o|o|  |
                         |
                         v
                        |b|a|r|

What's strange about this? Think about that T* defines a type which is a pointer to a T. Now if T == char* then you have that char** defines a pointer to a char*, which in its turn is a pointer to a char.

Remember that in C and C++ a pointer can represent an array.

Upvotes: 3

Related Questions