Передайте двумерный массив функции постоянного параметра

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

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

 #include  #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 и функция используют одномерный массив, предупреждения нет.)

Системная информация:

Ubuntu 14.04LTS

Компилятор: gcc 4.8.2

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


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

Для любого classификатора q указатель на не- q -qualified тип может быть преобразован в указатель на q -qualified версию типа;

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

Если спецификация типа массива включает в себя квалификаторы любого типа, тип элемента имеет такую ​​квалификацию, а не тип массива.

В этой последней цитате сказано, что int const[4] не рассматривается как const -qualified версия int[4] . На самом деле это const квалифицированный массив из 4 const int s. int[4] а int const[4] – массивы разных типов элементов.

Поэтому 6.3.2.3/2 фактически не позволяет преобразовать int const (*)[4] в int const (*)[4] .


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

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

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

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

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

 Sum2D( (const int (*)[])array, ROWS ); 
  • Почему я должен использовать указатель, а не сам объект?
  • Как эта ссылка осуществляется внутри страны?
  • Почему я могу изменить локальную константную переменную с помощью указателей, но не глобальную в C?
  • разница между указателем и ссылочным параметром?
  • Объявление указателей; звездочку слева или справа от пространства между типом и именем?
  • Что такое указатель void и что такое пустой указатель?
  • Почему ссылки не переустанавливаются в C ++
  • Как псевдоним имени функции в Fortran
  • Является ли указатель с правильным адресом и типом все еще всегда действительным указателем с C ++ 17?
  • Как найти «sizeof» (указатель, указывающий на массив)?
  • В C, являются указателями массивов или используются в качестве указателей?
  • Interesting Posts

    Какую функцию hashирования использует Java для реализации classа Hashtable?

    Расшифровка AES256 с помощью node.js возвращает неверную длину конечного блока

    Есть ли разница между GUID и UUID?

    Как вы клонируете repository Git в определенную папку?

    R: Замена значений NA средним часом с помощью dplyr

    Когда переходить от безопасности, управляемой контейнером, к альтернативам, таким как Apache Shiro, Spring Security?

    Почему бы не использовать контейнер IoC для разрешения зависимостей для объектов / бизнес-объектов?

    Есть ли способ переименовать файлы в нижний регистр?

    Почему мой подclass не может получить доступ к защищенной переменной своего суперclassа, когда он находится в другом пакете?

    Почему ArrayList не отмечен ?

    Использование сборочных сборок для загрузки x64 или x32 версии DLL

    Как добавить рабочие дни в текущую дату на Java?

    C ++ Статическая инициализация члена (внутри шаблона)

    Поделитесь подключением Wi-Fi

    Общий TryParse

    Давайте будем гением компьютера.