提问人:programme3219873 提问时间:8/26/2022 更新时间:8/26/2022 访问量:108
为什么这个指针声明适用于 malloc()?
Why does this pointer declaration work with malloc()?
问:
我是 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*
- 并指向返回的指针
p
malloc
- 因此,它本质上是指向另一个指针的指针
- 所以满足的类型
p
对不起,如果这是一个愚蠢的问题,但我真的很困惑为什么这不起作用。提前感谢您的任何帮助。
答:
返回类型 不是 ,无论它如何调用。返回类型为 。malloc
struct n *
malloc
void *
初始化 type 值的对象会将其隐式转换为 。这种隐式转换是允许的,因为初始化规则遵循 C 2018 6.5.16.1 1 中的赋值规则,其中声明允许的赋值之一是:struct n **
void *
struct n **
...左操作数具有原子指针类型、限定指针或非限定指针类型,并且(考虑到左操作数在左值转换后将具有的类型)一个操作数是指向对象类型的指针,另一个操作数是指向 的限定或非限定版本的指针,并且左指向的类型具有右指向的类型的所有限定符;
void
- 并指向返回的指针
p
malloc
否,该值初始化为返回的值。然后指向分配的内存。p
malloc
p
malloc
此代码错误地为 (using ) 分配了足够的空间,但将该空间的地址分配给 即 。要指向 ,请使用 或,最好是 。struct n
malloc(sizeof(struct n))
struct n **
p
struct n
struct n *p = malloc(sizeof (struct n));
struct n *p = malloc(sizeof *p);
要指向指向 a 的指针,首先创建一些指向 的指针,如上所述。那么指向该指针的指针将是 。struct n
struct n
struct n *p = malloc(sizeof *p);
struct n **pp = &p;
如果要为这些指针到指针分配空间,可以使用 ,然后可以将指针填充到 with 。但是,您不应在没有充分理由的情况下添加此额外的分配层。struct n **pp = malloc(sizeof *pp);
struct n
*pp = malloc(sizeof **pp);
请注意,该表单通常更受欢迎,因为前者会自动使用指向的类型。后者容易出错,例如有人错误地输入了 的类型并且设置不正确,或者有人后来更改了 的声明,但省略了对调用的相应更改。MyPointer = malloc(sizeof *MyPointer);
MyPointer = malloc(sizeof (SomeType));
MyPointer
MyPointer
SomeType
MyPointer
SomeType
malloc
评论
malloc(sizeof(*MyPointer))
MyPointer
sizeof
这实际上不起作用。在此示例中,malloc 返回一个 void *,它指向堆中新分配的位置,该位置足够大,可以容纳结构体 n。
请注意,malloc() 返回类型 void *,它基本上是指向任何潜在类型的指针,malloc() 不返回类型 struct n *(指向您声明的结构类型的指针)。void * 具有能够强制转换为任何其他类型的指针并再次转换的特殊属性。
总而言之,这意味着您的代码实际上不起作用,因为结构 n** 的第一个取消引用将是结构 n,而不是结构 n*。如果尝试取消引用两次,则很可能会得到无效的内存引用并崩溃。
您的代码之所以能够编译和运行而不会崩溃,是因为:
- 编译器自动将 void * 强制转换为结构 n **
- 您永远不会尝试实际取消引用指针,这意味着您永远不会尝试无效的内存引用。
评论
void *
具有能够强制转换为任何其他对象类型的指针的特殊属性:“ 到/从函数指针有问题。void *
void *
void *
简化问题和理解可能会到来:
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;
}
由于返回 void ptr,因此您可以自由地将指针存储到任何指针数据类型中。如果你把它放到错误的数据类型中......malloc()
评论
malloc()
void (*f)() = malloc(1);
returns
malloc
评论