Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 理解指针到指针的概念_C_Pointers - Fatal编程技术网

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

我是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);
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。有关测试,请参阅。我们可以想象,当试图将字符转换为指针时,符号传播就会发生。