-3

When I run the code:

char *abc="Goodbye";
for(i=0; i<=7; i++){
    printf("%c\n",*(abc+i)); }

it runs without problem, but when I run the following:

char *der={'a','a','a','a','a'};
for(i=0; i<=4; i++){
    printf("%c\n",*(der+i)); }

it doesn't show the correct results and I receive warnings.

So why is this happening since "Goodbye" and {'a','a','a','a','a'} are arrays of chars?

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
BasilG
  • 43
  • 4
  • Let apart the string literals, I don't see an array. What do you mean? (Note: the first version does not "run without problems". You just don't notice there is a problem, as you likely don't want to print the trailing `\0` of the string literal. And the second invokes undefined behaviour. Your compiler should be yelling at you. If not, enable warnings and never ignore them! – too honest for this site Aug 10 '16 at 21:36
  • 3
    You should listen to the compiler's warnings, and never ignore one unless you fully understand the implications of doing so. The warnings "initialization makes pointer from integer without a cast" and "excess elements in scalar initializer" indicate that your second piece of code does not mean what you think it means. – molbdnilo Aug 10 '16 at 21:42
  • 1
    Related? http://stackoverflow.com/questions/1704407/what-is-the-difference-between-char-s-and-char-s-in-c – Fantastic Mr Fox Aug 10 '16 at 21:50
  • Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself. Questions without a clear problem statement are not useful to other readers. – Fantastic Mr Fox Aug 10 '16 at 21:51
  • 1
    "... and I receive warnings." --> post the warnings and why code has not been changed to remove the warnings. – chux - Reinstate Monica Aug 10 '16 at 21:52
  • The warnings are:initialization makes pointer from integer without a cast – BasilG Aug 10 '16 at 22:01
  • and: excess elements in scalar initializer – BasilG Aug 10 '16 at 22:01
  • "I don't understand the downvotes" --> NMDV, but by not originally posting the warnings, it appears your compiler gave you the answer to your problem then - which was ignored. It is common to include compiler warnings, even if you do not understand them (that is common) as 1) it helps other to help you 2) it helps others to find this post via a search. Including those warning messages in a post improves its quality. Leaving them out reduces it. – chux - Reinstate Monica Aug 10 '16 at 22:43
  • `char *der=(char[]){'a','a','a','a','a'};` or `char der[]={'a','a','a','a','a'};` also `i<=7` --> `i<7` – BLUEPIXY Aug 11 '16 at 00:00

2 Answers2

2

{'a','a','a','a','a'} is not an array but an initializer list, and it can be used to initialize either an aggregate or a scalar.
(Yes, int x = {'a'}; is valid.)

If it's used to initialize a scalar, such as a pointer, only the first value is used, so your declaration of der is equivalent to

char *der = 'a';

You can probably see what the problem is.

So today's programming lessons:

  • When your compiler warns you that something might be wrong, it probably is.
    (Most experienced programmers treat warnings as errors, -Werr. It's an even more important habit for the inexperienced.)
  • If you don't understand what a warning means, don't do anything until you've found out.
molbdnilo
  • 64,751
  • 3
  • 43
  • 82
1

One way to initialize the array - which is related to your second example - is by doing:

char foo[] = {'a', 'b', 'c'};

In this syntax, to the right side of = you provide the array elements as comma separeted values inside a { }. So in the above example, array foo has three elements. First is a, second is b, and third is c. If you wanted a \0 at the end, you need to do it explicitly as char foo[] = {'a', 'b', 'c', '\0'};.

Regarding your second example, answer by @molbdnilo already explains what is semantically wrong with your statment char *der={'a','a','a','a','a'};. If you want to define der as array and initialize it using { }, you can do:

char der[] = {'a','a','a','a','a'};

This way you are actually defining a char array and initializing it with the content you want.

Note that, you NEED to mention the array size if you are not initializing it while defining it. Which means:

char foo[];   // Will give error because no size is mentioned
char foo[10]; // Fine because size is given as 10

However, mentioning size is optional if you initialize the array while defining it, as we saw in the examples above. But, if you mention the size and if your initializer is smaller than the array size, remaining elements will be initialized to 0. Like:

char bar[10] = {'a', 'b', 'c', '\0'};
/* Your arrays' content will be 'a', 'b', 'c', '\0',
 * and all remaning 6 elements will be 0 
 */
sps
  • 2,720
  • 2
  • 19
  • 38
  • 1
    ISO/IEC 9899:2011 §6.4.5 **String literals** ¶6: _In translation phase 7, a byte or code of value zero is appended to each multibyte character sequence that results from a string literal or literals. The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence. For character string literals, the array elements have type char, and are initialized with the individual bytes of the multibyte character sequence. …_ This might be regarded as contradicting 'is not an array'. – Jonathan Leffler Aug 10 '16 at 23:38
  • @JonathanLeffler Thanks for the comment. I have removed the contraditcting part. Now wondering, what happens when we use string literal to initialize the array? Will it also have a static storage duration? Or like I guess, it is only used to initialize the array to LHS of `=`; after which its (string literal's) lifetime ends? Is it even considered as a string literal in this case (while initializing an array)? – sps Aug 11 '16 at 00:07
  • 1
    In a loop like `for (int i = 0; i < 9; i++) { char data[12] = "abcdefghijk"; data[i] = 'X'; printf("[%s]\n", data); }`, I believe that there must be a copy of the string stored somewhere, and the loop code contains an analogue to `memmove()` (or `memcpy()`) that copies from the stored value into the local variable on the stack. I've not disassembled code to prove that hypothesis, but I think it must be roughly equivalent to that. – Jonathan Leffler Aug 11 '16 at 00:12