1

Hi I got confused to get the explanation for this below, can anyone explain it to me? Thanks in advance.

#include<stdio.h>
int main(){
    char *arr,c;
    arr = &c;

    arr++;
    *arr = 'a';

    arr++;
    *arr = 'b';

    arr++;
    *arr = 'c';

    arr--;
    arr--;

    printf("\narr 1 = %c",arr);
    printf("\narr 2 = %c",arr[1]);
    printf("\narr 3 = %c",arr[2]);
    getch();
    return 1;
    }

Output is :
arr 1 = a
arr 2 = b
arr 3 = c

but if the change the line:

printf("\narr 1 = %c",arr);

with

printf("\narr 1 = %c",arr[0]);

Now Output is:
arr 1 =  
arr 2 = b
arr 3 = c

why 'a' is not getting printed.?

*For all those who are questioning the program as bad coding.. I know its not a good coding practice to use pointer like this, But my question is why arr[0] is not printing anything where as arr[1] & arr[2] is printing what is assigned?

Kuntal Basu
  • 830
  • 2
  • 12
  • 28
  • 4
    You have a more severe problem which is that you have only one `char` but you're attempting to modify 3 different `char`s. – Joseph Mansfield Dec 18 '12 at 16:41
  • 3
    Undefined behaviour, after the first `arr++`, you point to no memory you own. – Daniel Fischer Dec 18 '12 at 16:41
  • 2
    I don't understand the downvotes. I'm agree that the code is very bad. But the guy tried something and it didn't work as he expected. IMHO the question is very legitimate and doesn't deserve downvote. – Luc M Dec 18 '12 at 16:49
  • @LucM "Output is : argc = a argc = b argc = c" is simply not true. I downvote questions that claim nonsense as fact because they show a lack of effort on the asker's part (can't even be bothered to copy/paste actual results). – melpomene Dec 18 '12 at 16:55
  • @EricPostpischil *Except for the change from “argc” to “arr 1”, et cetera* - that's exactly what I mean. – melpomene Dec 18 '12 at 17:16
  • @EricPostpischil Those are the same thing as far as I'm concerned. "Here's my code and here are results I made up" and "here's my code and here are results from a different program" are equally unhelpful for debugging. – melpomene Dec 18 '12 at 17:21
  • @melpomene: Of course conflicting information is unhelpful for debugging, but you stated earlier that your complaint was it showed a lack of effort. Would you like to delete your prior statement, since it appears to be inaccurate? (I see what you mean; I do find your conflicting information to be unhelpful, so I must agree with you.) – Eric Postpischil Dec 18 '12 at 17:28
  • hey guys.. its my mistake, Please don't fight. I am going to edit it. :-) – Kuntal Basu Dec 18 '12 at 17:32
  • As per your last paragraph - it's not bad coding practice, it's code that exhibits undefined behavior. Simple as that. – Luchian Grigore Dec 18 '12 at 17:45

3 Answers3

9

In the first version of the program, what likely happens is:

  • The compiler puts c at some address on the the stack, say 1003 (a single byte).
  • The compiler puts arr at some address on the stack, say 1004-1007 (four bytes).
  • The statement arr = &c; puts the address of c, 1003, into arr.
  • The statement arr++; adds one to arr, so it is now 1004 instead of 1003.
  • The statement *arr = 'a'; writes 'a' to the place where arr points. This is now behavior that is undefined by the C standard. When arr was set to &c, there was only one byte in the object at that location, and the C standard does not guarantee what happens when you write to other locations after incrementing that address outside the object.
  • As it happens in this instance, 1004 points into arr, so you are writing 'a' into one of the bytes of arr. This horribly alters the address that was in arr.
  • Then arr++; increments the address again, and *arr = 'b'; writes 'b' somewhere. We do not know where, because arr has a bad value in it.
  • Then arr++; increments the address again, and *arr = 'c'; writes 'c' somewhere. We do not know where.
  • Then arr--; and arr--; return the address to the value it had after 'a' was written.
  • Then the first printf call passes the value in arr to be printed with a “%c” specifier. “%c” is for printing a character, but the arr you pass it is a pointer. However, you previously wrote 'a' into the pointer, so the value of the pointer has 'a' in one of its bytes.
  • As it happens, when the “%c” specifier is used with a pointer, this implementation of printf prints one of the bytes in the pointer value, in this case the same byte where you wrote 'a'. So “a” is printed. You cannot rely on this happening in other C implementations. This happened in this case only because the compiler happened to place arr in memory just after c in memory, so the statement *arr = 'a'; wrote 'a' into arr. This will not happen in all C implementations. You got “lucky.”
  • After the write of 'a' into arr, arr is pointing somewhere, although we do not know where. Let’s call this location x.
  • The statements arr++; and *arr = 'b'; wrote 'b' to the location x+1.
  • The statements arr++; and *arr = 'c'; wrote 'c' to the location x+2.
  • Then two arr--; statements returned arr to point to x. So arr[1] is the character at x+1, which is 'b', and arr[2] is 'c'. Passing these to printf to be printed with “%c” prints “b” and “c”.

In the second version of the program, when arr[0] is passed to printf:

  • The value of arr is the value that was formed by writing 'a' into one of its bytes. This is some “random” address, pointing to no location we have controlled. Apparently there is a 0 character there, or some other non-printing character, so, when arr[0] is passed to printf, nothing is printed.
  • Passing arr[1] and arr[2] print “b” and “c” because the code wrote 'b' and 'c' to those locations.
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Good answer (+1). Note that, strictly speaking, the behavior is undefined as soon as you do `arr++`, even without dereferencing it. See [this answer](http://stackoverflow.com/a/6566975/768469). (Compilers can and do assume you are not doing this sort of thing and optimize accordingly.) – Nemo Dec 19 '12 at 00:58
  • @Nemo: The first `arr++` is safe. You are allowed to point one beyond the last element of an array, and a single object acts as an array of one element. The first undefined operation in the code is the assignment into that location. – Eric Postpischil Dec 19 '12 at 01:03
6

arr is not equivalent to arr[0], since arr[0] dereferences the array. The correct equivalent would be &arr[0].

By the way, what you're doing invokes undefined behavior, since after incrementing arr, it points to an invalid memory location - originally it points to a single character, so you can't assume there's anything after it.

  • And if what's after it is `arr`, there could be great fun as `*arr = 'a'` changes the address (creating a wild pointer) and the subsequent writes don't just trash locals, but memory locations throughout the program. – Ben Voigt Dec 18 '12 at 16:45
  • @H2CO3 Ok if so, ie, if arr is not equal to arr[0]. then how arr+1 is printing same value as arr[1] ? – Kuntal Basu Dec 18 '12 at 17:58
  • 1
    @KuntalBasu the keyword is undefined behavior. This program is not guaranteed to do anything meaningful. –  Dec 18 '12 at 18:02
6

This is just undefined behavior - arr++; *arr = 'a'; is illegal because arr points to a single char. Anything can happen.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 1
    The first `arr++` is legal since you may point one after the end of the array (and a single `char` is considered an array of length one for the purposes of pointer arithmetic). The subsequent ones, and the writes `*arr = x;` are undefined behaviour. – Daniel Fischer Dec 18 '12 at 16:46
  • 1
    @DanielFischer yes, that's why I included the assignment. – Luchian Grigore Dec 18 '12 at 16:46
  • 2
    This is undefined behavior as well: `printf("\narr 1 = %c",arr);` since the actual type (after promotion) of an argument to a varargs function is different from what is decoded. – Ben Voigt Dec 18 '12 at 16:50
  • Yes I understand this is not legal, then why arr[1] and arr[2] is printing b & c? – Kuntal Basu Dec 18 '12 at 17:27
  • @KuntalBasu because anything can happen... that's what undefined behavior means. – Luchian Grigore Dec 18 '12 at 17:27
  • 1
    @LuchianGrigore: Saying “Anything can happen” (according to the C standard) is not an answer to the question “Why did this happen?” The C standard is not the **only** specification that governs the behavior of computers, and there are reasons that the observed behavior happened. – Eric Postpischil Dec 18 '12 at 17:33
  • @EricPostpischil yes Eric that's what I want to know, I know its a unsafe program, but in C or every programming language everything happens for a logic behind it. I can not assume it random behavior because it is happening every time I run the program. – Kuntal Basu Dec 18 '12 at 17:39
  • Ok, I'm not going to get into a debate over "how undefined is undefined". IMO, it's just stupid asking "why is this illegal code behaving like this". Mind you, this isn't implementation-defined behavior, so you could try to make sense of what the compiler is doing, but pure undefined behavior. If you want to know how it works, produce legal code that exibits the issue. Otherwise, there's no point to it. – Luchian Grigore Dec 18 '12 at 17:40
  • @LuchianGrigore: This is not “illegal” code, since neither law nor the C standard prohibits a person from passing this code to the C compiler. And there are specifications that fully define the behavior: A C compiler itself is built from source code, and the compilers that compile it and the specifications of the machines it runs on and produce output for specify the resulting behavior. – Eric Postpischil Dec 18 '12 at 17:46
  • 1
    @LuchianGrigore: Given a specification of the compiler ideone.com uses and the machine it runs on, certainly we could determine why this particular segmentation fault occurred. But why bother? How would that help anybody learn? The case asked about in this question is interesting because “a” is printed when `arr` is passed to `printf`. That is, a completely wrong call was made, but the “right” character was printed. Something did not just go wrong, something coincided in a way that is misleading to somebody who is learning. There is an opportunity for education here. – Eric Postpischil Dec 18 '12 at 18:05