В контексте объявления {
и }
просто означают «здесь есть группа вещей». Они не представляют объект, адрес или массив.(Примечание. Внутри инициализации есть выражения, и эти выражения могут содержать фигурные скобки в определенных контекстах, которые представляют объекты. Но в коде, показанном в вопросе, фигурные скобки просто группируют вещи.)
В char* m[] = { "Excellent","Good", "bad" };
перечислены три элемента для инициализации m
: "Excellent"
, "Good"
и "bad"
.Таким образом, каждый элемент инициализирует один элемент из m
.
"Excellent"
является строковым литералом.Во время компиляции он становится массивом символов, оканчивающихся нулевым символом.В некоторых ситуациях массив сохраняется как массив:
- Когда он используется в качестве операнда
sizeof
. - Когда он используется в качестве операнда унарного
&
(для получения адреса). - Когда это строковый литерал, используемый для инициализации массива.
Ничто из этого не применимо в этой ситуации."Excellent"
не является операндом sizeof
, это не операнд &
, и он инициализирует только один элемент m
, а не весь массив.Таким образом, массив не сохраняется как массив: по правилу в C он автоматически преобразуется в указатель на свой первый элемент.Затем этот указатель инициализирует m[0]
: m[0]
является указателем на первый элемент "Excellent"
.
Аналогично, m[1]
инициализируется указателем на первый элемент "Good"
, и m[2]
инициализируется указателем на первый элемент "bad"
.
В int* x[] = { {1,2,3},{4,5,6} };
перечислены две вещи для инициализации x
.Каждая из этих вещей сама является группой (из трех вещей).Однако x
- это массив int *
.Каждый элемент x
должен быть инициализирован указателем.Но группа из трех вещей, {1,2,3}
, не является указателем.
Правила Си для интерпретации групп вещей при инициализации массивов и структур немного сложны, потому что они предназначены для обеспечения некоторой гибкости при пропускефигурные скобки, поэтому я должен изучить стандарт немного больше, чтобы объяснить, как они применяются здесь.Достаточно сказать, что компилятор интерпретирует объявление как использование 1
для инициализации x[0]
.Поскольку 1
является int
и x[0]
является int *
, компилятор жалуется, что типы не совпадают.
Дополнительные примечания
char *m[]
не объявляетдвумерный массив.Это массив указателей на char
.Из-за правил C, он обычно может использоваться синтаксически так же, как двумерный массив, так что m[i][j]
выбирает символ j
строки i
.Однако существует разница между char *m[]
и char a[3][4]
, например:
- In
m[i][j]
, m[i]
- указатель.Этот указатель загружается из памяти и используется в качестве базового адреса для [j]
.Затем к этому адресу добавляется j
, и символ загружается из памяти. В этой оценке есть две загрузки памяти. - В
a[i][j]
, a[i]
- массив.Местоположение этого массива вычисляется по арифметике от начала a
.Тогда a[i][j]
- это char
, и его адрес вычисляется путем добавления j
, и символ загружается из памяти. В этой оценке есть одна загрузка памяти.
Существует синтаксис для инициализации массива указателей int
, указывающих на массив int
.Он называется составной литерал .Это редко используется:
int *x[] = { (int []) {1, 2, 3}, (int []) {4, 5, 6} };
Ключевое различие между этими строковыми литералами и составными литералами состоит в том, что строковые литералы определяют объекты, которые существуют в течение времени выполнения программы, но составные литералы, используемые внутри функций, имеют длительность автоматического хранения- он исчезнет, когда ваша функция вернется, и, возможно, раньше, в зависимости от того, где она используется.Программисты-новички С должны избегать использования составных литералов, пока не поймут правила продолжительности хранения.