5

I have a sample C program I am trying to understand. Below is a function excerpt from the source code:

double** Make2DDoubleArray(int arraySizeX, int arraySizeY)
{
  double** theArray;
  theArray = (double**) malloc(arraySizeX*sizeof(double*));
  int i = 0;

  for (i = 0; i < arraySizeX; i++)
    theArray[i] = (double*) malloc(arraySizeY*sizeof(double));

  return theArray;
}

My question is what is the significance of the ** in the return type. I know that the * is generally used as a pointer. I know that it may also be used to dereference the pointer.

This makes me think that double** is a double value because it is essentially the dereferencing of a reference. Is my thinking correct? If not, can someone please explain the use of ** in this example?

Brian
  • 7,098
  • 15
  • 56
  • 73
  • 5
    pointer to a pointer – advocateofnone Feb 10 '15 at 22:13
  • @sasha What is the significance of having a pointer to a pointer? Can you explain this in an answer? – Brian Feb 10 '15 at 22:14
  • cdecl C gibberish ↔ English declare a as pointer to pointer to double permalink – huseyin tugrul buyukisik Feb 10 '15 at 22:14
  • @BrianVanover: Well, you have pointers that point to (say) `double`. And then you have pointers that point to another pointer (which points to, say, `double`). That's all of it. – Tim Čas Feb 10 '15 at 22:15
  • 3
    first you need to understand what is `pointer` and stop mixing it with `reference`, then you will extend your knowledge to `pointer to pointer` – Iłya Bursov Feb 10 '15 at 22:15
  • 1
    Read types right to left. `double **` is "pointer to pointer to double". What you wrote, `**double`, doesn't make sense: "double to pointer to pointer." So `**double` is invalid syntax. – yellowantphil Feb 10 '15 at 22:15
  • 1
    Perhaps because this question could be answered by reading a chapter on pointers in a C book. I didn't downvote though. – yellowantphil Feb 10 '15 at 22:18
  • 3
    @S.Morgenstern All problems can be solved by reading the correct book. Leading to the conclusion that this site isn't needed? I think not... – Support Ukraine Feb 10 '15 at 22:22
  • @nielsen: I guess he was just slightly clumsy in expressing that: By reading any chapter on pointers in a basic C book or tutorial. Which, come to think of it, would fit official guidance. – Deduplicator Feb 10 '15 at 22:25
  • [don't cast the result of malloc in C](http://stackoverflow.com/q/605845/995714) – phuclv Mar 01 '16 at 14:34

6 Answers6

5

In this case, double means a variable of type double.

double* means a pointer to a double variable.

double** means a pointer to a pointer to a double variable.

In the case of the function you posted, it is used to create a sort of two-dimensional array of doubles. That is, a pointer to an array of double pointers, and each of those pointers points to an array of pointers.

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
  • 1
    @Jonathan Thanks. Can you elaborate as to why a pointer to a pointer is useful/necessary within the context of this example? – Brian Feb 10 '15 at 22:14
  • 5
    @StenSoft: No, **pointers are not arrays**. Please read section 6 of the [comp.lang.c FAQ](http://www.c-faq.com/). I request that you delete your comment, since it may mislead others. The idea that arrays are "really" pointers is a widespread misconception; please do not help to spread it. – Keith Thompson Feb 10 '15 at 22:16
  • @StenSoft: Not really in C; arrays are different from pointers (though an array will implicitly get converted to a pointer at any opportunity it gets). – Tim Čas Feb 10 '15 at 22:16
  • @StenSoft: pointers are not arrays and arrays are not pointers, for all they're closely related and you can use a pointer as the starting address for an array. And a `double **dptr;` is not the same as `double darray[23][17];` because `dptr[0]` points to/at a pointer, but `darray[0]` _is_ a pointer, but does not point at a pointer. – Jonathan Leffler Feb 10 '15 at 22:16
  • 3
    A 2D array is an array of arrays; the whole thing is contiguous in memory. A pointer-to-pointer can be used to implement a data struct that behaves similarly, with each row allocated independently, but it's misleading to call it a 2D array. – Keith Thompson Feb 10 '15 at 22:18
  • This is an old-style "shortcut" that obfuscates the intent of the code by leveraging how C to reduces array references to a pointer to the first element. When you think of C as being structured PDP-11 assembly language, it makes perfect sense. But there's not a lot of us still active that have ever programmed in PDP-11 assembly. – pojo-guy Feb 10 '15 at 22:22
  • `T**` arrays are usually known as "jagged arrays", FYI – Tim Čas Feb 10 '15 at 22:26
  • @pojo-guy: It also makes sense when you think of C as C. I see nothing particularly PDP-11ish about array expressions decaying to pointers. – Keith Thompson Feb 10 '15 at 22:33
  • @pojo-guy: Aren't null-terminated strings the more PDP-11-like thing in C? Because of the `.ASCIZ` directive. I'm not sure how implicit array->pointer conversions are PDP-like (but I'm curious to see). – Tim Čas Feb 10 '15 at 22:49
  • C was specifically built as an extension to B (itself a subset of BCPL) that could leverage features of the PDP-11 instruction set, such as byte addressability. It was not initially intended to be portable. PDP-11 assembly language (like most assembly languages) didn't support arrays directly. You used a pointer plus a register offset. – pojo-guy Feb 11 '15 at 04:58
  • @KeithThompson I will grant that the practice was also common in other platforms and languages, and is in fact the underlying mechanism for passing data structures by reference in any programming language. – pojo-guy Feb 11 '15 at 05:09
4
some_type*

is a pointer to some_type. So

some_type**

is a pointer to a pointer to some_type.

One typically use is for (emulating) 2D arrays.

In your case the first malloc reserves memory for the pointers to an array of doubles. The second malloc reserves memory for an array of doubles. In this way you have allocated memory that can be used like a 2D array.

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
4

Here's a more general answer: the spiral rule. For this particular example:

      +-----------+
      |+--------+ |
      ||  +---+ | |
      ||  ^   | | |
double** foo; | | |
   ^  |^      | | |
   |  |+------+ | |
   |  +---------+ |
   +--------------+

Read this as "\"foo\" is a pointer to a pointer to a double."

In this case, each pointer is semantically an array, so this represents a 2D array of type double.

geometrian
  • 14,775
  • 10
  • 56
  • 132
2

The author is using one method (not the only) in C of creating two-dimensional array of doubles, namely, creating Y one-dimensional arrays of double, and a single array of X pointers to these. Each of those Y arrays is accessed by a variable of type double *. Then he creates a single one-dimensional array of pointers to each of these arrays, and stores those pointers in an array of type double **, or pointer-to-pointer-to-double.

There are several advantages of using this method to make 2D arrays. One, you need to do less math to reach an element, and you can even pass such arrays to functions that don't have to know their exact dimensions to work. Also, you can create things like triangular arrays, or other shapes where the sub-arrays need not all be the same size.

The only downside is that they take up a bit more memory.

Lee Daniel Crocker
  • 12,927
  • 3
  • 29
  • 55
  • "less math to reach an element" - to clarify, that means using syntax like `theArray[x_index][y_index]` to access an element – anatolyg Feb 10 '15 at 22:26
  • Another possible downside is that the memory isn't contiguous, which might slow down reads, depending on what order you read the elements in. – yellowantphil Feb 10 '15 at 22:26
  • Less math, sure. But more indirection and severely reduced locality-of-reference, which is both far more important. Now if the array should be jagged, that might be an acceptable (maybe unavoidable) decision... – Deduplicator Feb 10 '15 at 22:27
  • When I say "less math" I mean that accessing an array like this just requires two multiply-by-eight operations in machine code, while a contiguous array requires a multiply by 8 and a multiply by the size of the inner array, which might be more expensive (although nowadays the extra memory access of the former probably obviates that). – Lee Daniel Crocker Feb 10 '15 at 22:29
1

* has multiple meanings:

  1. Designating a pointer in a type.
  2. The dereference-operator.
  3. The multiplication-operator.

Your example only uses ** in a type for defining an automatic variable:
double**, meaning pointer-to-pointer-to-double.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
1

A this ** in your case means a pointer to a pointer. It is self - explanatory I guess. A ** points to a pointer which in turns points to a memory location. Its is useful say if you want to save memory and you have to declare a 2D array with r rows and c columns and they are variable. So following is what you do

      void create_matrix(int r,int c)
      {
           double ** matrix;
           matrix = (double **)malloc(sizeof(double *)*r);
           for(int i=0;i<r;i++ )
               matrix[i] = (double *)malloc(sizeof(double)*c);
           /* do operations on matrix */
           return ;
       }
advocateofnone
  • 2,527
  • 3
  • 17
  • 39