Избыточные элементы скалярного инициализатора для указателя на массив целых чисел - PullRequest
26 голосов
/ 13 ноября 2011

Я работаю над упражнением в K & R (пример 5–9) и пытался преобразовать 2D-массив исходной программы в

static char daytab[2][13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

на использование указателей на массив из 13-ти целых чисел, таких как

static char (*daytab)[13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

Но компилятор печатает предупреждение: избыточные элементы в скалярном инициализаторе .

Поиск в Google не помог, и даже K & R пишет при передаче массива в функцию,

myFunction(int daytab[2][13]) {...}

совпадает с

myFunction(int (*daytab)[13]) {...}

Ответы [ 2 ]

29 голосов
/ 13 ноября 2011

Два только частично эквивалентны. Разница в том, что:

static char daytab[2][13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, 
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

объявляет двумерный массив, который включает выделение пространства для массива и обеспечение того, чтобы daytab ссылался на эту память. Тем не менее:

static char (*daytab)[13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, 
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

... объявляет только указатель. Итак, вы пытаетесь инициализировать указатель с помощью инициализатора массива, который работает не так, как ожидалось. Там нет массива; нет памяти, выделенной для массива. Вместо этого происходит то, что первое число в вашем инициализаторе присваивается указателю daytab, и компилятор генерирует предупреждение, чтобы вы знали, что вы указали много дополнительных значений, которые просто отбрасываются. Поскольку первое число в вашем инициализаторе - 0, вы просто устанавливаете daytab в NULL довольно многословно.

Так что, если вы хотите выполнить инициализацию такого рода, используйте первую версию - она ​​распадается на тот же тип указателя, который вы явно объявили во второй версии, так что вы можете использовать его таким же образом. Вторая версия с указателем массива необходима, если вы хотите динамически выделить массив или получить ссылку на другой массив, который уже существует.

Так что вы можете сделать это:

static char arr[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
static char (*ptr)[3] = NULL;

ptr = arr;

... и затем используйте ptr и arr взаимозаменяемо. Или это:

static char (*ptr)[3] = NULL;

ptr = malloc(2 * sizeof(*ptr));

... чтобы получить динамически размещаемый двумерный массив (не массив указателей на одномерные массивы, а реальный двумерный массив). Конечно, в этом случае он не инициализируется.

«Эквивалентность» этих двух вариантов просто означает, что 2D-массив, когда он распадается на указатель на свой первый элемент, распадается на тип указателя, объявленный во втором варианте. Как только версия указателя фактически указана на массив, они эквивалентны. Но версия 2D-массива устанавливает память для массива, где объявление указателя не ... и указателю может быть присвоено новое значение (указывающее на другой массив), где переменная 2D-массива не может.

В C99 вы можете сделать это, хотя (если не static по крайней мере):

char (*daytab)[13] = (char [][13]){
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, 
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
1 голос
/ 25 мая 2018

@ Дмитрий хорошо объяснил, но я хотел добавить, что

static char (*daytab)[13] = { ... };

- это один указатель на массив из 13 char элементов. Компилятор выдает предупреждение, потому что вы передали два массива. Это все равно что пытаться присвоить два адреса одному указателю char *p = {a, b}. В вашей декларации больше элементов, чем необходимо. См. объяснение Geekforgeek о том, что в действительности означает указатель массива.

Что касается ответа на упражнение K & R, рассмотрим

Вариант 1:

static char *daytab[2] = { 
    (char []) {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    (char []) {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
    };} 

или вариант 2:

static char (*daytab)[13] = (char [][13]) { 
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
    };} 

Вариант 1 - это массив из двух char указателей.

Вариант 2 - один указатель массива. Он указывает на массив из 13 char элементов. Так же, как вы можете увеличить указатель char, чтобы получить следующую букву в строке, вы можете увеличить этот указатель массива, чтобы получить следующий массив из 13 char с.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...