我是C的新手,有一个关于特定指针声明的问题:
这是我写的一个程序:
#include <stdlib.h>
struct n {
int x;
int y;
};
int main()
{
struct n **p = malloc(sizeof(struct n));
return 0;
}
这里的声明不正确,但为什么不正确呢?
以下是我的思考过程:
malloc
的手册页指定它返回一个指针:
The malloc() and calloc() functions return a pointer to the
allocated memory, which is suitably aligned for any built-in
type.
p
的类型是struct n**
,也就是指向另一个指针的指针。但这个声明在理论上不应该起作用吗?因为:
malloc
返回类型struct n*
(指针(- CCD_ 6指向CCD_
- 所以它本质上是指向另一个指针的指针
- 因此满足CCD_ 8的类型
如果这是一个愚蠢的问题,我很抱歉,但我真的很困惑为什么这不起作用。感谢您提前提供的帮助。
无论如何调用,malloc
的返回类型都不是struct n *
。malloc
的返回类型为void *
。
使用类型为void *
的值初始化struct n **
对象会将其隐式转换为struct n **
。这种隐式转换是允许的,因为初始化的规则遵循C 2018 6.5.16.1 1中的分配规则,该规则规定允许的分配之一为:
…左操作数具有原子、限定或非限定指针类型,并且(考虑左操作数在左值转换后的类型(一个操作数是指向对象类型的指针,另一个是指向合格或非限定版本的
void
的指针,并且左边指向的类型具有右边指向的类型的所有限定符;…
- 和
p
指向malloc
返回的指针
否,值p
初始化为malloc
返回的值。则CCD_ 21指向所分配的存储器CCD_。
此代码为struct n
分配足够的空间(使用malloc(sizeof(struct n))
(,但将该空间的地址分配给struct n **
,即p
,这是错误的。要指向struct n
,请使用struct n *p = malloc(sizeof (struct n));
,或者最好使用struct n *p = malloc(sizeof *p);
。
要指向指向struct n
的指针,请首先创建指向struct n
的指针,就像上面的struct n *p = malloc(sizeof *p);
一样。那么指向该指针的指针将是struct n **pp = &p;
。
如果您想为这些指向指针的指针分配空间,您可以使用struct n **pp = malloc(sizeof *pp);
来完成,然后您可以用*pp = malloc(sizeof **pp);
填充指向struct n
的指针。但是,您不应该在没有充分理由的情况下添加这个额外的分配层。
请注意,MyPointer = malloc(sizeof *MyPointer);
的形式通常比MyPointer = malloc(sizeof (SomeType));
更可取,因为前者会自动使用MyPointer
所指向的类型。后者很容易出错,例如有人错误地输入了MyPointer
的类型,但没有正确设置SomeType
,或者有人后来更改了MyPointer
的声明,但在malloc
调用中省略了对SomeType
的相应更改。
这真的不起作用。在这个例子中,malloc返回一个void*,它指向堆中一个新分配的位置,这个位置足够大,可以容纳一个结构n。
请注意,malloc((返回类型void*,它基本上是指向任何潜在类型的指针,mallock((不返回类型structn*(指向您声明的结构类型的指针(。void*有一个特殊的特性,可以转换为任何其他类型的指针,然后再返回。
总之,这意味着你的代码实际上不起作用,因为结构n**的第一个解引用将是结构n,而不是结构n*。如果您尝试两次取消引用,很可能会得到无效的内存引用并崩溃。
您的代码能够在不崩溃的情况下编译和运行的原因是:
- 编译器自动将void*强制转换为struct n**
- 您永远不会尝试实际取消引用指针,这意味着您永远不会尝试无效的内存引用
简化问题并理解可能出现的问题:
int main()
{
struct n data;
struct n *pData = &data; // skipped in your version
struct n **ppData = &pData;
// struct n **ppData = &data; // Will not compile
// struct n **ppData = (struct n **)&data; // Casting but wrong!
return 0;
}
因为malloc()
返回一个void ptr,所以您可以自由地将指针存储到任何指针数据类型中。如果你把它放错了数据类型。。。