简体   繁体   中英

Understanding pointer to pointer concept

I am a begineer in C and I am trying to understand pointer to pointer concept. I have the following example

int main() {
char *names[]={"Peter", "Dan"};
printf("names = %p\n", names);
printf("(char *)names = %p\n", (char *)names);
printf("(char **)names = %p\n", (char **)names);
printf("*(char *)names = %p\n", *(char *)names);
printf("*(char **)names = %p\n", *(char **)names);
return 0;
}

Output:
names = 0x7fff167f7c00
(char *)names = 0x7fff167f7c00
(char **)names = 0x7fff167f7c00
*(char *)names = 0x58
*(char **)names = 0x400658

Here my question why *(char *)names doesn't return me the 0x400658 ? From the above output i can see that value of (char *)names is 0x7fff167f7c00, now if i dereference this it should show me 0x400658 right ?

Could someone please explain me how this works ?

EDITED after the initial question:

I did some further analysis and figured out some theory but still need help to understand. When doing (char *)names, it thinks that it is pointer to char hence *(char *)names prints 1 byte of the address of 0x400658 ie 0x58. But in (char **)names case it thinks that as pointer to pointer and when dereferencing that it gives the whole address ie0x400658. Below will help newbies like me to understand this more

printf("notes =%p\n", notes);
printf("(char *)notes+1 =%p\n", ((char *)notes+1));
printf("(char **)notes+1 =%p\n", ((char **)notes+1));

Output:
notes =0x7fff75e4c260
(char *)notes+1 =0x7fff75e4c261
(char **)notes+1 =0x7fff75e4c268

Above was my theory but now lets say what i observed is correct but sometimes am getting below output

*(char **)notes =0x4007ec
*(char *)notes =0xffffffec 

here this should be 0xec considering my theory is correct ? why is it appended by ffff ? Am i missing something here ?

Here is how I read it:

// (char*) is an address (of char): 8 bytes
(char *)  names = 0x7fff167f7c00 // actual address of names

// (char**) is an address (of char*): 8 bytes
(char **) names = 0x7fff167f7c00 // actual address of names.

// *(char*) is a char: 1 byte.
*(char *) names = 0x58           // first byte of the first value of names (ie address of "Peter").

// *(char **) is an address (of char): 8 bytes
*(char **)names = 0x400658       // first value of names (ie address of "Peter").

About 0xec .

This code: printf("*(char *)names = %p\\n", *(char *)names); prints a pointer (because of %p ) and the value given is a *(char *) ie a char .

What happen is that the given char (1 byte) is converted to a pointer (8 bytes) before it is printed.

This conversion is intended to fail. You can not have a valid pointer from a single bit of data.

For 0x58 , as char is 88 and 88 as a 8 bytes integer is 0x00..0058 it is printed 0x58 .

Char is a signed type. 0xec , as char is -20, and -20 as a 4 bytes signed integer is 0xffffffec , the sign byte fills all the new bits. That is called sign propagation .

So you can see that 0xec is converted to 0x00000000ffffffec . Why the sign propagation only occurs on the first 4 bytes may have multiple explanations. The first I see is about performance.

Anyway, the char to pointer conversion will depend on the compiler, the target, etc... and because the result is intended to be unusable, it can be anything.

Type of the names variable is a pointer to pointer to char. By using expression *(char *)names you pretend that names is a pointer to char and dereference it, that is type of the *(char *)names expression is char.

You are bringing in errors by type casting a char** object to char* object . Thus you cannot expect to get the same answer in both the cases.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM