C 理解指针到指针的概念
我是C语言的初学者,我试图理解指针到指针的概念。我有下面的例子C 理解指针到指针的概念,c,pointers,C,Pointers,我是C语言的初学者,我试图理解指针到指针的概念。我有下面的例子 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
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
我的问题是为什么*(char*)名称不返回0x400658?从上面的输出中,我可以看到(char*)名称的值是0x7fff167f7c00,现在如果我取消引用它,它应该显示0x400658,对吗
有人能给我解释一下这是怎么回事吗
在初始问题之后编辑:
我做了一些进一步的分析,得出了一些理论,但仍然需要帮助理解。当执行(char*)名称时,它认为它是指向char的指针,因此*(char*)名称打印0x400658地址的1字节,即0x58。但在(char**)names的情况下,它认为作为指向指针的指针,当取消引用时,它给出了整个地址,即0x400658。下面将帮助像我这样的新手更了解这一点
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
以上是我的理论,但现在让我们说,我观察到的是正确的,但有时会低于输出
*(char **)notes =0x4007ec
*(char *)notes =0xffffffec
考虑到我的理论是正确的,这里应该是0xec?为什么附加ffff?这里缺少什么吗?names变量的类型是指向char的指针。
通过使用表达式*(char*)名称,您可以假装名称是指向char的指针并取消引用它,即*(char*)名称表达式的类型是char。将char**对象强制转换为char*对象会带来错误。因此,您不能期望在这两种情况下得到相同的答案 我是这样读的:
// (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").
关于0xec
此代码:printf(“*(char*)名称=%p\n”,*(char*)名称)
打印指针(因为%p
),给定的值是*(char*)
即char
所发生的情况是,给定的字符(1字节)在打印之前被转换为指针(8字节)
此转换将失败。无法从单个数据位获得有效指针。
对于0x58
,由于字符是88,而作为8字节整数的88是0x00..0058
,因此将打印0x58
Char是一种有符号类型0xec
,由于char是-20,而-20作为4字节的有符号整数是0xffffffec
,符号字节将填充所有新位。这就是所谓的
因此您可以看到0xec
被转换为0x00000000ffffffec
。为什么符号传播只发生在前4个字节上,可能有多种解释。我首先看到的是关于性能的
无论如何,字符到指针的转换将取决于编译器、目标等。。。由于结果是不可用的,所以它可以是任何类型。请注意,将指针投射到错误的类型,然后取消引用,是未定义的行为。(好吧,您可以将指针强制转换到错误的类型,只要您对它所做的唯一事情是将其强制转换回;这也不适用于函数指针)@immibis不正确。允许某些类型组合;例如,强制转换到
char*
并取消引用。搜索“严格别名规则”以获得允许组合的完整列表(也允许对齐)。(char*)名称
不会假装任何东西;它执行转换。结果是指向char的指针指向的地址与name
指向的地址相同。@顺磁性羊角面包:我承认指向char的指针和指向char的指针数组并不完全相同,然而,在这个问题的上下文中,names变量被视为指向char的指针。@Matt McNabb:您的说法有些矛盾。如果结果指向的地址与名称指向的地址相同,则意味着不会进行转换,因为指向数据的所有指针都相同。因此,在指向数据的指针之间使用C样式转换基本上就像告诉“假设存储在指向某个对象的指针中的内存地址实际上指向其他对象”。@trbvm更改类型是一种转换。它正在生成一个指向同一地址但类型不同的新指针。旧指针没有改变,它仍然具有与以前相同的类型和值。@trbvm否,它甚至没有被视为指针。它被视为一个数组,这就是它被转换为指针的原因。第三行不正确。没有值截断(即(char)名称
)。相反,从存储名称[0]
的内存位置读取一个字节。@MattMcNabb,你说得对,地址也在8个字节上,我将尝试更正它。感谢Orace的详细解释,但我仍在试图理解0xec部分-为什么会转换为-12?0xec decimel值为236,其ascii值为[ascii代码236=ý(小写字母y带锐重音)]…当转换为8字节整数时,它不应该是0xec吗?哦,好的,现在我知道了…这些是有符号整数,0xec的二进制值应该是-12,现在我知道它为什么打印0xFFFFEC了-正确吗?Char是有符号类型,喝咖啡后,我可以看出(有符号)Char 0xec是-20。(int)((char)0xEC)也是-20,编码为0xFFFFFFec。有关测试,请参阅。我们可以想象,当试图将字符转换为指针时,符号传播就会发生。