Printing pointers in C

CPointers

C Problem Overview


I was trying to understand something with pointers, so I wrote this code:

#include <stdio.h>

int main(void)
{
	char s[] = "asd";
	char **p = &s;
	
	printf("The value of s is: %p\n", s);
	printf("The direction of s is: %p\n", &s);
	
	printf("The value of p is: %p\n", p);
	printf("The direction of p is: %p\n", &p);
	
	printf("The direction of s[0] is: %p\n", &s[0]);
	printf("The direction of s[1] is: %p\n", &s[1]);
	printf("The direction of s[2] is: %p\n", &s[2]);
	
	return 0;
}

When compiling it with gcc I get these warnings:

$ gcc main.c -o main-bin -ansi -pedantic -Wall -lm
main.c: In functionmain’:
main.c:6: warning: initialization from incompatible pointer type
main.c:9: warning: format ‘%pexpects typevoid *’, but argument 2 has typechar (*)[4]main.c:11: warning: format ‘%pexpects typevoid *’, but argument 2 has typechar **’
main.c:12: warning: format ‘%pexpects typevoid *’, but argument 2 has typechar ***’

(The flags for gcc are because I must be C89)

Why incompatible types of pointer? Isn't the name of an array a pointer to it's first element? So if s is a pointer to 'a', &s must be a char **, no? And why do I get the other warnings? Do I have to cast the pointers with (void *) in order to print them?

And when running I get something like this:

$ ./main-bin
The value of s is: 0xbfb7c860
The direction of s is: 0xbfb7c860
The value of p is: 0xbfb7c860
The direction of p is: 0xbfb7c85c
The direction of s[0] is: 0xbfb7c860
The direction of s[1] is: 0xbfb7c861
The direction of s[2] is: 0xbfb7c862

How can the value of s and it's direction (and of course the value of p) be the same?

C Solutions


Solution 1 - C

"s" is not a "char*", it's a "char[4]". And so, "&s" is not a "char**", but actually "a pointer to an array of 4 characater". Your compiler may treat "&s" as if you had written "&s[0]", which is roughly the same thing, but is a "char*".

When you write "char** p = &s;" you are trying to say "I want p to be set to the address of the thing which currently points to "asd". But currently there is nothing which points to "asd". There is just an array which holds "asd";

char s[] = "asd";
char *p = &s[0];  // alternately you could use the shorthand char*p = s;
char **pp = &p;

Solution 2 - C

Yes, your compiler is expecting void *. Just cast them to void *.

/* for instance... */
printf("The value of s is: %p\n", (void *) s);
printf("The direction of s is: %p\n", (void *) &s);

Solution 3 - C

If you pass the name of an array as an argument to a function, it is treated as if you had passed the address of the array. So &s and s are identical arguments. See K&R 5.3. &s[0] is the same as &s, since it takes the address of the first element of the array, which is the same as taking the address of the array itself.

For all the others, although all pointers are essentially memory locations they are still typed, and the compiler will warn about assigning one type of pointer to another.

  • void* p; says p is a memory address, but I don't know what's in the memory
  • char* s; says s is a memory address, and the first byte contains a character
  • char** ps; says ps is a memory address, and the four bytes there (for a 32-bit system) contain a pointer of type char*.

cf http://www.oberon2005.ru/paper/kr_c.pdf (e-book version of K&R)

Solution 4 - C

It's not a pointer to character char* but a pointer to array of 4 characters: char* [4]. With g++ it doesn't compile:

> main.cpp: In function ‘int main(int, char**)’: main.cpp:126: error: > cannot convert ‘char (*)[4]’ to ‘char**’ in initialization

Moreover, the linux man pages says:

> p > > The void * pointer argument is printed in hexadecimal (as if by %#x or > %#lx). It shoud be pointer to void.

You can change your code to:

char* s = "asd";
char** p = &s;

printf("The value of s is: %p\n", s);
printf("The address of s is: %p\n", &s);

printf("The value of p is: %p\n", p);
printf("The address of p is: %p\n", &p);

printf("The address of s[0] is: %p\n", &s[0]);
printf("The address of s[1] is: %p\n", &s[1]);
printf("The address of s[2] is: %p\n", &s[2]);

result:

The value of s is: 0x403f00

The address of s is: 0x7fff2df9d588

The value of p is: 0x7fff2df9d588

The address of p is: 0x7fff2df9d580

The address of s[0] is: 0x403f00

The address of s[1] is: 0x403f01

The address of s[2] is: 0x403f02

Solution 5 - C

change line:

char s[] = "asd";

to:

char *s = "asd";

and things will get more clear

Solution 6 - C

You can't change the value (i.e., address of) a static array. In technical terms, the lvalue of an array is the address of its first element. Hence s == &s. It's just a quirk of the language.

Solution 7 - C

Normally, it's considered poor style to unnecessarily cast pointers to (void*). Here, however, you need the casts to (void*) on the printf arguments because printf is variadic. The prototype doesn't tell the compiler what type to convert the pointers to at the call site.

Solution 8 - C

You have used:

char s[] = "asd";

Here s actually points to the bytes "asd". The address of s, would also point to this location.

If you used:

char *s = "asd";

the value of s and &s would be different, as s would actually be a pointer to the bytes "asd".

You used:

char s[] = "asd";
char **p = &s;

Here s points to the bytes "asd". p is a pointer to a pointer to characters, and has been set to a the address of characters. In other words you have too many indirections in p. If you used char *s = "asd", you could use this additional indirection.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionalcuadradoView Question on Stackoverflow
Solution 1 - CJames CurranView Answer on Stackoverflow
Solution 2 - CindivView Answer on Stackoverflow
Solution 3 - CAirsource LtdView Answer on Stackoverflow
Solution 4 - C4pie0View Answer on Stackoverflow
Solution 5 - CSergey GolovchenkoView Answer on Stackoverflow
Solution 6 - CChris ConwayView Answer on Stackoverflow
Solution 7 - CfizzerView Answer on Stackoverflow
Solution 8 - CselwynView Answer on Stackoverflow