2015-01-21 6 views
3

Я узнал от C Primer Plus, что если вы хотите защитить массив от случайного изменения функции, вы должны добавить модификатор const до объявления указателя в заголовке определения функции.Передайте двумерный массив функции постоянного параметра

После этого разумного совета, в следующем минимальном примере, я пытаюсь передать непостоянный двумерный массив array функциям Sum2D, один параметр, который является pointer-to-const-int[2].

#include <stdio.h> 
#define ROWS 2 
#define COLS 2 
int Sum2D(const int ar[][COLS], int rows); //use `const` to protect input array 
int main(void) 
{ 
    int array[ROWS][COLS]={{1,2},{3,4}}; //the non-constant array 

    printf("%d\n", Sum2D(array,ROWS)); 

    return 0; 
} 

int Sum2D(const int ar[][COLS], int rows) 
{ 
    int total=0; 
    int i,j; 
    for(i=0 ; i<rows ; i++) 
    { 
     for(j=0 ; j<COLS ; j++) 
     { 
      total+=ar[i][j]; 
     } 
    } 
    return total; 
} 

Однако gcc не может успешно скомпилировать этот код, не выполнив следующие предупреждения:

$gcc -ggdb3 -Wall -Wextra -o test test.c 

test.c: In function ‘main’: 
test.c:16:2: warning: passing argument 1 of ‘Sum2D’ from incompatible pointer type [enabled by default] 
    printf("%d\n", Sum2D(array,4)); 
^
test.c:4:5: note: expected ‘const int (*)[4]’ but argument is of type ‘int (*)[4]’ 
int Sum2D(const int ar[][COLS], int rows); 
    ^

1) Почему предупреждение?

2) Как я могу устранить «шум»? (Помимо добавления const к array декларации.)

(Если array и функционируют оба используют один одномерный массив, нет никакого предупреждения.)

System information:

Ubuntu 14.04LTS

Compiler: gcc 4.8.2

+0

Очень прямолинейно. Функция 'Sum2D' ожидает получить массив const 2d, но вы даете ему не const. Это может быть опасно, но не обязательно, поэтому предупреждение, а не ошибка. –

+0

@inneedofhelp На самом деле функция ожидает * указателя * для размера COLS-массива 'const int'. В параметре функции 'const int ar [] [COLS]' является таким же, как 'const int (* ar) [COLS]' – juanchopanza

+0

Есть ли причина для вашего параметра 'rows', а не просто использование определенного измерения? – Mario

ответ

8

Это неудачная «ошибка» в дизайне C; T (*p)[N] неявно конвертирует в T const (*p)[N]. Вам придется либо использовать уродливое литье, либо параметр функции не принимать const.


На первый взгляд похоже, что это преобразование должно быть законным. C11 6.3.2.3/2:

For any qualifier q, a pointer to a non-q-qualified type may be converted to a pointer to the q-qualified version of the type;

Однако также посмотреть на C11 6.7.3/9 (было/8 в C99):

If the specification of an array type includes any type qualifiers, the element type is so-qualified, not the array type.

Эта последняя цитата говорит, что int const[4] является не считается должна быть const -qualified версия int[4]. На самом деле это не const -qualified массив из 4 const int s. int[4] и int const[4] - это массивы различных типов элементов.

Таким образом, 6.3.2.3/2 фактически не разрешает int (*)[4] преобразовывать в int const (*)[4].


Другая странная ситуация, когда этот вопрос с const и массивов проявляется, когда определения типов в использовании; например:

typedef int X[5]; 
void func1(X const x); 
void func1(int const x[5]); 

Это приведет к ошибке компиляции: X const x означает, что x является Const, но он указывает на массив неконстантных int с; тогда как int const x[5] означает, что x не const, но он указывает на массив констант ints!

Дальнейшее чтение here, благодаря @JensGustedt

+1

У вас есть ссылка на это? Интересно, означает ли это, что clang «фиксирует» это как расширение. Я попытался выполнить компиляцию в строгом режиме ('-Wall -Wextra -Wconversion -pedantic-errors -std = cxx', где' xx' равно 89, 99, 11.) – juanchopanza

+0

Уродливым литом, вы имеете в виду что-то вроде '(const int (*) []) '? Я «исправил» его, добавив это в вызов функции. – Naitree

+0

@ Найтри Да. –

0

Вы можете ввести отливать массив при вызове функции.Он не будет автоматически преобразовывать не const в const. Вы можете использовать это.

Sum2D((const int (*)[])array, ROWS); 
+0

На самом деле я все еще получаю предупреждение, используя ваш тип. Я думаю, что вы имеете в виду '(const int (*) [])'. Затем предупреждение исчезло. – Naitree

+0

@Naitree Извините !!!!!! –