5

I have some problems related with this code. The parameter of printf is of type const char* and ... (variable argument list).

1) Why the output of the program is d and not 127?
2) Is it that the +1 would get converted into string and passed to parameter variable of type const char*?

#include<stdio.h>
int main()
{
   printf("%d"+1 , 127); //how this will get executed?
   return 0;
}

Output:

d
Yunnosch
  • 26,130
  • 9
  • 42
  • 54
Goku
  • 81
  • 6
  • 6
    What `"%d"+1` is even supposed to do? – Eugene Sh. Jun 06 '18 at 21:11
  • 1
    The answer to #2 is "definitely not". – lurker Jun 06 '18 at 21:24
  • 3
    If it's not obvious, this is a trick question. The code is like none you will ever see in a real C program (except perhaps by mistake). It doesn't do anything remotely useful. It's just to get you thinking; it's to make sure you understand exactly how strings work, and how pointers work, and how `printf` works. If you know C well, it's immediately obvious what it does, but if it's not obvious to you yet, don't worry; this is not the step that's standing in the way of your making progress learning about normal C programming. – Steve Summit Jun 06 '18 at 22:43
  • Your confusion regarding behavior of string literal followed by +1 is partially caused by the variation in how some languages use '+' for string concatenation, and perform automatic coercion of numeric 1 to string "1". Specifically, "%d"+1 is not concat("%d","1"). – ChuckCottrill Jun 06 '18 at 23:32

2 Answers2

18

First parameter is a pointer to char.
The literal "%d" would be a pointer to the '%', which is implicitly followed by 'd' and '\0'. It is a pointer to char, because that is the C representation of string literals: sequences of characters with a '\0' at the end; represented for use as parameters etc. as a pointer to char.
But "%d"+1, according to pointer arithmetic, is a pointer to 'd', followed by '\0'.
Both are zero-terminated, as fitting for a parameter to printf.

So the output is the same as

printf("d", ignored);

127 turns into "ignored", i.e. it is ignored, because the "d" tells printf not to expect anything, because it does not have any of the special character sequences, e.g. "%someletter". So it will not expect, not look for anything and will not do any printing beyond the perfectly normal string it thinks to have been given.
Note however that the additional parameters, those not covered by anything in the format string, do get evaluated and then ignored. This is relevant, because any side effects (e.g. function calls) of that evaluation do in fact occur.
See e.g. here for details:
http://en.cppreference.com/w/c/io/fprintf

Yunnosch
  • 26,130
  • 9
  • 42
  • 54
  • can you please explain this why 127 will get ignored? – Goku Jun 06 '18 at 21:14
  • 1
    Because `printf("d", ...)` has nothing to do with whatever is coming after `,`. – Eugene Sh. Jun 06 '18 at 21:15
  • one more, why did you say that %d is a pointer, i don't get it. what i have learned is that pointer is a variable which stores address of another variable.. – Goku Jun 06 '18 at 21:17
  • 1
    @Goku Well you are not incorrect, but you should also learn about literals. ""adasf", 'c', 34, 3.4, 3.4F, 3U, 3L, 3UL, 0x34, 08, etc, a lot will be denoted to int, others double, "asd" is an address in read-only memory area that points to the character 'a', read as a string, all characters until '\0' will be read from that address – Edenia Jun 06 '18 at 21:19
  • @Goku in C when you cite a string literal such as `"%d"` you are actually referring to a *pointer to the string "%d" (with trailing 0)* in memory. You really should get a good C textbook and dig into it. A lot of fundamental things to learn there. – lurker Jun 06 '18 at 21:23
  • 1
    @Goku: A string literal such as `"%d"` is an array expression (since strings are stored as arrays). Under most circumstances, array expressions are converted to pointer expressions which point to the first element of the array. If you add 1 to a pointer, the result is a pointer to the next object (in this case, the second character of the string). So `printf` sees the string `"d"` as the first argument. Since `"d"` doesn't have any conversion specifiers in it, `printf` won't check for any additional arguments - the parameter `127` is ignored. – John Bode Jun 06 '18 at 21:28
  • 2
    I can recommend that of several books you flip through in any decent book store, which grips you most. I.e. flip through the pages and the book you do not put down after reading a few paragraphs, that is the right one for you. The favorite book of any user here might be the wrong one, too expensive or take too long to be delivered. Book store, browse, like, buy. That is the 1hour recipe. – Yunnosch Jun 06 '18 at 21:45
  • 2
    @Goku I think you should make more effort to understand this answer, which explains what you see, and why the argument `127` is ignored. A good book will help, but his answer is quite specific to your problem. – Weather Vane Jun 06 '18 at 21:53
  • 1
    Suggest adding that not only is 127 is "ignored", it is OK (well defined) to use `printf()` with extra arguments. `printf("%d" , 127, rand());` is OK. `rand()` is still called, but the results are not used. – chux - Reinstate Monica Jun 06 '18 at 22:15
  • 2
    @chux Good point, any side effects will of course occur before ignoring, edited it into answer. Thanks. – Yunnosch Jun 06 '18 at 22:27
5

Let me try to help and add to @Yunnosch answer, you could do following:

 char *str = "%d";
 printf (str, 127);

and output should be:

127

In above example str is stored in memory like this (this is just an example and in real life addresses are like 0xabcdef12345678):

address | memory
--------+--------------
0       | %
1       | d
3       | \0

so str points to address 0 (or equivalent on your system) which holds %, printf() gets that address and starts reading from there, reads until it hits the NULL character '\0'. Now every time it sees the % it looks for next character d, c, x etc. it reads next argument from argument list. If you supplied d it will output decimal, if you supply c it will print character, x is for hex and there is many more. So printf() will read all characters and replace %<place holder> with appropriate parameter until it hits the NULL character \0, but it will start at supplied address.

Your case:

printf("%d"+1, 127);

is same as:

char *str = "%d";
printf (str + 1, 127); // printf receives address of character `d` as starting point

or it is similar to

char *str = "%d";
char *str1 = str+1; // increment the address of string by one
printf (str1, 127)

in both cases it receives address of d and reads from there until it hits \0.

If you do following:

printf ("%d" + 2, 127);

This would be the same as:

char *str = "%d";
printf (str + 2, 127);

it would output nothing because, printf() will get the address of \0. and as @Yunnosh said 127 would be ignored.

So +1 and +2 do not get converted to a string they get added to the address of the string.

I hope this helps, I think I answered both of your questions.