strange compiler behavior on pointer type

I have this program

1
2
3
4
5
6
7
8
9
#include <iostream>
#include <string>

int main()
{
    int x;
    int p[3][3];
    x = p;
}


and it produces error: [Error] invalid conversion from 'int (*)[3]' to 'int' [-fpermissive]

and when I change x from simple int to int * like this

1
2
3
4
5
6
7
8
9
#include <iostream>
#include <string>

int main()
{
    int * x;
    int p[3][3];
    x = p;
}


the error is: [Error] cannot convert 'int [3][3]' to 'int*' in assignment

seems like compiler is adapting from 'int (*)[3]' type to 'int [3][3]' type to keep me from understanding about pointers

the compiler doesn't want me to know about it's secrets what a shame!
Pointer is a variable, whose value is a number that is interpreted as a memory address.

Array is a variable that is not a pointer, but is in some ways similar. However, you have a 2D array, which is a bit more complicated.

You can:
1
2
3
int p[3][3];
int x = p[0][0];  // copies value of first array element into x
int *y = p[0]; // y points to the first element of the first row 


I know pointer basics but I'm worried about why compiler has to adapt

look:
int x; x is always gonna be an integer no matter what my rest of the program is but, x; as long as I don't change x type from other parts of code, it is always gonna be of type int

I'm wondering why compiler changes p from type (*)[3] to type [3][3]

I don't change p. In both situations p is declared as int p[3][3]; then why is this being like a dynamic type{something I hear in javascript type of languages} C is strict type and it should behave strictly and not allow change of type for same statement
I'm wondering why compiler changes p from type (*)[3] to type [3][3]

The compiler does not. You have made the assumption that int p[3][3] has a particular type, and you're wondering why the compiler doesn't agree with your assumption. It's very simple - your assumption is wrong.

int (*)[3] is pointer to an array of 3 int. p's type is not int[3], it is int[3][3].
In many expressions, a C-style array is implicitly converted to a pointer to the first element in the array, and constant conversions can happen silently.

Lets consider with that. The base case is:
1
2
3
T a;
U b;
a = b;  // conversion is required 

That can fail directly, and say: "cannot convert U to T"
However, the compiler could - according to its rules - perform an implicit conversion before failure:
1
2
V c = b; // implicit
a = c; // error, cannot convert V to T 

It is not the type of b alone that triggers implicit conversions, it is the combination of a and b. In you example a was either int or int*, two quite different types.

You are right though, the difference in error messages is baffling. How do other compilers react to this test?
Thanks for your response cire, I'm assuming based on the compiler errors not by myself.
In condition a compiler says; int (*)[3] ------in condition b compiler says; int [3][3] ----and says it about same variable (I didn't change anything in declaration of this variable)

int (*)[3] is pointer to an array of 3 int. p's type is not int[3] (you meant here "not int(*)[3]" right?), it is int[3][3]
I agree with you if this is what you meant

and thanks keskiverto, I haven't tried this on other compilers but one thing is still kind of funny I'd say

1. when I'm comparing with a simple integer, compiler is casting the compared in pointer
2. when I'm comparing with a pointer, compiler is casting the compared in an array

to my mind logical casting try from compiler should've been exactly opposite

I'd say
1. when comparing with simple variable try casting in array
2. when comparing with pointer try casting in pointer to array
I might have a wrong logic please guide me if I'm thinking in a wrong way

thanks in anticipation
I'd say
1. when comparing with simple variable try casting in array
2. when comparing with pointer try casting in pointer to array
I might have a wrong logic please guide me if I'm thinking in a wrong way


IMO you are overthinking.

The compiler is going to give you an error unless the types match (or unless they can match after an implicit cast). In both of your examples, the types do not match, nor can they match with an implicit cast... so you get a "cannot convert type" error as you'd expect.

Whether or not the compiler tries an implicit cast to a pointer or not before it reports the error doesn't really matter... does it?
you're right Disch

now for knowledge purpose I wanna know about what kind of pointer can receive address of int arr[3][3] type
Last edited on
You have already seen the pointer:
1
2
3
const int N = 4;
int arr[3][N];
int (*px)[N] = arr;


The following is mainly about VLA's (a C feature that is not in C++), but it does discuss pointers to arrays:
http://collaboration.cmc.ec.gc.ca/science/rpn/biblio/ddj/Website/articles/CUJ/2002/0201/meyers/meyers.htm
(Particularly Listing 3.)

The px is a pointer. It consumes as much space as any pointer. It holds one address. The compiler, however, carries along the type information for the pointer. That info contains answer to the question: What is px + k?

The px is obviously an address. k is an integer. px+k is an address that you get , when you add k*N*sizeof(int) bytes to px. Essentially, you do get the same with these two:
1
2
arr[2]
px[2]

You will hardly ever give only one index for a 2D array though. Normally you want an (int) element from the array:
assert( arr[2][3] == px[2][3] );

now for knowledge purpose I wanna know about what kind of pointer can receive address of int arr[3][3] type


To expand on keskiverto's example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// The concept is easier to understand with typedefs:
typedef int int3[3];
typedef int3 int33[3];

////////////////////////////
// Declaring arrays:

// These are identical:
int a[3];
int3 a;

// So are these:
int b[3][3];
int3 b[3];
int33 b;

////////////////////////////
// Declaring pointers

// pointer to an int
int* pint;

// pointer to an int3  (all identical):
int3* pint3;
int (*pint3)[3];

// point to an int33 (all identical):
int33* pint33;
int3 (*pint33)[3];
int (*pint33)[3][3];

/////////////////////////
// Assigning pointers

// pointer to an int (all identical):
pint = &b[0][0];
pint = b[0];  // <- implicit cast from int3 to int*

// pointer to an int3 (all identical):
pint3 = &b[0];
pint3 = b;  // <- implicit cast from int33 to int3*

// pointer to int33
pint33 = &b;
Topic archived. No new replies allowed.