You probably well know that double* is a pointer to a double element. In the same way, double** is a pointer to a double* element, which is itself a pointer. Again, double*** is a pointer to a double** element, and so on.

When you instanciate an array to a type T, you usually do new T [size];. For example, for an array of double, you write new double[size];. If your type T is a pointer itself, it's exactly the same : you write new double*[size];, and you get an array of pointers.

In your case, BTreeNode* is a pointer to BTreeNode, and BTreeNode** is a pointer to BTreeNode* which is a pointer to BTreeNode. When you instanciate it by doing new BTreeNode*[size]; you get an array of pointers to BTreeNode elements.

But actually, at this step you don't have a 2D array, because the pointers in your freshly allocated array are NOT allocated. The usual way to do that is the following example :

int num_rows = 10;
int num_cols = 20;
BTreeNode** C = new BTreeNode*[num_rows];
for(int i = 0; i < num_rows; i++)
{
  // Then, the type of C[i] is BTreeNode*
  // It's a pointer to an element of type BTreeNode
  // This pointer not allocated yet, you have now to allocate it
  C[i] = new BTreeNode [num_cols];
}

Don't forget to delete your memory after usage. The usual way to do it is the following :

for(int i = 0; i < num_rows; i++)
  delete [] C[i];
delete [] C;
Answer from Caduchon on Stack Overflow
Top answer
1 of 3
9

You probably well know that double* is a pointer to a double element. In the same way, double** is a pointer to a double* element, which is itself a pointer. Again, double*** is a pointer to a double** element, and so on.

When you instanciate an array to a type T, you usually do new T [size];. For example, for an array of double, you write new double[size];. If your type T is a pointer itself, it's exactly the same : you write new double*[size];, and you get an array of pointers.

In your case, BTreeNode* is a pointer to BTreeNode, and BTreeNode** is a pointer to BTreeNode* which is a pointer to BTreeNode. When you instanciate it by doing new BTreeNode*[size]; you get an array of pointers to BTreeNode elements.

But actually, at this step you don't have a 2D array, because the pointers in your freshly allocated array are NOT allocated. The usual way to do that is the following example :

int num_rows = 10;
int num_cols = 20;
BTreeNode** C = new BTreeNode*[num_rows];
for(int i = 0; i < num_rows; i++)
{
  // Then, the type of C[i] is BTreeNode*
  // It's a pointer to an element of type BTreeNode
  // This pointer not allocated yet, you have now to allocate it
  C[i] = new BTreeNode [num_cols];
}

Don't forget to delete your memory after usage. The usual way to do it is the following :

for(int i = 0; i < num_rows; i++)
  delete [] C[i];
delete [] C;
2 of 3
0

The statement C=new BTreeNode *[2*t]; allocates space for 2*t instances of type BTreeNode * and therefore returns a type BTreeNode ** pointing to the first element of such instances. This is the first dimension of your array, however no memory has been allocated for the second dimension.

🌐
Medium
medium.com › @muirujackson › use-of-double-pointers-in-c-d94e086a13fc
Use of Double Pointers in C?. In C, we use pointers to hold memory… | by Muiru Jackson | Medium
April 28, 2023 - In the code above, we first declare a double pointer variable “matrix” that will hold the address of the two-dimensional array. We then allocate memory for the rows of the array using the malloc function. Since each row of the array is itself a one-dimensional array, we use a single pointer to hold the address of each row.
Discussions

c - Double pointer vs array of pointers(**array vs *array[]) - Stack Overflow
Explore Stack Internal ... Im not clearly sure what is the difference between those 2. My professor wrote that **array is same as *array[] and we were presented an example where he used **array (so after classes I tried exchanging that with *array[] and it didn't work), could anyone tell me if those 2 are actually the same as he wrote?? Anyway the class was about dynamic memory allocation · @As soon as I changed the double pointer... More on stackoverflow.com
🌐 stackoverflow.com
Double Pointer to Array in C - Stack Overflow
When you indirect through the pointer ... + i is a pointer to an integer (i'th sibling of the first element of the first array). What would happen if instead I use double pointers (q in the above code).... More on stackoverflow.com
🌐 stackoverflow.com
June 4, 2021
How do I use a double pointer to manipulate an array in C? - Stack Overflow
When you dereference the pointer ptr in *ptr = arr it must already point somewhere. You're dereferencing an uninitialized pointer that doesn't point anywhere, leading to undefined behavior. Why do you need a "double pointer"? Arrays naturally decays to pointers to their first element, so using ... More on stackoverflow.com
🌐 stackoverflow.com
Passing an array as double pointer in c warning message - Stack Overflow
I am trying to run this code but there is a compiler warning: for the statement invoking the print function print(arr,3,4); passing argument 1 of 'print' from incompatible pointer type [- More on stackoverflow.com
🌐 stackoverflow.com
🌐
EDUCBA
educba.com › home › software development › software development tutorials › c programming tutorial › double pointer in c
Double Pointer in C | How does Double Pointer work in C with Examples
April 1, 2023 - Explanation: In the above code, as “matrix” is a double pointer it uses malloc function which dynamically allocates memory for the matrix of 5 rows and 5 columns. As we know that in the code “matrix” is integer data type so integer pointer can be used in the starting of the array as the address of the “matrix” pointer is an integer.
Address: Unit no. 202, Jay Antariksh Bldg, Makwana Road, Marol, Andheri (East),, 400059, Mumbai
🌐
Brynmawr
cs.brynmawr.edu › Courses › cs246 › spring2014 › Slides › 16_2DArray_Pointers.pdf pdf
4/1/14 1 2D Arrays and Double Pointers Bryn Mawr College
• A possible way to make a double pointer work with a · 2D array notation: o use an auxiliary array of pointers, o each of them points to a row of the original matrix. int A[m][n], *ptr1, **ptr2; ptr2 = &ptr1; ptr1 = (int *)A; WRONG · int A[m][n], *aux[m], **ptr2; ptr2 = (int **)aux; for ...
🌐
GeeksforGeeks
geeksforgeeks.org › c language › c-pointer-to-pointer-double-pointer
C - Pointer to Pointer (Double Pointer) - GeeksforGeeks
A 2D array consists of multiple 1D arrays arranged in rows and columns. A double pointer can be used to create a dynamic 2D array, where it points to an array of row pointers, and each row is allocated separately using malloc().
Published: July 18, 2026
Top answer
1 of 3
24

If the code you reference in your question was given to you by your professor as an example of the use of pointer arrays of pointers to pointers, I'm not sure how much good that class will actually do. I suspect it was either provided as a debugging exercise or it may have been your attempt at a solution. Regardless, if you simply compile with Warnings enabled, you will find a number of problems that need attention before you advance to debugging your code.

Regarding the code you reference, while you are free to use a global text buffer, you are far better served by not using a global buffer and passing a pointer to your data as required. There are some instances, various callback functions, etc. that require global data, but as a rule of thumb, those are the exception and not the rule.

Your question basically boils down to "How do I properly use an array of pointers and double-pointers (pointer-to-pointer-to-type) variables. There is no way the topic can be completely covered in one answer because there are far too many situations and contexts where one or the other can be (or should be) used and why. However, a few examples will hopefully help you understand the basic differences.

Starting with the array of pointers to type (e.g. char *array[]). It is generally seen in that form as a function argument. When declared as a variable it is followed with an initialization. e.g.:

char *array[] = { "The quick",
                  "brown fox",
                  "jumps over",
                  "the lazy dog." };

char *array[]; by itself as a variable declaration is invalid due to the missing array size between [..]. When used globally, as in your example, the compiler will accept the declaration, but will warn the declaration is assumed to have one element.

The elements of array declared above are pointers to type char. Specifically, the elements are pointers to the string-literals created by the declaration. Each of the strings can be accessed by the associated pointer in array as array[0], ... array[3].

A pointer to pointer to type (double-pointer), is exactly what its name implies. It is a pointer, that holds a pointer as its value. In basic terms, it is a pointer that points to another pointer. It can be used to access the members of the array above by assigning the address of array like:

char **p = array;

Where p[1] or *(p + 1) points to "brown fox", etc.

Alternatively, a number of pointer to pointer to type can be dynamically allocated and used to create an array of pointers to type, that can then be allocated and reallocated to handle access or storage of an unknown number of elements. For example, a brief example to read an unknown number of lines from stdin, you might see:

#define MAXL 128
#define MAXC 512
...
char **lines = NULL;
char buf[MAXC] = {0};
lines = malloc (MAXL * sizeof *lines);
size_t index = 0;
...
while (fgets (buf, MAXC, stdin)) {
    lines[index++] = strdup (buf);
    if (index == MAXL)
        /* reallocate lines */
}

Above you have lines, a pointer-to-pointer-to-char, initially NULL, that is use to allocate MAXL (128) pointers-to-char. Lines are then read from stdin into buf, after each successful read, memory is allocated to hold the contents of buf and the resulting start address for each block of memory is assigned to each pointer line[index] where index is 0-127, and upon increment of index to 128, index is reallocated to provide additional pointers and the read continues.

What makes the topic larger than can be handled in any one answer is that an array of pointers or pointer to pointer to type can be to any type. (int, struct, or as a member of a struct to different type, or function, etc...) They can be used linked-lists, in the return of directory listings (e.g opendir), or in any additional number of ways. They can be statically initialized, dynamically allocated, passed as function parameters, etc... There are just far too many different contexts to cover them all. But in all instances, they will follow the general rules seen here and in the other answer here and in 1,000's more answers here on StackOverflow.

I'll end with a short example you can use to look at the different basic uses of the array and double-pointer. I have provided additional comments in the source. This just provides a handful of different basic uses and of static declaration and dynamic allocation:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main (void) {

    /* array is a static array of 4 pointers to char, initialized to the 
       4 string-literals that a part of the declaration */
    char *array[] = { "The quick",
                    "brown fox",
                    "jumps over",
                    "the lazy dog." };
    /* p is a pointer-to-pointer-to-char assigned the address of array */
    char **p = array;
    /* lines is a pointer-to-pointer-to-char initialized to NULL, used
       below to allocate 8 pointers and storage to hold 2 copes of array */
    char **lines = NULL;
    size_t narray = sizeof array/sizeof *array;
    size_t i;

    printf ("\nprinting each string-literal at the address stored by\n"
            "each pointer in the array of ponters named 'array':\n\n");
    for (i = 0; i < narray; i++)
        printf (" %s\n", array[i]);

    printf ("\nprinting each string using a pointer to pointer to char 'p':\n\n");
    for (i = 0; i < narray; i++, p++)
        printf (" %s\n", *p);

    p = array;
    printf ("\nprinting each line using a pointer to pointer"
            " to char 'p' with array notation:\n\n");
    for (i = 0; i < narray; i++)
        printf (" %s\n", p[i]);

    /* allocate 8 pointers to char */
    lines = malloc (2 * narray * sizeof *lines);

    /* allocate memory and copy 1st 4-strings to lines (long way) */
    for (i = 0; i < narray; i++) {
        size_t len = strlen (array[i]);
        lines[i] = malloc (len * sizeof **lines + 1);
        strncpy (lines[i], array[i], len);
        lines[i][len] = 0;
    }

    /* allocate memory and copy 1st 4-strings to lines 
       (using strdup - short way) */
    // for (i = 0; i < narray; i++)
    //     lines[i] = strdup (array[i]);

    /* allocate memory and copy again as last 4-strings in lines */
    p = array;
    for (i = 0; i < narray; i++, p++)
        lines[i+4] = strdup (*p);

    p = lines; /* p now points to lines instead of array */
    printf ("\nprinting each allocated line in 'lines' using pointer 'p':\n\n");
    for (i = 0; i < 2 * narray; i++)
        printf (" %s\n", p[i]);

    /* free allocated memory */
    for (i = 0; i < 2 * narray; i++)
        free (lines[i]);
    free (lines);

    return 0;
}

Let me know if you have any questions. It a large topic with a relatively small set of rules that can be applied in whole lot of different ways and in different contexts.

2 of 3
15

My professor wrote that **array is same as *array[]

That is true in some contexts and not true in other contexts.

If used in a function as argument,

void foo(int **array) {}

is the same as

void foo(int *array[]) {}

When declared as variables,

int **array;

is not the same as

int *array[];

Re comment "Why is int **array; not the same as int *array[];?"

Let's address the question with int *array and int array[].

Here are some of the valid and invalid ways to declare the variables.

int *array; // Ok. Uninitialized pointer.
int *array = nullptr; // ok.
int *array = new int; // ok.
int *array = new int[10]; // ok.

const size = sizeof(array); // Size of a pointer. For 32 bit
                            // pointers, this will be 4.
                            // For 64 bit pointers, this will be 8

Contrast that with

int array[]; // Not ok.
int array[] = nullptr; // Not ok.
int array[] = new int; // Not ok.
int array[] = new int[10]; // Not ok.
int array[] = {10, 20, 30}; // Ok.
int array[3] = {10, 20, 30}; // Ok. same as previous

const size1 = sizeof(array); // (size of int)*3
                             /// Unrelated to size of pointers

int array[5] = {10, 20, 30}; // Ok.
int array[5] = {10, 20, 30, 0, 0}; // Same as previus.

const size2 = sizeof(array); // (size of int)*5
                             /// Unrelated to size of pointers

More on the differences:

  1. int *array; is sufficent to declare a variable while int array[] is not. Size of the array must be known at compile time for the latter.

  2. sizeof operator works diferently for int *array; and int array[];.

  3. A variable declared with int * can be reassigned to point to a different location while a variable declared with int [] cannot be reassigned.

    int *array = nullptr;
    array = new int; // Syntactically ok.
    array = new int[10]; // Syntactically ok.
    

    OTOH

    int array[] = {10, 20, 30};
    array = new int[3]; // Not ok. Compiler error.
    array = {50, 60, 70}; // Not ok. Compiler error.
    
  4. A variable declared with int * can point to statically allocated memory as well as dynamically allocated memory. A variable declared with int [] references only statically defined and constant size memory.

The differences apply equally to int **array; and int *array[];.

🌐
MYCPLUS
mycplus.com › home › programming
Double Pointer in C (Pointer to Pointer): Guide + Examples
February 10, 2021 - A double pointer stores the address of a pointer: pptr → address of ptr, *pptr → ptr‘s content, **pptr → the value. Every * is one hop. The essential use case: pass T ** when a function must modify the caller’s T * — allocation ...
Find elsewhere
Top answer
1 of 2
2

For starters this assignment

q = A;

is incorrect because the left operand (having the type int ( ** )[3]) and the right operand (having the type int ( * )[3] after the implicit conversion of the array designator to a pointer to its first element) have different types and there is no implicit conversion between the types.

The compiler can issue an error like this

error: assignment to ‘int (**)[3]’ from incompatible pointer type ‘int (*)[3]’

You could write instead

q = &p;

In this call of printf

printf("*p is : %d\n", *p);

there is used an incorrect argument. The type of the expression *p is int[3]. So in fact you are trying to output a pointer (due to implicit conversion of the array designator to a pointer to its first element) using the conversion specifier %d that is designed to output integers.

Here is a demonstrative program.

#include <stdio.h>

int main(void) 
{
    int A[2][3] = {{1100, 1200, 1300}, {1400, 1500, 1600}};
    int (*p)[3], (**q)[3];
    p = A;
    q = &p;
    
    printf( "A  is : %p\n", ( void * )A );
    printf( "*p is : %p\n", ( void * )*p );
    printf( "*q is : %p\n", ( void * )*q);
    
    return 0;
}

Its output might look like

A  is : 0x7ffdb1c214e0
*p is : 0x7ffdb1c214e0
*q is : 0x7ffdb1c214e0

That is the first call of printf output the initial address of the first element A[0] (of the type int[3]) of the two-dimensional array.

The second call of printf outputs the address of the first element of the first "row" of the two-dimensional array that is &A[0][0].

The third call of printf outputs the value stored in the pointer p that is the address of the first "row" of the two-dimensional array A.

If you want to output the first elements of the array A using the pointers then the program can look the following way.

#include <stdio.h>

int main(void) 
{
    int A[2][3] = {{1100, 1200, 1300}, {1400, 1500, 1600}};
    int (*p)[3], (**q)[3];
    p = A;
    q = &p;
    
    printf( "**p  is : %d\n", **p );
    printf( "***q is : %d\n", ***q);
    
    return 0;
}

Now the program output is

**p  is : 1100
***q is : 1100
2 of 2
1

p is a pointer to integer array of size 3.

Correct.

*p + i points to ith array in A i.e. A[i].

Incorrect. p + i would be a pointer to an array.

When you indirect through the pointer to array, the result is an array, and when you add an integer to an array, the array decays to pointer to element of that array and since *p is an array of integers, the decayed pointer points to an integer element of the array. Thus, the result of *p + i is a pointer to an integer (i'th sibling of the first element of the first array).

What would happen if instead I use double pointers (q in the above code).

I assume that by substituted above code, you mean *q + i.

If you have a pointer to a pointer to an array, then indirecting through the pointer results in a pointer to an array. Adding an integer to pointer to an array gives you pointer to an array that is a sibling.


q = A;

This assignment is ill-formed in C++. An array of arrays of integers is not convertible to a pointer to pointer to an array.

printf("*p is : %d\n", *p);
printf("*q is : %d", *q);//Why ?  

%d is an invalid format specifier for int* as well as for a int (*)[3]. By using invalid format specifier, the behaviour of this program is undefined. That explains all of the behaviour.

🌐
TutorialsPoint
tutorialspoint.com › double-pointer-pointer-to-pointer-in-c
Pointer to Pointer (Double Pointer) in C
August 30, 2019 - If you do need to have a pointer to "c" (in the above example), it will be a "pointer to a pointer to a pointer" and may be declared as − ... Mostly, double pointers are used to refer to a two−dimensional array or an array of strings.
🌐
Zakuarbor
zakuarbor.github.io › blog › double-pointers
A look at Double Pointers - RANDOM BITS
October 25, 2020 - For instance, in the example below, you have a regular pointer to an int named x and an array of int named arr. arr is just a pointer to the first element in the array we allocated and it looks oddly similar to x, an integer variable. Except, we reserved 5 consecutive blocks of size int for the array (i.e.
Top answer
1 of 3
3

Let’s start with:

int arr[][4]={{1,2,3,4},
              {5,6,7,8},
              {9,10,11,12},
             };

print(arr,3,4);

In print(arr,3,4);, arr is an array. Specifically, it is an array of 3 elements, each of which is an array of 4 elements, each of which is an int. Thus, arr is an array of 3 arrays of 4 int. You have probably heard or read that arrays “decay” to pointers. This is a colloquial term. The actual rule, which you can find in clause 6.3.2.1, paragraph 3, of the C 2011 standard, is:

Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type “array of type” is converted to an expression with type “pointer to type” that points to the initial element of the array object and is not an lvalue.

Here is how this rule applies to arr in print(arr,3,4);:

  • arr is an identifier, meaning it is the name of some object. As such, it designates its object. That object is an array of 3 arrays of 4 int.
  • This array is not the operand of sizeof or Alignof or &, and it is not a string literal. So, following the rule, it is converted from an array of 3 arrays of 4 int to a pointer to the first array of 4 int.

What happens next? Nothing. The expression we have is a pointer to an array of 4 int. There is no rule that says a pointer to an array is converted to a pointer to a pointer. We have a pointer to an array, but that array is not used in an expression yet, not in the simple expression arr. So it is not converted.

This means what you are passing to print is a pointer to an array of 4 int. But your declaration for print says it takes a pointer to a pointer to an int. Those are different things, and they are incompatible, so the compiler warns you.

(To see they are incompatible, consider the difference to a pointer to an array of 4 int and a pointer to a pointer to int. The memory at a pointer to an array of 4 int contains 4 int values. The memory at a pointer to a pointer to an int contains a pointer. These are very different things.)

Next, consider:

void print (int **A, int m, int n)
…
    printf("%d  ", *((A+(m * 4) + n)));

We know from above that you ought to change int **A to int (*A)[4], which is a pointer to an array of 4 int. You can also change it to int A[][4], because there is a rule in C that such a parameter declaration will be automatically adjusted to be int (*A)[4], as a convenience. However, suppose you keep it as int **A. Then does *((A+(m * 4) + n)) mean?

Since A is a pointer to a pointer to an int, then A+(m * 4) means to add m * 4 to the pointer. (That is strange spacing, by the way. m and 4 are more tightly bound by the higher-precedence multiplication than A and (m * 4) are by the addition, so why do they have looser spacing? A + m*4 would portray the meaning better.) Then A+(m * 4) + n means to add n to that. In total, we have moved m*4+n elements beyond where A points. Since A points to a pointer, we have advanced the pointer by m*4+n pointers. Then *((A+(m * 4) + n))) dereferences that. When you dereference a pointer to a pointer to an int, you get a pointer to an int. So the result of this expression is a pointer. But you wanted an int.

The link you reference talks about a “2D array”. The kinds of arrays it talks about are implemented using pointers to pointers. To create such an array, you create an array of pointers, and then you set each of those pointers to point to the elements of a row. Then a pointer to that array of pointers acts like a 2D array, in that A[i][j] refers to element j of row i. If you had an array like that, you could refer to element n of row m using A[m][n]. Equivalently, you could refer to it with *(*(A+m)+n). What this expression means is:

  • Take the pointer A and add m to it. Since A points to a pointer to an int, adding m advances the value of the pointer to point to m pointers further along. That is where we should find the pointer to the elements of row m.
  • *(A+m) gets the value of the pointer that A+m points to. This value should be a pointer to the elements of row m, specifically a pointer to the first element (with index 0).
  • *(A+m)+n advances the value of the pointer to point n int further along. That is where we should find element n of row m.
  • *(*(A+m)+n) gets the value of the int that *(A+m)+n points to.

Now suppose instead you changed print to be print(int A[][4], int m, int n). Then your printf statement should use A[m][n], just as before. Or it could use *(*(A+m)+n), also just as before. But, in this case, the expression is evaluated:

  • A is a pointer to an array of 4 int. Adding m to it advances value of the pointer to point m arrays further along.
  • *(A+m) gets the object that A+m points to. This object is an entire array. So this is an expression that designates an array. Following the C rule about arrays in expressions, this array is converted to a pointer to its first element. Thus, *(A+m) becomes a pointer to the first element of the array numbered m.
  • *(A+m)+n advances the value of the pointer to point n int further along. That is where we should find element n of row m.
  • *(*(A+m)+n) gets the value of the int that *(A+m)+n points to.

Thus A[m][n] has the same end result for pointers-to-pointers, for pointers-to-arrays, and for arrays-of-arrays, but the steps it goes through for each are different. C knows the types of each subexpression and processes them differently, to achieve the same result.

Finally, suppose you pass &A[0][0] to print and change its parameter to int *A. Now what is the expression *((A+(m * 4) + n)))? In this case, you are treating the array of 3 arrays of 4 int as one big array of 12 int. Then you calculate where element n of row m is. In this case, A is a pointer to int (not a pointer to a pointer to int). So A+(m * 4) + n is a calculation to where element n of row m ought to be, and *((A+(m * 4) + n))) gets the value of that element.

That is a method you ought to avoid when possible. Generally, you should use C’s built-in methods of addressing array elements and avoid doing your own calculations. Whether it is strictly conforming C code or not may depend on how pedantic you are about interpreting certain passages in the C standard.

2 of 3
2

You expectation that a 2D array will decay to a pointer to a pointer is ill-founded.

To be able to use arr as an argument to print, you have the following options.

  1. Change print to

    void print (int (*A)[4], int m){ // Not need for n. It is 4
    
  2. Change print to use a VLA. For this to work, m and n have to come before A.

    void print(int m, int n, int A[m][n] {
    

Both these changes will require you to change the call also.

Top answer
1 of 3
12

When used as a function parameter

char a[]  // compiler interpret it as pointer to char

is equivalent to

char *a

and similarly, in main's signature, char *argv[] is equivalent to char **argv. Note that in both of the cases char *argv[] and char **argv, argv is of type char ** (not an array of pointers!).

The same is not true for the declaration

char **r;
char *a[10];

In this case, r is of type pointer to pointer to char while a is of type array of pointers to char.
The assignment

r = a;   // equivalent to r = &a[0] => r = &*(a + 0) => r = a

is valid because in this expression again array type a will be converted to pointer to its first element and hence of the type char **.

Always remember that arrays and pointers are two different types. The pointers and arrays equivalence means pointer arithmetic and array indexing are equivalent.

Suggested reading:

  • But I heard that char a[] was identical to char *a.
  • Why are array and pointer declarations interchangeable as function formal parameters?
2 of 3
2

argv is an argument so the array is decayed to pointer and there is no way other than size (int c) to differentiate.

When a double pointer and array of pointer are not the arguments, their syntax may look similar sometimes but their type is different and thus the compiler generates different types of code for both.

When the variable of interest is not the function argument, sizeof will give different size for pointer to pointer and array of pointers.

Slightly related question: extern declaration, T* v/s T[]

🌐
BeginnersBook
beginnersbook.com › 2014 › 01 › c-pointer-to-pointer
C – Pointer to Pointer (Double Pointer) with example
Value of num is: 123 Value of num using pr2 is: 123 Value of num using pr1 is: 123 Address of num is: XX771230 Address of num using pr2 is: XX771230 Address of num using pr1 is: XX771230 Value of Pointer pr2 is: XX771230 Value of Pointer pr2 using pr1 is: XX771230 Address of Pointer pr2 is: 66X123X1 Address of Pointer pr2 using pr1 is: 66X123X1 Value of Pointer pr1 is: 66X123X1 Address of Pointer pr1 is: XX661111 · There are some confusions regarding the output of this program, when you run this program you would see the address similar to this: 0x7fff54da7c58. The reason I have given the address in different format is because I want you to relate this program with the diagram above.
🌐
Reddit
reddit.com › r/learnprogramming › i don't understand double pointers in c
r/learnprogramming on Reddit: I don't understand double pointers in C
September 9, 2020 -

So I understand pointers. An int * would point to the address of an integer. I understand how you could have a struct pointer and all that. I even sort of understand double pointers. An int ** would be a pointer, pointing to another pointer, which is pointing to an integer. I think that's right but I could be wrong. It's just when I see it in code my brain has a hard time grasping it. I'm looking at a past lab from a course to try to understand it, and I just don't really get it.

So in the lab we were given a struct student, which in itself has two pointer variables among others. We have to read in a file, with the first line containing three integers. The first is the number of courses, C. The next integer is N, which is the number of students per course. In the code, they do fscanf to take in the first few integers. I understand that. Then they allocate memory for courses using calloc.

The line is: student** courses = calloc(*C, sizeof(student*));

This is all inside a function which returns another student**. This is where I get lost. A struct double pointer still is hard for me to grasp. My friend said it's like an array of structs, but I still don't really get it.

Maybe if someone could explain them, or give me a resource that will explain them I would really appreciate it.

Top answer
1 of 3
2
Here's the critical piece of information you need to reason about pointers. A pointer is a variable that holds an address. That's it. That's all you need to know. From there you should be able to reason about anything pointer related. It will still be mind bendy for a time, but always start there. int i = 42; This is a variable that holds an integer. No problem. int *p = &i; This is a variable that holds an address. Specifically an address of an integer, but don't really worry about that. Just remember, it's an address. int **double_p = &p; This is also a variable that holds an address. The only difference is what it holds an address of. It holds the address of the variable p. p holds an address of an int. student** courses = calloc(*C, sizeof(student*)); To help understand this, take a step back for a moment. int *foo = calloc(16, sizeof(int)); foo holds the address of an int. calloc sets aside enough memory for 16 ints, and then returns the address of the "zeroth" element of that dynamically allocated array. foo then holds the address of the start of that array. OK, now back to the confusing line of code. student** courses = calloc(*C, sizeof(student*)); courses holds an address. The type of data at that address? Another pointer, specifically, a pointer to a student struct. So, calloc will set aside enough memory for an array to hold a bunch of memory addresses. calloc is going to return the address of the "zeroth" element of that array. Each element of that array will be able to hold a memory address of a student struct.
2 of 3
1
A pointer can be thought of as a reference to something else by specifying the location of that thing. If you want to deliver a package to my house, you aren’t going to ask me to bring my house to you because that’s silly. Instead, you ask me for the address of my house and then you go to that address and drop off the package. You have to dereference (go to an address) just once to get to the house, so this is a single pointer. A pointer to a pointer is the same thing, just with another reference layer. I don’t want anyone to overhear where my house is, so instead of telling you it’s address directly, I write the address on a piece of paper and I hide it somewhere. I then tell you where to find the piece of paper. To get to my house, you first have to go to the paper’s address, read it, then go to the address that’s written on it. You have to dereference twice in order to get to the house, so this is a double pointer.
🌐
Medium
medium.com › @ryan_forrester_ › double-pointers-in-c-a-practical-guide-ffb91c2628b7
Double Pointers in C++: A Practical Guide | by ryan | Medium
January 7, 2025 - This approach allows you to create arrays of varying row lengths, which isn’t possible with a single-dimension dynamic array. Double pointers are useful when you need to modify a pointer passed to a function.
🌐
Spiceworks
community.spiceworks.com › programming & development
2D Array and Double Pointer in C - Programming & Development - Spiceworks Community
November 18, 2011 - In expressions the name of an array is converted to a pointer to its first element. As arr is a two-dimensional array when arr is converted to int ( * )[4]. When you apply derederencing *arr you ...
🌐
Quora
quora.com › How-do-I-make-2d-array-using-double-pointer
How to make 2d array using double pointer - Quora
Answer (1 of 6): Pointer is a variable which holds the address of another variable and array is collection of consecutive location of a particular data type. So we can use pointer to allocate memory for an array. allocating memory for integer type can be done like this : [code]int *num; int n =...
🌐
SkillVertex
skillvertex.com › blog › c-pointer-to-pointer-double-pointer
C – Pointer To Pointer (Double Pointer)
May 10, 2024 - For changing the value of a double pointer, we can use a triple pointer, such as int ***t_ptr. ... This concept extends further, allowing us to use “level – x + 1” pointers to change the value of a “level – x” variable, and this can be carried to higher levels as needed. Ans. Declaring a 2D array like int input[][c_in] doesn’t make the computer interpret these as pointers.
🌐
Quora
quora.com › What-is-the-purpose-of-a-double-pointer-for-arrays
What is the purpose of a double pointer for arrays? - Quora
Answer (1 of 4): Variable addresses are stored via pointers. Therefore, the first pointer is utilized to store the address of the second pointer when we define a pointer to pointer. It is called a double pointer as a result. Algorithm Begin Declare v of the integer datatype. Initialize v = 76...