Printing pointers in C

匿名 (未验证) 提交于 2019-12-03 02:14:01

问题:

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 function ‘main’: main.c:6: warning: initialization from incompatible pointer type main.c:9: warning: format ‘%p’ expects type ‘void *’, but argument 2 has type ‘char (*)[4]’ main.c:11: warning: format ‘%p’ expects type ‘void *’, but argument 2 has type ‘char **’ main.c:12: warning: format ‘%p’ expects type ‘void *’, but argument 2 has type ‘char ***’ 

(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?

回答1:

"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; 


回答2:

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); 


回答3:

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)



回答4:

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



回答5:

change line:

char s[] = "asd";

to:

char *s = "asd";

and things will get more clear



回答6:

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.



回答7:

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.



回答8:

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.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!