-2

If I iterate over an array of chars using a pointer and declared this way:

char my_ary[3] = { 'A', 'B', 'C' };
char *my_p = my_ary;
while(*my_p){
  printf("value of pointer is %c\n", *my_p);
  my_p++;
}

I get the values along with some garbage:

value of pointer is A
value of pointer is B
value of pointer is C
value of pointer is �
value of pointer is �
value of pointer is u
value of pointer is �
value of pointer is �
value of pointer is 

If on the other hand I declare the array as static, I don't get the garbage:

static char my_ary[3] = { 'A', 'B', 'C' };
char *my_p = my_ary;
while(*my_p){
  printf("value of pointer is %c\n", *my_p);
  my_p++;
}

value of pointer is A
value of pointer is B
value of pointer is C

Why is the static keyword affecting this particular case?

pacuna
  • 1,831
  • 16
  • 15
  • 1
    Both examples give undefined behaviour, due to falling off the end of an array. The `static` will affect memory layout of the program, so may change what is in memory immediately past the end of `my_ary`. But the behaviour is still undefined. With another compiler, the first example may work perfectly on Christmas day every year, and the second might consistently print garbage. – Peter Jan 02 '18 at 02:30

3 Answers3

0

You are moving the pointer out of the array bound which is undefined behaviour, so you can't expect anything from it. If you want this loop to work you have to have a NUL character at the end ('\0') or iterate to the length of the array. And static in this case just means that the value will remain between function invocations. This might affect how the compiler manages the memory but without knowing the compiler subtleties it is impossible to tell.

mdatsev
  • 3,054
  • 13
  • 28
  • so that NUL character is added automatically when I declare a pointer instead of an array of chars, i.e. char *my_ary = "ABC"; ? Because in that way it works fine – pacuna Jan 02 '18 at 02:36
  • @pacuna The null character is **not** added automatically. It **happens to** be. – iBug Jan 02 '18 at 02:37
  • Yes you are correct, string literals implictly have it at the end. – mdatsev Jan 02 '18 at 02:38
  • 1
    @pacuna It's not because you define a pointer. It's because you define a **string literal**, which is automatically zero-terminated *in most cases* (but not always). See my answer for a counter-example. – iBug Jan 02 '18 at 02:43
0

Both are undefined behavior because there's no trailing zero terminator to stop the while loop. As soon as my_p goes to my_ary + 3 your dereferencing it triggers UB.

Variables declared as static has a life span as long as the whole program runs, and they are stored in a different place from variables with automatic life span, where there is likely more zeros (because static variables are initialized to zero if not specified), so your loop can end at my_ary + 3. But again, accessing out of bounds is UB, don't rely on it.

You may be able to observe a different output if you write it like this:

static char my_ary[8] = "ABCDEFGH";

This is my test result.

I specifically picked the size of 8 to avoid automatic zeros in paddings (due to memory alignment). Your loop on static array stopping is likely because there are static variables of other types in its adjacency, leaving zero-initialized paddings in between, thus terminating your loop.

When you define a pointer pointing to a string literal, the behavior is well-defined because string literals have an implicit null character at the end of them. For example:

char c1[] = {'a', 'b', 'c'}, c2[] = "abc";
printf("%d %d\n", sizeof c1, sizeof c2);
// Output: 3 4

So in this way, when your pointer reaches the null terminator, the loop stops.

iBug
  • 35,554
  • 7
  • 89
  • 134
  • can you add a small explanation of why it works fine with a string literal so I can accept this answer? – pacuna Jan 02 '18 at 02:51
0

I don't get the garbage:..

So what? You think that is right? Well it is undefined behavior.

Here putting static and then getting a correct output made you think - if this is correct. Well this is not.

char my_ary[3] = { 'A', 'B', 'C' };

You don't like \0 that's why you are just storing 3 characters. There is no space for \0. So this loop never terminates.

static char my_ary[3] = { 'A', 'B', 'C' };

Still the same logic applies. In your case the next byte after A..C is 0. That's why loop terminated. This is still undefined behavior. We don't know what will happen next time we run it.

If you do

static char my_ary[3] = "ABC";

here again

my_ary[3] is equivalently {'A','B','C'}. Yes there is no \0. So if you pass it where null terminated char array is expected it will invoke undefined behavior again.

user2736738
  • 30,591
  • 5
  • 42
  • 56