6

I am preparing for quiz on programming involving guessing C code outputs.

After long try, I am still struggling to understand the output of the below code:

#include <stdio.h>

char *c[] = {"GeksQuiz", "MCQ", "TEST", "QUIZ"};
char **cp[] = {c+3, c+2, c+1, c};
char ***cpp = cp;

int main()
{
    printf("%s ", **++cpp);
    printf("%s ", *--*++cpp+3);
    printf("%s ", *cpp[-2]+3);
    printf("%s ", cpp[-1][-1]+1);
    return 0;
}

Output

TEST sQuiz Z CQ

Can anyone please help me to understand why is this output?

Mahesha999
  • 22,693
  • 29
  • 116
  • 189
  • 2
    What's the question? – Barry May 17 '15 at 21:37
  • And what is `*--*++cpp` useful for? and it looks worse just because of the lack of white space. – Iharob Al Asimi May 17 '15 at 21:38
  • 1
    I'm voting to close this question as off-topic because it's not a constructive or useful question. – Iharob Al Asimi May 17 '15 at 21:39
  • 5
    Don't assume that you are "poor at pointer arithmetic". These are questions deliberately constructed to confuse you. Nobody writes code like that in the real world. – Greg Hewgill May 17 '15 at 21:39
  • I will delete this question myself if its that bad...but was guessing if anyone in fact tried to guess why the output is like that before downvoting...sometimes its more important to understand technical reason why compiler and executor behave in particular way (and such behavior most of the time is un covered by practically non useful weird code) than just looking at practical use of code, I know this is not real world code but just an *Guess output of the code problem in the quiz*. – Mahesha999 May 17 '15 at 21:44
  • 1
    Actually I liked the quesiton. Not everything has to be applied. – rpsml May 17 '15 at 21:47
  • I'm voting to close this question as off-topic because it's pseudo-randomized pointer crap, not even suitable for homework. – Martin James May 17 '15 at 22:00
  • @Mahesha999 it's not important to know that. It's important to know to NEVER write code i such a manner as you have to resort to specs and/or standards to work out what is happening. Put yourself in place of some poor maintenance engineer who is trying to find some bug.. – Martin James May 17 '15 at 22:03
  • There is a missing `printf("\n");` before the `return 0;` in order for the program to have reliable behaviour. – chqrlie May 17 '15 at 22:26
  • The question is not off topic, it does contain purposely contorted pointer crap, but it is meant to be a test for programmers learning the arcanes of C pointers. As Joel once poetically summarized: understanding C pointers is a capability, you have it or you don't. This test will fail at detecting this capability because of too many false negatives. – chqrlie May 17 '15 at 22:32
  • @rpsml: I like questions about cooking. But they also do not belong here. – too honest for this site May 18 '15 at 00:09
  • 1
    @Mahesha999: Might be nice for a geek quiz, but this forum is to increase code quality. And this is actually the opposite. Regarding the question how it works,, it would be enough to have the commonly used parts (like `c`), to know that, because all terms will be generated recursively. And unless you experience invalid bahaviour, this code actually might work. So: wrong forum. You might better try [here](http://codegolf.stackexchange.com/) – too honest for this site May 18 '15 at 00:36

2 Answers2

10

It will be helpful to create the following temporary variables to understand some of the expressions.

char s1[] = "GeksQuiz";
char s2[] = "MCQ";
char s3[] = "TEST";
char s4[] = "QUIZ";

char *c[] = {s1, s2, s3, s4};
char **cp[] = {c+3, c+2, c+1, c};
char ***cpp = cp;

First printf

printf("%s ", **++cpp);

**++cpp has the side effect of cpp = cpp+1, and evaluates to

**(cpp+1), which is the same as

*(cp[1]), which is the same as

*(c+2), which is the same as:

c[2], which is the same as:

s3, which evaluates to "TEST".(initially it was s2 corrected)

At the end of that statement, cpp is the same as cp+1.

Second printf

printf("%s ", *--*++cpp+3);

*--*++cpp+3 is the same as

*(--(*(++cpp))) + 3, has side effect of cpp = cpp+1, and evaluates to:

*(--(*(cpp+1))) + 3, which is the same as

*(--(*(cp+2))) + 3, which is the same as

*(--(cp[2])) + 3

*(--(cp[2])) + 3 has the side effect of cp[2] = cp[2]-1 = c+1-1 = c, and evaluates to:

*(cp[2]-1) + 3, which is the same as

*(c+1-1) + 3, which is the same as

*(c) + 3, which is the same as

c[0] + 3, which is the same as

s1 + 3, which evaluates to "sQuiz"

At the end of that statement, cpp is the same as cp+2.

Third printf

printf("%s ", *cpp[-2]+3);

*cpp[-2]+3 is the same as

*(cpp[-2])+3, which is the same as

*(cp)+3 because of the previous ++ operations on cpp., which is the same as

c[3]+3, which is the same as

s4+3, which evaluates to "Z".(corrected initially it was s3+3)

Fourth printf

printf("%s ", cpp[-1][-1]+1);

cpp[-1][-1]+1 is the same as

*(cpp-1)[-1]+1, which is the same as

*(*(cpp-1) -1) + 1, which is the same as

*(*(cp+1) -1) + 1, which is the same as

*(cp[1] -1) + 1, which is the same as

*(c+2-1) + 1, which is the same as

*(c+1) + 1, which is the same as

c[1] + 1, which is the same as

s2 + 1, which evaluates to "CQ".

Dytlov
  • 37
  • 7
R Sahu
  • 204,454
  • 14
  • 159
  • 270
7

It helps to draw a picture of the pointers, but that's difficult to do on StackOverflow:

cpp: cp
cp: c+3, c+2, c+1,  c
c:   s0,  s1,  s2,  s3
s0: 'G', 'e', 'K', 's', 'Q', 'u', 'i', 'z', '\0'
s1: 'M', 'C', 'Q', '\0'
s2: 'T', 'E', 'S', 'T', '\0'
s3: 'Q', 'U', 'I', 'Z', '\0'

This is a table showing each of the arrays, plus the static strings (which I've given names to make them easier to talk about).

So now lets look at what the statements do:

printf("%s ", **++cpp);

Increment cpp (changing to point at cp[1]), then deref twice -- the first gets c+2, the second s2 which is then printed: TEST

printf("%s ", *--*++cpp+3);

Increment cpp (now points at cp[2]), dereferece and decrement that (changing cp[2] to now point at c[0]), and dereference again (getting s0). Finally add 3 (s0+3) and print: sQuiz

printf("%s ", *cpp[-2]+3);

Get the value back 2 slots from cp[2] (which is cp[0] == c+3) and then dereference it to get s3. Then add 3, and print: Z

printf("%s ", cpp[-1][-1]+1);

Get the value back 1 slot from cp[2] (which is cp[1] == c+2), then get the value back one slot from that (which is c[1] == s1), then add 1 and print: CQ


The important things to remember are:

  • every * or [] is a dereference which refers to the value pointed at by a pointer
  • increment/decrement operators operate on the last dereferenced thing (or on the variable directly if nothing has been dereferenced yet.
  • unary operators are higher precedence than binary, so (barring parenthesis), all unary postfix operators happen first, then unary prefix, and only then binary.
  • [] is really a unary postfix operator, not an infix binary operator (even though it has two operands), as the second operand is within the brackets.
Chris Dodd
  • 119,907
  • 13
  • 134
  • 226