【问题标题】:Assigning values to C pointers using malloc without variable initialization使用 malloc 为 C 指针赋值,无需变量初始化
【发布时间】:2021-03-19 12:05:32
【问题描述】:

来自this question,我明白为什么下面的代码可能不起作用:

int *ptr;
*ptr = 1000;
printf("%d", *ptr);

当我使用:gcc file.c; ./a.out 编译和运行它时,我得到了:

分段错误(核心转储)./a.out

这里的ptr 可能指向一个没有初始化变量的随机位置。对吗?

但是,当使用malloc() 时不会出现该问题。

int *ptr = malloc(sizeof(int));
*ptr = 1000;
printf("%d", *ptr);

malloc 是否初始化其指针指向的变量?

【问题讨论】:

  • malloc() 不会初始化变量,但它会在内存中保留一些空间(您需要的大小),通常您需要根据变量的类型来确定变量大小所需的空间。
  • 是错字吗? int *ptr = 1000; 应该是*ptr = 1000; 和第一个代码一样吗?
  • “没有变量初始化”是什么意思?在变量定义期间赋值就是初始化。从哪里获得该值并不重要。
  • 我想知道为什么int *ptr; *ptr = 1000 在打印时返回分段错误。当我使用 malloc 时,这并没有发生,我能够打印 ptr 指向的值。

标签: c pointers malloc


【解决方案1】:

简短回答:否

malloc 不初始化变量。它只是分配内存。您可以将整数放入函数中,例如malloc(8),它只会分配8个字节供以后使用。如果您进一步查看 malloc 函数,它实际上返回 void* 数据类型。以后可以将其类型转换为其他数据类型。

根据您的代码malloc(sizeof(int)),实际上sizeof(int) 返回一个整数,表示您放入其中的数据类型/变量的大小。

【讨论】:

  • 如果我使用int *ptr = malloc(4);,我不会从第二个代码块中得到分段默认错误。但是,当我尝试打印时,第一个使用 int *ptr; 的代码块会返回分段错误
  • @Shahin 在您的第一个代码块上,您没有分配所需的内存。这就是为什么你不能给它赋值。
  • 我想我现在明白了。当我使用int *ptr; 时。使用malloc() 分配内存以进行动态分配,或者为静态分配的指针初始化一个int 变量(int num; int *ptr = &num)。数组也分配内存:int ptr[sizeof(int)]
【解决方案2】:

您链接的帖子或多或少地解释了它。没有涉及的一件事是未定义的行为 - 这正是没有 malloc 的版本中会发生的情况。

如果你尝试使用这样的指针,各种事情都会出错——你还没有说应该指向的位置。它可以指向任何地方。

这一行:

int *ptr = malloc(sizeof(int));

确实是一个初始化。这里发生了两件事:(1)malloc 在内存中保留空间,以便您随后可以使用指针;(2)它返回该内存的起始地址。

地址被分配给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)。然而,它不是必须的,也不能保证你的程序会做什么。 所有变量,包括指针,都需要初始化。

顺便说一句,如果您查看this 的帖子,它会告诉您为什么您需要在这里调用malloc——这是因为您正在动态分配内存,所以它将是在堆中而不是在堆栈中。

【讨论】:

  • 非常有帮助!谢谢!
【解决方案3】:

案例一
代码:

int *ptr;
*ptr = 1000;

*ptr 表示您正在取消引用 ptr 指针。取消引用未初始化的指针是undefined behaviour。未定义的行为包括它可能执行不正确(崩溃或静默生成不正确的结果),或者它可能恰好按照程序员的意图执行。

案例二
代码:

int *ptr = malloc(sizeof(int));
*ptr = 1000;

malloc 分配内存块(大小以字节为单位)并在成功时返回指向新分配内存开头的指针。新分配的内存块没有初始化。

当这样做时:

int *ptr = malloc(sizeof(int));

假设malloc 调用成功,它返回指向新分配内存开头的指针。这个返回的指针将被分配给ptr 指针。所以,现在ptr 指针已初始化,尽管它指向的内存未初始化
由于ptr 指针指向一个有效 内存位置,您可以取消引用并访问它。

在此声明中

*ptr = 1000;

取消引用ptr 并将1000 分配给该内存位置。现在,ptr 指针指向的内存位置包含值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
  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-19
    • 2017-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多