13

I have the following source:

#include <iostream>
using namespace std;

void main(int j)
{
    char arr[10][10];
    char** ptr;
    ptr = arr;
}

when I compile it using VS2010 I get this error:

error : a value of type "char (*)[10]" cannot be assigned to an entity of type "char **"

I thought arrays in c++ were just pointers. So a char[][] could also be char**. What am I doing wrong?

atoMerz
  • 7,534
  • 16
  • 61
  • 101
  • The C FAQ covers this: http://c-faq.com/aryptr/pass2dary.html – NPE Dec 12 '11 at 17:13
  • 6
    "I thought arrays in c++ were just pointers" - if you could do me a favour: find the person who told you that, call them a muppet, and point them at this question. If you read it in a book, take it back for a refund. If it was a library book, put a bit of paper into that page with some relevant URLs and a note that the author is a muppet. – Steve Jessop Dec 12 '11 at 17:26
  • possible duplicate of [conversion of 2D array to pointer-to-pointer](http://stackoverflow.com/questions/8203700/conversion-of-2d-array-to-pointer-to-pointer) – kiranpradeep Apr 17 '15 at 16:18

8 Answers8

12

Arrays aren't pointers.

An array decays to a pointer in most circumstances, but this isn't recursive. So a T[] decays to a T *, but a T[][] doesn't decay to a T**.

I suggest reading the whole of the C FAQ chapter on arrays and pointers; in particular, the section on 2D arrays and pointers-to-pointers.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
11

The existing answers, though correct, don't make it very clear that there is a fundamental reason (apart from the language rules) why you cannot cast char [10][10] to char **. Even if you force the cast by saying something like

char arr[2][2];
char ** ptr = (char **)arr;

it won't actually work.

The reason is that in C and C++ a two-dimensional array is laid out in memory as an array of arrays. That is, in C a two-dimensional array is laid out in memory as a single allocation,

arr -> arr[0][0]
       arr[0][1]
       arr[1][0]
       arr[1][1]

You'll notice that arr doesn't point to a char * but to arr[0][0] which is a char; therefore, while arr can be cast to a char *, it cannot be cast to a char **.

The correct forced cast would be

char arr[2][2];
char * ptr = (char *)arr;

If you don't want to force the cast (always a good idea if possible!) you would say

char arr[2][2];
char * ptr = arr[0];

or, to make the outcome clearer,

char arr[2][2];
char * ptr = &arr[0][0];

And you now have (in effect) a pointer to an array of 4 characters. [Proviso: I can't find anything in the C standard that prohibits an implementation from adding padding between two rows of an array, but I don't believe that any real-world implementations do so, and common coding practice depends on the assumption that there will be no such padding.]

If you really needed to convert arr to a char ** you would have to explicitly create an array of pointers:

char arr[2][2]
char * arr_ptrs[2];
char ** ptr;
arr_ptrs[0] = arr[0];
arr_ptrs[1] = arr[1];
ptr = arr_ptrs;

The C language could in principle do this for you automatically if you tried to cast a two-dimensional array to a pointer-to-pointer but that would violate the programmer's expectation that a cast does not have side-effects such as allocating memory.

In Java, by way of comparison, a two-dimensional array is always an array of pointers to arrays, so that the array

char arr[][] = { {'a', 'b'}, {'c', 'd'} };

is laid out in memory as three separate allocations, in arbitrary order and not necessarily adjacent,

arr -> arr[0]
       arr[1]

arr[0] -> arr[0][0]
          arr[0][1]

arr[1] -> arr[1][0]
          arr[1][1]

You will immediately notice that this requires more memory than the equivalent C array, and is slower to evaluate at runtime. On the other hand, it does allow the rows of an array to have different lengths.

Harry Johnston
  • 35,639
  • 6
  • 68
  • 158
6

The types char[10][10] and char** and char (*)[10] are all different types. However, the first one cannot convert into the second one, it can convert into the third one.

So try this:

char arr[10][10];
char (*ptr)[10];
ptr = arr; //ok

It will work, because as I said object of type char[10][10] can convert into an object of type char (*)[10]. They're compatible types.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 1
    One question: Isn't `char(*ptr)[10]` a pointer to a 1d char array? If so, isn't a 1d char array same as 'char*'? If this is also true, then I have a pointer to a pointer to a char -> `char**`. – atoMerz Dec 12 '11 at 17:25
  • 1
    @AtoMerZ: No. 1D array is not `char*`. `1D` array can convert into `char*`. But chained conversion is not allowed in C++. There is only one conversion from `char[10][10]` to `char (*)[10]`. And no further conversion. If `A` can convert into `B`, and `B` can convert into `C`. then you cannot write `C=A` which is chained conversion, which is not allowed. – Nawaz Dec 12 '11 at 17:28
  • *"Isn't char(*ptr)[10] a pointer to a 1d char array?"* -- It's more specific than that. It's specifically a pointer to a 1d array of *10* characters, no more, no less. – Benjamin Lindley Dec 12 '11 at 17:30
1

The error exactly tells you whats wrong a double dimensional array can be assigned to an pointer to array not an double pointer. So what you need is:

char (*ptr)[10] = arr; 

What am I doing wrong?

First things first
Arrays are not pointers!! but they act sometimes like pointers.

The rule is:

An expression with array type (which could be an array name) converts to a pointer anytime an array type is not legal, but a pointer type is.

So if you have a single dimensional array:

char arr[10];

Then arr decays to address of the zeroth element it has the type char *. Hence:

char *ptr = arr;

But if you have an 2 dimensional array which is essentially an array of arrays.

 char arr[10][10];

Then arr decays to the pointer to an array of 10 characters.

So, In order to assign arr to something, you will need that something to match the type, which is pointer to an array of characters.
Hence:

char (*ptr)[10] = arr; 
Alok Save
  • 202,538
  • 53
  • 430
  • 533
1

I thought arrays in c++ were just pointers.

No, an array is a set of objects laid out contiguously in memory. In some circumstances, they are convertible to a pointer to the first element.

So a char[][] could also be char**

No. It is convertible to a pointer to the first one-dimensional array (which is the type char (*)[10] mentioned in the error message); but that array is not a pointer, so it is not convertible to a pointer-to-pointer.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
0

When you cast ar[10][10] to pointer you will get a array of pointer as said above *ar[10] and not **ar.

0

Arrays are NOT just pointers -- arrays are arrays. Arrays are not first-class types, however, so you can't use them in many places. The thing that causes your confusion is that array names CAN be implicitly converted into pointers to the array's first element, which means that you can use an array in many places where you need a pointer and it 'just works'. This, however, is not one of those places.

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
0

Arrays are not pointers (I notice a lot of books tend to make you think this, though). They are something completely different. A pointer is a memory address while an array is a contiguous set of some data.

In some cases, an array can decay to a pointer to its first element. You can then use pointer arithmetic to iterate through the contiguous memory. An example of this case would be when passing an array to a function as a parameter.

What you probably want to do here is something like:

char arr[10];
char * i = &arr[0];

Obviously you'll need to use 2D arrays and char** in your case. I'll leave that to you to figure out :)

MGZero
  • 5,812
  • 5
  • 29
  • 46