Почему инициализация массива с тернарным оператором недопустима? - PullRequest
0 голосов
/ 29 января 2019

C позволяет мне использовать char указатели и массивы достаточно взаимозаменяемо, поэтому я часто считаю их полностью взаимозаменяемыми.Но следующий код демонстрирует, что это не так.Может кто-нибудь объяснить, почему инициализация const char d[] с помощью троичного оператора в приведенном ниже коде является недопустимой?

/* main.c */
#include <stdio.h>

int main()
{
  const char* a = "lorem";
  const char b[] = "ipsum";
  int* p;
  const char* c = ( *p ? "dolor" : "sit" );
  const char d[] = ( *p ? "amet" : "consectetur" ); // Why am I an error?
  return 0;
}

Компиляция:

> gcc -g main.c 
main.c: In function \u2018main\u2019:
main.c:10:20: error: invalid initializer
   const char d[] = ( *p ? "amet" : "consectetur" ); // Why am I an error?

Смежный вопрос: в случае, если мойтерминология здесь неточна: какой правильный термин описать const char d[]?Это массив?Массив переменной длины?Что-то другое?Указатель не считается - верно?

Редактировать: Я полагаю, что на этот вопрос не отвечает Инициализация массива с помощью троичного оператора?

RE: упомянутый вопрос, я полагаю, предпосылка немного отличается.Например, принятый ответ объясняет, что { 1, 2 }; (или { 'a', 'b' );) не являются действительными C выражениями, которые я уже знаю и принимаю.Однако "amet"; и "consectetur"; являются действительными C выражениями.

Ответы [ 4 ]

0 голосов
/ 30 января 2019

Вы ошиблись, прежде чем пытаться определить d.В попытке определить c вы задаете вопрос * p?Но р не инициализируется.Поведение, я считаю, не определено.

0 голосов
/ 29 января 2019

6.7.9 Инициализация

...

14 Массив символьного типа может быть инициализирован строковым литералом или строковым литералом UTF-8, необязательно заключенным в фигурные скобки.Последовательные байты строкового литерала (включая завершающий нулевой символ, если есть место или если массив имеет неизвестный размер) инициализируют элементы массива.

C 2011 Онлайн-черновик

( *p ? "amet" : "consectetur" ) это не строковый литерал, ни вычисляет в строковый литерал.Он оценивается как выражение типа char *, которое само по себе не является допустимым инициализатором массива, и эта оценка не происходит до времени выполнения.

Не говоря уже о том, что p неинициализирован, поэтому выражение не определено для начала.

0 голосов
/ 29 января 2019

Строковые литералы слегка волшебны.Обычно (при использовании в выражениях) они представляют собой массивы.Массивы могут "распадаться" (неявно преобразовываться) в указатели, поэтому, например, допустимо

const char *p = "foo";

."foo" здесь нормальное выражение.Вы также можете написать

const char *p;
p = "foo";  // assignment, not initialization

Однако, если строковый литерал используется для инициализации массива, он ведет себя как список символов инициализатора:

char s[] = "foo";
// equivalent to:
char s[] = { 'f', 'o', 'o', '\0' };

В вашем примере

const char d[] = ( *p ? "amet" : "consectetur" );

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

0 голосов
/ 29 января 2019

Вы можете инициализировать массив только списком инициализаторов, а не выражением.В вашем коде

const char* c = ( *p ? "dolor" : "sit" );  

Здесь c - переменная-указатель, а строковые константы - только адрес.Вот почему мы можем использовать троичный оператор, и мы можем присвоить адрес строковой константы указателю c, и мы можем инициализировать массив.Но

const char d[] = ( *p ? "amet" : "consectetur" );

Здесь d - массив, но d представляет адрес массива, а строковые константы также представляют только адрес.Поэтому мы не можем присвоить адрес адресу означает, что строковая константа массива d.Вот почему мы получим ошибку.

Пожалуйста, перейдите по ссылке для лучшего понимания:

https://www.geeksforgeeks.org/whats-difference-between-char-s-and-char-s-in-c/

Инициализация массива с троичным оператором?

...