简体   繁体   中英

Why can't we use double pointer to represent two dimensional arrays?

Why can't we use double pointer to represent two dimensional arrays?

arr[2][5] = {"hello","hai"};
**ptr = arr;

Here why doesn't the double pointer (**ptr) work in this example?

I'm going to try to draw how

int array[10][6];

and

int **array2 = malloc(10 * sizeof *array2);
for (int i = 0; i < 10; ++i)
    array2[i] = malloc(6 * sizeof **array2);

look like in the memory and how they are different (And that they can't be cast to each other)

array looks like:

 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| | | | | | | | | | | | | ..............| | | (10*6 elements of type int)
 - - - - - - - - - - - - - - - - - - - - - -
< first row >< second row> ...

array2 looks like:

 _ _ _ _ _ _ _ _ _ _ 
| | | | | | | | | | | (10 elements of type int *)
 - - - - - - - - - - 
 | |     ....      |     _ _ _ _ _ _
 | |                \-->| | | | | | | (6 elements of type int)
 | |                     - - - - - -
 | |
 | |      _ _ _ _ _ _
 |  \ -->| | | | | | | (6 elements of type int)
 |        - - - - - -
 |
 |
 |      _ _ _ _ _ _
  \ -->| | | | | | | (6 elements of type int)
        - - - - - -

When you say array[x][y] , it translates into *((int *)array+x*6+y)

While, when you say array2[x][y] , it translates into *(*(array2+x)+y) (Note that for array , this formula also works (read to the end of the post, and then the comments)).

That is, a static 2d array is in fact a 1d array with rows put in one line. The index is calculated by the formula row * number_of_columns_in_one_row + column .

A dynamic 2d array, however is just a 1d array of pointers. Each pointer then is dynamically allocated to point to another 1d array. In truth, that pointer could be anything. Could be NULL , or pointing to a single variable, or pointing to another array. And each of those pointers are set individually, so they can have different natures.

If you need to pass the pointer of array somewhere, you can't cast it to int ** (imagine what would happen. The int values of the cells of array are interpreted as pointers and dereferenced -> Bam! Segmentation fault!). You can however think of array as a 1d array of int [6] s; that is a 1d array of elements, with type int [6] . To write that down, you say

int (*p)[6] = array;

In C, a two-dimensional array is an array of arrays .

You need a pointer-to-array to refer to it, not a double-pointer:

char array[2][6] = {"hello", "hai"};
char (*p)[6] = array;
//char **x = array;  // doesn't compile.

For a double pointer to refer to "2-dimensional data", it must refer to the first element of an array of pointers . But a 2-dimensional array in C (array of arrays) is not the same thing as an array of pointers, and if you just define a 2-D array, then no corresponding array of pointers exists.

The only similarity between the two is the [][] syntax used to access the data: the data itself is structured quite differently.

Having pointer-to-pointer means that each row (or column, if you prefer to think of it that way) can have a different length from the other rows/columns.

You can also represent a 2D array by just a pointer to the start element, and an integer that specifies the number of elements per row/column:

void matrix_set(double *first, size_t row_size, size_t x, size_t y, double value)
{
  first[y * row_size + x] = value;
}

Making an array of pointers to each row in order to obtain an object that "looks like" a multidimensional array of variable size is an expensive design choice for the sake of syntactic sugar . Don't do it.

The correct way to do a variable-sized multidimensional array is something like:

if (w > SIZE_MAX/sizeof *m/h) goto error;
m = malloc(w * h * sizeof *m);
if (!m) goto error;
...
m[y*w+x] = foo;

If you want it to "look pretty" so you can write m[y][x] , you should be using a different language, perhaps C++.

Let's start by talking about legal code. What you've written (assuming a char in front of each declaration) won't compile, for several reasons: you have too many initializers (six char's for arr[0], and its size is 5), and of course, char** p doesn't have a type compatible with char arr[2][5]. Correcting for those problems, we get:

char arr[2][6] = { "hello", "hai" };
char (*p)[6] = arr;

Without any double pointer. If you want to access single characters in the above, you need to specify the element from which they come:

char* pc = *arr;

would work, if you wanted to access characters from the first element in arr.

C++ doesn't have two dimensional arrays. The first definition above defines an array[2] or array[6] of char. The implicite array to pointer conversion results in pointer to array[6] of char. After that, of course, there is no array to pointer conversion, because you no longer have an array.

There is forever a decouple from language to representation.

To some extent, C is nearly Dissendium .

Take the above example, we are trying to assign or transform 2D array into another form,

#include <stdio.h> 
  
int main() 
{ 
        char array[2][6] = {"hello", "hai"};
        int h, i;
        for (h = 0; h < 2; h++) 
                for (i = 0; i < 6; i++) 
                        printf("%c\n", *(*(array+h) + i));
        char (*p)[6] = array;
        for (h = 0; h < 2; h++) 
                for (i = 0; i < 6; i++) 
                        printf("%c\n", *(*(p+h) + i));
        char **x = array;
        for (h = 0; h < 2; h++) 
                        printf("%c\n", *(x+h));
} 

And the output,

h
e
l
l
o

h
a
i



h
e
l
l
o

h
a
i



h
i

Nowadays compilers are so smart they probably will just warn instead of fail, ie

main.c:14:13: warning: initialization from incompatible pointer type [enabled by default]
  char **x = array;

At this point, we should be able to understand double pointer is not double array.

The first h is from hello , the second i is from hai . Notice the distance is 8 bytes, equal to size of a pointer .

Besides, we can also do,

char *y[2];
for (h = 0; h < 2; h++) 
        y[h] = array[h];
for (h = 0; h < 2; h++)
        printf("%s\n", y[h]);
for (h = 0; h < 2; h++)
        for (i = 0; i < 6; i++)
                printf("%c\n", *(*(p+h) + i));

But this assignment is not a one-line statement.

And the output,

hello
hai
h
e
l
l
o

h
a
i

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM