Почему вы можете иметь указатель на массив строк в C - PullRequest
0 голосов
/ 17 сентября 2018

почему

char *names [] = {"hello", "Jordan"};

отлично работает

но это не

char names [] = {"hello", "Jordan"};

был бы признателен, если бы кто-то мог мне это объяснить, спасибо :).

Ответы [ 4 ]

0 голосов
/ 17 сентября 2018

Строковый литерал, такой как "hello", хранится в статической памяти в виде массива char с.Фактически строковый литерал имеет тип char [N], где N - количество символов в массиве (включая терминатор \0).В большинстве случаев идентификатор массива затухает до указателя на первый элемент массива, поэтому в большинстве выражений строковый литерал, такой как "hello", затухает до указателя на char элемент 'h'.

char *names[] = { "hello", "Jordan" };

Здесь два строковых литерала затухают до указателей на char, которые указывают на 'h' и 'J' соответственно.То есть здесь строковые литералы имеют тип char * после преобразования.Эти типы согласуются с объявлением слева, и массив names[] (который является не массивом символьного типа, а массивом char *) инициализируется с использованием этих двух значений указателя.

char names[] = "hello";

или аналогично:

char names[] = { "hello" };

Здесь мы сталкиваемся с особым случаем.Идентификаторы массива не преобразуются в указатели на их первые элементы, когда они являются операндами оператора sizeof или унарного оператора &, или когда они являются строковыми литералами, используемыми для инициализации массиватип символа .Так что в этом случае строковый литерал "hello" не затухает до указателя;вместо этого символы, содержащиеся в строковом литерале, используются для инициализации массива names[].

char names[] = {"hello", "Jordan"};

Опять же, строковые литералы будут использоваться для инициализации массива names[], но есть избытокинициализаторы в списке инициализаторов.Это нарушение ограничения в соответствии со Стандартом.Из § 6.7.9 *2 проекта стандарта C11:

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

Соответствующая реализация должна выдать диагностику в случае нарушения ограничения, которая может принимать форму предупреждения или ошибки.На версии gcc, которую я сейчас использую (gcc 6.3.0), эта диагностика является ошибкой:

error: excess elements in char array initializer

Тем не менее, для массивов char, которые инициализируются списком инициализаторов char значения, а не строковые литералы, такая же диагностика является предупреждением, а не ошибкой.

Чтобы инициализировать массив char, который не является массивом указателей, вам понадобится 2d массивchar с здесь.Обратите внимание, что второе измерение является обязательным и должно быть достаточно большим, чтобы содержать наибольшую строку в списке инициализатора:

char names[][100] = { "hello", "Jordan" };

Здесь каждый строковый литерал используется для инициализации массива из 100 char с.в большем 2d массиве char с.Или, другими словами, names[][] - это массив массивов 100 char с, каждый из которых инициализируется строковым литералом из списка инициализаторов.

0 голосов
/ 17 сентября 2018

Первый - это массив указателей на символ. Второй массив массивов и должен выглядеть как char names[] = {'a', 'b', 'c'}

0 голосов
/ 17 сентября 2018

char name[] - это массив символов, в котором вы можете сохранить слово:

char name[] = "Muzol";

Это то же самое из:

char name[] = {'M', 'u', 'z', 'o', 'l', '\0'}; /* '\0' is NULL, it means end of the array */

И char* names[] - это массив массивов, где каждый элемент первого массива указывает на начало элементов второго массива.

char* name[] = {"name1", "name2"};

Это то же самое из:

char name1[] = {'n', 'a', 'm', 'e', '1', '\0'}; /* or char name1[] = "name1"; */
char name2[] = {'n', 'a', 'm', 'e', '2', '\0'}; /* or char name2[] = "name2"; */
char* names[] = { name1, name2 };

Таким образом, в основном names[0] указывает на &name1[0], где он может читать память до name1[5], где он находит символ '\0' (NULL) и останавливается. То же самое происходит для name2[];

0 голосов
/ 17 сентября 2018

Здесь

char *names [] = {"hello", "Jordan"};

names - это массив символов-указателей , т.е. он может содержать указатели, т.е. names каждый элемент сам по себе является одним массивом символов.Но здесь

char names [] = {"hello", "Jordan"};

names - это просто массив символов , т. Е. Он может содержать только один массив символов, например "hello", а не несколько.

Во втором случае, например,

int main(void) {
        char names[] = {"hello", "Jordan"};
        return 0;
}

при компиляции (советуем компилировать с -Wall -pedantic -Wstrict-prototypes -Werror флажками), компилятор ясно говорит:

ошибка: лишние элементы в инициализаторе массива символов

, что означает, что в этом случае вы не можете иметь более одного массива символов.Правильным является

char names[] = {'h','e','l','l','o','\0'}; /* here names is array of characters */

Редактировать: - Также есть больше возможностей, если синтаксис names выглядит следующим образом

char names[] = { "hello" "Jordan" }; /* its a valid one */

тогда здесь оба helloи Jordan присоединяется и становится единым массивом символов helloJordan.

char names[] = { "helloJordan" }; 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...