Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is array initialization with ternary operator illegal?

C lets me use char pointers and arrays interchangeably often enough that I often think of them as completely interchangeable. But the following code demonstrates this is not true. Can anyone please explain why the initialization of const char d[] with the ternary operator, in the code below, is illegal?

/* 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;
}

Compilation:

> 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?

Related question: in case my terminology has been imprecise here: what is the correct term to describe const char d[]? Is it an array? A variable-length array? Something else? It is not considered a pointer - true?

Edit: I believe this question is not answered by Array initialization with a ternary operator?

RE: the referenced question, I believe the premise is slightly different. E.g. the accepted answer explains that { 1, 2 }; (or { 'a', 'b' );) are not valid C expressions, which I know already and accept. However "amet"; and "consectetur"; are valid C expressions.

like image 253
StoneThrow Avatar asked Mar 04 '23 15:03

StoneThrow


2 Answers

6.7.9 Initialization

...
14 An array of character type may be initialized by a character string literal or UTF−8 string literal, optionally enclosed in braces. Successive bytes of the string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.

C 2011 Online Draft

( *p ? "amet" : "consectetur" ) is not a string literal, nor does it evaluate to a string literal. It evaluates to an expression of type char *, which on its own is not a valid array initializer, and that evaluation does not occur until runtime.

Not to mention, p is uninitialized, so the expression is undefined to begin with.

like image 61
John Bode Avatar answered Mar 07 '23 03:03

John Bode


String literals are slightly magical. Ordinarily (when used in expressions), they represent arrays. Arrays can "decay" (implicitly convert) to pointers, which is why e.g.

const char *p = "foo";

is valid. "foo" is a normal expression here. You could also write

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

However, if a string literal is used to initialize an array, it behaves like an initializer list of characters:

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

In your example of

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

the initializer is not a sole string literal; it is an expression. Hence both string literals decay to pointers, and then you get an error because you cannot initialize an array from a pointer. (In fact, you cannot initialize an array from an expression at all.)

like image 27
melpomene Avatar answered Mar 07 '23 05:03

melpomene