const and array of array (of array ...)

M

Mara Guida

Imagine I have an array of arrays of ints and want to sum all the
ints.

#include <stdio.h>

int sumints(int arr[3][3])
{
int c, r, s=0;
for (r=0; r<3; r++)
{
for (c=0; c<3; c++) {
s += arr[r][c];
}
}
return s;
}

int main(void)
{
int my_array[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
printf("sum of ints is %d\n", sumints(my_array));
return 0;
}

I tried to define the sumints() function with constant ints, but the
types are not compatible

int sumints(const int arr[3][3])

I understand arrays 'decay' into a pointer to their first element when
passed to functions.
I understand the elements of the array `my_array` are not int: they
are arrays[3] of int.

I tried several variations on the theme (mostly using typedefs) and
reached the conclusion that
a pointer to an array[3] of int is compatible with
1) a constant pointer to an array[3] of int
2) a pointer to a constant array[3] of int
3) a constant pointer to a constant array[3] of int





Why aren't

int (*a)[3] /* a is a pointer to an array[3] of int */
and
const int (*a)[3] /* a is a pointer to an array[3] of
constant int */

compatible types?


It shouldn't be too hard for the compiler to figure it out, right?
 
D

David RF

Imagine I have an array of arrays of ints and want to sum all the
ints.

        #include <stdio.h>

        int sumints(int arr[3][3])
        {
            int c, r, s=0;
            for (r=0; r<3; r++)
            {
                for (c=0; c<3; c++) {
                    s += arr[r][c];
                }
            }
            return s;
        }

        int main(void)
        {
            int my_array[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
            printf("sum of ints is %d\n", sumints(my_array));
            return 0;
        }

I tried to define the sumints() function with constant ints, but the
types are not compatible

        int sumints(const int arr[3][3])

I understand arrays 'decay' into a pointer to their first element when
passed to functions.
I understand the elements of the array `my_array` are not int: they
are arrays[3] of int.

I tried several variations on the theme (mostly using typedefs) and
reached the conclusion that
        a pointer to an array[3] of int is compatible with
                1) a constant pointer to an array[3] of int
                2) a pointer to a constant array[3] of int
                3) a constant pointer to a constant array[3] of int

Why aren't

        int (*a)[3]    /* a is a pointer to an array[3] of int */
and
        const int (*a)[3]    /* a is a pointer to an array[3] of
constant int */

compatible types?

It shouldn't be too hard for the compiler to figure it out, right?

Take a look to this thread:
http://groups.google.com/group/comp.lang.c/browse_thread/thread/677fe66ded99b7a2
 
B

Ben Bacarisse

Mara Guida said:
Imagine I have an array of arrays of ints and want to sum all the
ints.

#include <stdio.h>

int sumints(int arr[3][3])
{
int c, r, s=0;
for (r=0; r<3; r++)
{
for (c=0; c<3; c++) {
s += arr[r][c];
}
}
return s;
}

int main(void)
{
int my_array[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
printf("sum of ints is %d\n", sumints(my_array));
return 0;
}

I tried to define the sumints() function with constant ints, but the
types are not compatible

int sumints(const int arr[3][3])

I understand arrays 'decay' into a pointer to their first element when
passed to functions.
I understand the elements of the array `my_array` are not int: they
are arrays[3] of int.
Yup...

I tried several variations on the theme (mostly using typedefs) and
reached the conclusion that
a pointer to an array[3] of int is compatible with
1) a constant pointer to an array[3] of int
2) a pointer to a constant array[3] of int
3) a constant pointer to a constant array[3] of int

.... but here you have been led astray, possibly by the compiler's
original error message and subsequent lack of a message.

Type compatibility is very strict and all of your examples are
incompatible with each other. When gcc complains that you are
"passing argument 1 of 'sumints' from incompatible pointer type" it is
true but not the whole story. For example, you can pass an argument
of type int * to function that takes a const int * but these two types
are not compatible.

Parameter passing is defined as assignment in C and pointer assignment
requires that

"both operands are pointers to qualified or unqualified versions of
compatible types, and the type pointed to by the left has all the
qualifiers of the type pointed to by the right" [6.5.16.1 p1]

So, you can pass an int * to a const int * parameter because both are
pointer to qualified or unqualified versions of compatible types (int
in this case) and the type pointed to left (const int) has all the
qualifiers of the type pointed to by the right (int).
Why aren't

int (*a)[3] /* a is a pointer to an array[3] of int */
and
const int (*a)[3] /* a is a pointer to an array[3] of
constant int */

compatible types?

In this case, both are not pointers to qualified or unqualified
versions of compatible types. The two types pointed to are int[3] and
const int[3] and neither of these is qualified, so the only issue
whether are they compatible and they are not. (Arrays are compatible
only if the element types are compatible and int and const int are
not.)

The point of all this verbiage is that when assigning and passing
parameters a qualifier can be added only to[1] the immediately
pointed-to type and not to the element type of a pointed-to array or,
indeed, of another pointer.

The compiler resorts to saying "not compatible" partly because that
is indeed true but mainly, I suspect, because there is no word for
this slightly weaker "assignable" type test.
It shouldn't be too hard for the compiler to figure it out, right?

With the correction that actual compatibility is not the issue, you
have a valid point and it has come up here often -- most usually when
passing a T ** to a function with a const T ** parameter. There is
not good technical answer. C went with a simple rule that makes some
obvious things need a cast (C++, for example, has a more complex rule
that permits such things).

[1] Parameters themselves can also be declared const but that is
ignored for all these determinations.
 
D

David RF

Imagine I have an array of arrays of ints and want to sum all the
ints.

        #include <stdio.h>

        int sumints(int arr[3][3])
        {
            int c, r, s=0;
            for (r=0; r<3; r++)
            {
                for (c=0; c<3; c++) {
                    s += arr[r][c];
                }
            }
            return s;
        }

        int main(void)
        {
            int my_array[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
            printf("sum of ints is %d\n", sumints(my_array));
            return 0;
        }

I tried to define the sumints() function with constant ints, but the
types are not compatible

        int sumints(const int arr[3][3])

I understand arrays 'decay' into a pointer to their first element when
passed to functions.
I understand the elements of the array `my_array` are not int: they
are arrays[3] of int.

I tried several variations on the theme (mostly using typedefs) and
reached the conclusion that
        a pointer to an array[3] of int is compatible with
                1) a constant pointer to an array[3] of int
                2) a pointer to a constant array[3] of int
                3) a constant pointer to a constant array[3] of int

Why aren't

        int (*a)[3]    /* a is a pointer to an array[3] of int */
and
        const int (*a)[3]    /* a is a pointer to an array[3] of
constant int */

compatible types?

It shouldn't be too hard for the compiler to figure it out, right?

Try this:

#include <stdio.h>

int sumints(const int arr[3][3]);
int sumints(const int arr[3][3])
{
int c, r, s = 0;

for (r = 0; r < 3; r++) {
for (c = 0; c < 3; c++) {
s += arr[r][c];
}
}
return s;
}

int main(void)
{
int arr[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};

printf("sum of ints is %d\n", sumints((const int (*)[])arr));
return 0;

}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,734
Messages
2,569,441
Members
44,832
Latest member
GlennSmall

Latest Threads

Top