3

Consider following code:

// hacky, since "123" is 4 chars long (including terminating 0)
char symbols[3] = "123";

// clean, but lot of typing
char symbols[3] = {'1', '2', '3'};

so, the twist is actually described in comment to the code, is there a way to initialize char[] with string literal without terminating zero?

Update: seems like IntelliSense is wrong indeed, this behaviour is explicitly defined in C standard.

Petr Abdulin
  • 33,883
  • 9
  • 62
  • 96
  • Is wasting that single byte really so bad? – nmichaels Aug 02 '11 at 17:06
  • What's wrong the first line? If you want a char array and not a null terminated string then just use that to initialize the array. Put a comment next to it to indicate what you're doing. – Praetorian Aug 02 '11 at 17:07
  • @nmichaels No, but there is some legacy code requirements which apply such restriction on array. – Petr Abdulin Aug 02 '11 at 17:09
  • @Praetorian I'm not sure if first variant is correct, since IntelliSense is producing errors like: IntelliSense: a value of type "const char [16]" cannot be used to initialize an entity of type "Byte [15]" – Petr Abdulin Aug 02 '11 at 17:11
  • @Petr Abdulin: Well then I'm wrong about being about initialize with a string that's bigger than the array you're trying to fit it into. Sorry about that. – Praetorian Aug 02 '11 at 17:15
  • When I want an array of `char` which is not necessarily a string, to make it more noticeable I use `signed char` or `unsigned char` (and a comment!). `unsigned char symbols[3] = "123"; /* not a string */` – pmg Aug 02 '11 at 17:56

3 Answers3

13

This

char symbols[3] = "123";

is a valid statement.

According to the ANSI C Specification of 1988:

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

Therefore, what you're doing is technically fine.

Note that character arrays are an exception to the stated constraints on initializers:

There shall be no more initializers in an initializer list than there are objects to be initialized.

However, the technical correctness of a piece of code is only a small part of that code's "goodness". The line char symbols[3] = "123"; will immediately strike the veteran programmer as suspect because it appears, at face value, to be a valid string initialization and later may be used as such, leading to unexpected errors and certain death.

If you wish to go this route you should be sure it's what you really want. Saving that extra byte is not worth the trouble this could get you into. The NULL symbol, if anything, allows you to write better, more flexible code because it provides an unambiguous (in most instances) way of terminating the array.

(Draft specification available here.)

To co-opt Rudy's comment elsewhere on this page, the C99 Draft Specification's 32nd Example in §6.7.8 (p. 130) states that the lines

char s[] = "abc", t[3] = "abc";

are identical to

char s[] = { 'a', 'b', 'c', '\0' },
t[] = { 'a', 'b', 'c' };

From which you can deduce the answer you're looking for.

The C99 specification draft can be found here.

Richard
  • 56,349
  • 34
  • 180
  • 251
  • Thanks Richard for standard reference, now I can sleep well :-). As for the rest, the final structure is actually a three-dimentional array with a map-like data, which is initialized with characters. So null terminating character is not allowed. – Petr Abdulin Aug 02 '11 at 17:42
  • It is indeed suspect, if the array is to be used as a string, later on. Otherwise, the failing terminator should not make a difference. E.g. some file headers for musical or graphical files (like Windows .bmp files or .tiff files) contain 2 or 4 character "tags" to identify parts of its header information. – Rudy Velthuis Aug 02 '11 at 17:44
  • +1 for a well written answer. FWIW, it is `Rudy`, **not** `Rudi`. – Rudy Velthuis Aug 02 '11 at 18:10
  • 1
    The problem with the way C does this is that it requires you to state the length of the string explicitly. `char s[3] = "abc";` is valid, but if you decide later you only want "ab", you have to update the size from 3 to 2. If you forget, `char s[3] = "ab";` is still valid, but it includes the trailing '\0'. There's no really good way around that, unless you use some tool that generates the declaration for you (no, the C preprocessor isn't powerful enough for the task). If I were redesigning the language, I might add a new form of string literal that doesn't specify a trailing '\0'. – Keith Thompson Aug 02 '11 at 18:31
  • Sorry about that, @Rudy. I fixed it. – Richard Aug 02 '11 at 20:37
  • “is a valid statement” In the C grammar, `char symbols[3] = "123";` is not a statement. It is a declaration. – Pascal Cuoq Sep 13 '13 at 15:09
4

If your array is only 3 chars long, the first line of code is identical to the second line. The '\0' at the end of the string will simply not be stored. IOW, there is nothing "dirty" or "wrong" with it.

Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
  • I'm not sure if first variant is correct, since IntelliSense is producing errors like: IntelliSense: a value of type "const char [16]" cannot be used to initialize an entity of type "Byte [15]" – Petr Abdulin Aug 02 '11 at 17:13
  • 1
    See C99 docs, §6.7.8, point 32 (example 8) which says that: `char t[3] = "abc"` is identical to `t[] = { 'a', 'b', 'c' };`. Now IntelliSense is VC++, and I heard VC++ doesn't do C99 (yet), but this was the same in older standards, IIRC. – Rudy Velthuis Aug 02 '11 at 17:25
  • @Rudy Velthuis: +1 for the C99 reference. – hari Aug 02 '11 at 17:48
0

1) The problems you are mentioning are not problems. 2) Que: Is there a way to initialize char[] with string literal without terminating zero? -- you are already doing that.

hari
  • 9,439
  • 27
  • 76
  • 110
  • Well, C allows us to do many things, writing to unallocated memory, for example, but does that mean it's a correct way to do it? It's working, yes, I just want to be sure this code is correct, or maybe it's not. – Petr Abdulin Aug 02 '11 at 17:19
  • @Petr Abdulin: What you just said seems irrelevant to the question you posted. I tried to answer the question you asked. – hari Aug 02 '11 at 17:25
  • Indeed, my question wasn't quite correct (I was asking about correctness of the code actually), but anyway, thanks. – Petr Abdulin Aug 02 '11 at 17:48