[英]Assigning values to C pointers using malloc without variable initialization
从这个问题,我明白为什么下面的代码可能不起作用:
int *ptr;
*ptr = 1000;
printf("%d", *ptr);
当我编译并运行它时使用: gcc file.c; ./a.out
gcc file.c; ./a.out
我得到:
分段错误(核心转储)./a.out
这里的 ptr 可能指向一个没有初始化变量的随机位置。 那是对的吗?
但是,使用malloc()
时不会出现该问题。
int *ptr = malloc(sizeof(int));
*ptr = 1000;
printf("%d", *ptr);
malloc 是否初始化其指针指向的变量?
简短的回答:没有
malloc 不初始化变量。 它只是分配 memory。 您可以将 integer 放入 function 中,例如malloc(8)
,它只会分配 8 个字节供以后使用。 如果您进一步查看 malloc function,它实际上返回void*
数据类型。 它可以稍后被类型转换为其他数据类型。
从您的代码malloc(sizeof(int))
,实际上sizeof(int)
返回一个 integer 用于您放入其中的数据类型/变量的大小。
案例一:
代码:
int *ptr;
*ptr = 1000;
*ptr
表示您正在取消引用ptr
指针。 取消引用未初始化的指针是未定义的行为。 未定义的行为包括它可能执行不正确(崩溃或默默地生成不正确的结果),或者它可能偶然地完全按照程序员的意图执行。
案例二:
代码:
int *ptr = malloc(sizeof(int));
*ptr = 1000;
malloc
分配 memory 块(大小以字节为单位)并在成功时返回指向新分配的 memory 开头的指针。 memory 新分配的块未初始化。
这样做时:
int *ptr = malloc(sizeof(int));
假设malloc
调用成功,它返回指向新分配的 memory 开头的指针。 这个返回的指针将被分配给ptr
指针。 因此,现在ptr
指针已初始化,尽管它指向的 memory 是uninitialised 。
由于ptr
指针指向一个有效的 memory 位置,因此您可以取消引用并访问它。
在这份声明中
*ptr = 1000;
取消引用ptr
并将1000
分配给该 memory 位置。 现在, ptr
指针指向的 memory 位置包含值1000
。 访问这个值非常好。
额外的:
遵循良好的编程习惯 - 始终检查malloc
返回。 你应该做:
int *ptr = malloc (sizeof (int));
if (NULL == ptr) {
exit(EXIT_FAILURE); // or whatever you want to do at malloc failure do it here
}
您链接的帖子或多或少地解释了它。 一件事是未定义的行为 - 这正是没有malloc
的版本中会发生的情况。
如果您尝试使用这样的指针,各种各样的事情都会出错 - 您还没有说它应该指向哪里。 它可以从字面上指向任何地方。
这一行:
int *ptr = malloc(sizeof(int));
确实是初始化。 这里发生的是两件事:(1) malloc
在 memory 中保留空间,以便您随后可以使用指针和(2)它返回该 ZCD69B4957F06CD818D7BF3D61980E29 的起始地址
地址被分配给ptr
- 它本身就是一个变量。 而且,像所有变量一样,您不能在未初始化的情况下使用它们。 如果这样做,那是无效的代码,因此会导致未定义的行为。
让我们再深入一点:
如果您不调用malloc
,则您的指针无效,不应使用。 为了证明这一点,请尝试编译您的代码,例如使用旧的gcc
。
如果你运行:
gcc program.c # no flags
它会编译——但仅仅因为gcc
给了你一个二进制文件,这并不意味着它会做你想做的事。 当你运行它时,它(大多数时候)会惨遭失败。
但是,如果您运行:
gcc -Wall program.c # enable warnings
它会警告您ptr
未初始化未使用。 但是,它仍然会生成一个您可以运行的二进制文件 - 产生与以前相同的结果。
最后,如果你运行:
gcc -Wall -Werror program.c # enable warnings and turn them into errors
它会再次警告你同样的事情,但这一次,它不会产生二进制文件——这就是你在这种情况下真正想要的。 在这里, gcc
告诉你,有些事情确实非常错误,你的代码根本无效。
现在,回到关于未定义行为的话题。 一旦你编译了你的无效代码(使用前两种方法中的任何一种——顺便说一句,请永远不要这样做),运行它通常会给你一个“分段错误”(seg fault)。 然而,它不是必须的,也不能保证你的程序会做什么。 所有变量,包括指针,都需要初始化。
顺便说一句,如果您查看这篇文章,它会告诉您为什么需要在这里调用malloc
——因为您正在动态分配 memory,因此它将位于堆中而不是堆栈中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.