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:
why did printf not require a format specifier in the second case? Is printf(pointer_name)
enough to print the value of the pointer?
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;
}
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.
why did printf not require a format specifier in the second case? Is printf(pointer_name) enough to print the value of the pointer?
With your code you told printf to use your string as the format string. Meaning your code turned equivalent to printf("abc")
.
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
If you use %c
you get a character printed, if you use %s
you get a whole string. But if you tell printf to use the string as the format string, then it will do that too.
char *p = "abc";
printf(*p);
This code crashes because the contents of p
, the character 'a'
is not a pointer to a format string, it is not even a pointer. That code should not even compile without warnings.
You are misunderstanding, indeed when you do
char *p = "Hello";
p
points to the starting address where literal "Hello" is stored. This is how you declare pointers. However, when afterwards, you do
*p
it means dereference p
and obtain object where p
points. In our above example this would yield 'H'. This should clarify your second question.
In case of printf just try
printf("Hello");
which is also fine; this answers your first question because it is effectively the same what you did when passed just p
to printf.
Finally to your edit, indeed
printf(*p);
above line is not correct since printf expects const char *
and by using *p
you are passing it a char
- or in other words 'H' assuming our example. Read more what dereferencing means.
- why did printf not require a format specifier in the second case? Is printf(pointer_name) enough to print the value of the pointer?
"abc" is your format specifier. That's why it's printing "abc". If the string had contained %
, then things would have behaved strangely, but they didn't.
printf("abc"); // Perfectly fine!
- why did printf not require a format specifier in the second case? Is printf(pointer_name) enough to print the value of the pointer?
%c
is the character conversion specifier. It instructs printf
to only print the first byte. If you want it to print the string, use...
printf ("%s", p);
The %s
seems redundant, but it can be useful for printing control characters or if you use width specifiers.
The best way to understand this really is to try and print the string abc%def
using printf
.
The %c
format specifier expects a char
type, and will output a single char
value.
The first parameter to printf
must be a const char*
(a char*
can convert implicitly to a const char*
) and points to the start of a string of characters. It stops printing when it encounters a \0
in that string. If there is not a \0
present in that string then the behaviour of that function is undefined. Because "abc"
doesn't contain any format specifiers, you don't pass any additional arguments to printf
in that case.