0

I'm learning how to program for ALSA in Linux and there's a piece of code like this:

snd_pcm_t * _soundDevice;

bool Init(const char *name)
{
  int i;
  int err;
  snd_pcm_hw_params_t *hw_params;

  if( name == NULL )
  {
      // Try to open the default device
      err = snd_pcm_open( &_soundDevice, "plughw:0,0", SND_PCM_STREAM_PLAYBACK, 0 );
  }

As you can see, it first creates the pointer to the struct snd_pmc_t and name it _soundDevice. Other parts of the code, however, use only the first pointer:

if ((err = snd_pcm_hw_params_any (_soundDevice, hw_params)) < 0)

I understand that a pointer to a struct is helpful to pass as an argument because passing the entire struct as a copy would be bad, and I also understand that this function modifies the content of the struct that the pointer points to, but why should somebody need a pointer to a pointer to a struct?

too honest for this site
  • 11,417
  • 3
  • 27
  • 49
  • 5
    So that the function you pass the address of the pointer to, can set the pointer. – Weather Vane Dec 11 '16 at 18:28
  • This looks like C code. Why have you included the [tag:c++] tag? Are you actually using C++? – Cody Gray Dec 11 '16 at 18:33
  • See also: http://stackoverflow.com/questions/897366/how-do-pointer-to-pointers-work-in-c, http://stackoverflow.com/questions/29848863/when-to-use-pointer-to-pointer-in-c, http://stackoverflow.com/questions/5580761/why-use-double-pointer-or-why-use-pointers-to-pointers, http://stackoverflow.com/questions/758673/uses-for-multiple-levels-of-pointer-dereferences ("pointer to pointer c" is eminently Googleable) – Cody Gray Dec 11 '16 at 18:33
  • When you pass arguments, that are not references, they get *copied*. So if you pass a *pointer* it will be *copied* in the function. If you change its value you only change the value of the *copy* in the function, not the pointer you passed in from the outside. You pass in a pointer to the *outside* pointer so you can change where the *outside* pointer points to (not just the copy). – Galik Dec 11 '16 at 18:39

4 Answers4

3

why should somebody need a pointer to a pointer to a struct?

This most often shows up when you need to pass a pointer into a function in a way that allows the function to change what that pointer points to. One idiomatic C way is to pass the pointer by pointer, resulting in that second level of indirection you're wondering about.

In your example snd_pcm_open modifies its first argument (i.e. makes _soundDevice point someplace new), whereas snd_pcm_hw_params_any doesn't.

If snd_pcm_open were to take snd_pcm_t* rather than snd_pcm_t**, it wouldn't be able to repoint the first argument in a manner that would propagate back to the caller.

NPE
  • 438,426
  • 93
  • 887
  • 970
  • What you mean by 'modify'? For example, given the pointer to the struct _soundDevice, can't I set things inside it? Like: void (snd_pcm_t * mystruct) { mystruct->something=anything}? –  Dec 11 '16 at 18:33
  • @GuerlandoOCs: Yes, you can set things *"inside it"*. What you can't do is *modify the pointer itself*. – NPE Dec 11 '16 at 18:34
  • Ok, so I'd be able to point the entire structure to another structure, right? Isn't it equivalent to setting the contents of a struct to the other one? –  Dec 11 '16 at 18:37
  • @GuerlandoOCs: No, not necessarily. You sometimes want to be able to allocate a completely new structure. Other times you want multiple pointers to point to the same struct, so that changes to one struct are automatically visible through the other pointer. – NPE Dec 11 '16 at 18:39
1

In C, parameter passing is by value (or by copy if you prefer), so if you want a function to modify the passed argument in return you need to pass its address.

Jean-Baptiste Yunès
  • 30,872
  • 2
  • 40
  • 66
0

Having a pointer to a pointer allows the function to modify your local pointer. If you passed just a regular pointer, the function gets that pointer on the stack. If it modifies that value (of the pointer, not the pointed-to data), the value is lost when the function returns the same way that changes to an int passed to a function would be lost. If you instead pass a pointer to a pointer, it can modify your pointer, which will still exist after the function returns.

If, for instance, the function is allocating memory for that structure, it can set your pointer to the address of the newly allocated memory or NULL if the allocation fails. In this case, it looks like this is being used as a second return value. It wants to return an error code as the actual return value and a pointer as a second value.

FazJaxton
  • 6,437
  • 6
  • 22
  • 31
0

Some times the target is not to change an object, but to change the pointer that points to it.

Imagine a function 'A' that choses among several functions

int A(someType* funcChosen)
{
     funcChosen = ...; //a pointer to a function
}
someType* myFunc;
int res = A(myFunc);

will modify myFunc. But you want a pointer to that function, not the code (??) of it. So better:

int A(someType** funChosen);
someType* myFunc;
int res = A(&myFunc);
Ripi2
  • 6,098
  • 1
  • 12
  • 28