4

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 i.e. 0x58. But in (char **)names case it thinks that as pointer to pointer and when dereferencing that it gives the whole address i.e.0x400658. 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 ?

2
  • 2
    Note that casting a pointer to the wrong type, then dereferencing it, is undefined behaviour. (AFAIK you're allowed to cast a pointer to the wrong type, as long as the only thing you do with it is cast it back; and this also does not apply to function pointers) Commented Mar 21, 2015 at 7:23
  • @immibis not true. Some type combinations are allowed; for example casting to char * and dereferencing . Search "strict aliasing rule" to get full list of allowed combinations (also allow for alignment). Commented Mar 21, 2015 at 8:55

3 Answers 3

3

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.

Sign up to request clarification or add additional context in comments.

5 Comments

3rd line isn't right. There is no value truncation (that would be (char)names). Instead, one byte is read from the memory location in which names[0] is stored.
@MattMcNabb, you are right, also address are on 8 bytes, I will try to correct it.
Thanks for the detailed explanation Orace, but i still trying to understand 0xec part - how come this converted to -12 ? 0xec decimel value is 236 and its ascii values is [ ASCII code 236 = ý ( Lowercase letter y with acute accent )] ..when converting to 8 byte integer shouldn't it be 0xec as you explained before ?
oh okay now I got it...these are signed integer and binary value for 0xec would be like -12 and now i see why it printed 0xffffffec - Is that correct ?
Char is a signed type, after a coffee, I can tell that for a (signed) char 0xEC is -20. (int)((char) 0xEC) is also -20 and is coded 0xFFFFFFec. See ideone.com/bCAfCb for testing. We can imagine that sign propagation occur when there is an attempt to converted a char to a pointer.
2

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.

5 Comments

(char *)names doesn't pretend anything; it performs a conversion. The result is a pointer to char which points to the same address as names was pointing.
@The Paramagnetic Croissant: I admit that pointer to pointer to char and array of pointers to char are not exactly the same thing, however in the context of this question names variable is being treated as pointer to pointer to char.
@Matt McNabb: Your statement is somewhat contradictory. If result points to the same address as names was pointing - that means no conversion is being made since all the pointers to data are the same. So using C-style cast between pointers to data is basically like telling "assume that memory address stored in this pointer to something actually points to something else".
@trbvm changing type is a conversion . It's making a new pointer which points to the same address but has a different type. The old pointer is unchanged, it still has the same type and value it always had.
@trbvm no, it's not even treated as a pointer. It is treated as an array, and that's why it is converted to a pointer.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.