simran dhamija simran dhamija - 1 month ago 26
C Question

Char pointers and the printf function

I was trying to learn pointers and I wrote the following code to print the value of the pointer:

#include <stdio.h>

int main(void) {
char *p = "abc";
printf("%c",*p);
return 0;
}


The output is:


a


however, if I change the above code to:

#include <stdio.h>

int main(void) {
char *p = "abc";
printf(p);
return 0;
}


I get the output:


abc


I don't understand the following 2 things:


  1. why did printf not require a format specifier in the second case? Is
    printf(pointer_name)
    enough to print the value of the pointer?

  2. as per my understanding (which is very little), *p points to a contiguous block of memory that contains
    abc
    . I expected both outputs to be the same, i.e.




abc


are the different outputs because of the different ways of printing?

Edit 1

Additionally, the following code produces a runtime error. Why so?

#include <stdio.h>

int main(void) {
char *p = "abc";
printf(*p);
return 0;
}

Answer

For your first question, the printf function (and family) takes a string as first argument (i.e. a const char *). That string could contain format codes that the printf function will replace with the corresponding argument. The rest of the text is printed as-is, verbatim. And that's what is happening when you pass p as the first argument.

Do note that using printf this way is highly unrecommended, especially if the string is contains input from a user. If the user adds formatting codes in the string, and you don't provide the correct arguments then you will have undefined behavior. It could even lead to security holes.

For your second question, the variable p points to some memory. The expression *p dereferences the pointer to give you a single character, namely the one that p is actually pointing to, which is p[0].

Think of p like this:

+---+      +-----+-----+-----+------+
| p | ---> | 'a' | 'b' | 'c' | '\0' |
+---+      +-----+-----+-----+------+

The variable p doesn't really point to a "string", it only points to some single location in memory, namely the first character in the string "abc". It's the functions using p that treat that memory as a sequence of characters.

Furthermore, constant string literals are actually stored as (read-only) arrays of the number of character in the string plus one for the string terminator.

Also, to help you understand why *p is the same as p[0] you need to know that for any pointer or array p and valid index i, the expressions p[i] is equal to *(p + i). To get the first character, you have index 0, which means you have p[0] which then should be equal to *(p + 0). Adding zero to anything is a no-op, so *(p + 0) is the same as *(p) which is the same as *p. Therefore p[0] is equal to *p.


Regarding your edit (where you do printf(*p)), since *p returns the value of the first "element" pointed to by p (i.e. p[0]) you are passing a single character as the pointer to the format string. This will lead the compiler to convert it to a pointer which is pointing to whatever address has the value of that single character (it doesn't convert the character to a pointer to the character). This address is not a very valid address (in the ASCII alphabet 'a' has the value 97 which is the address where the program will look for the string to print) and you will have undefined behavior.