gpt4 book ai didi

c - 指向 C 中指针的指针

转载 作者:太空宇宙 更新时间:2023-11-04 05:03:06 24 4
gpt4 key购买 nike

我试图理解指向指针的指针是如何工作的,我想出了这个例子,它编译得很好。但是,当它被执行时,我得到了一个段错误。PS:我不希望 f1() 返回 char *

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

int f1(char **str_);

int main(int argc, char **argv)
{
char *str = NULL;

f1(&str);
printf("str : %s\n", *str);

str = realloc(str, (size_t) 0);
assert(str == NULL);

return 0;
}

int f1(char **str_)
{
if ((*str_ = realloc(*str_, sizeof(char) * 12)) == NULL)
{
fprintf(stderr,"realloc() failed\n");
exit(3);
}

(*str_) = "hello there";

return 0;
}
  • 代码有什么问题?

最佳答案

您要么需要在编译器中打开更多警告,要么获得更好的编译器。当我编译你的代码时,我收到警告:

mem.c: In function ‘main’:
mem.c:12: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’
mem.c:12: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’
mem.c: At top level:
mem.c:7: warning: unused parameter ‘argc’
mem.c:7: warning: unused parameter ‘argv’

我不太清楚为什么第 12 行的警告会重复出现,但 MacOS X 10.7 上的 GCC 4.2 和 4.6.1 都给出了两次。关于 argc 的警告和 argv是使用 int main(void) 的充分理由当您不使用命令行参数时;它们不是大问题。

关于 %s 的警告(实际上是一个错误)和 int对比char *足以解释您的崩溃 - 但是,这不是代码的唯一问题。其实还有:

  1. 早期内存泄漏,
  2. 实际泄漏,
  3. 您(不小心)依赖未定义行为的地方,以及
  4. 您依赖于可能与您的期望不符的实现定义行为的地方。

您的代码注释:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

int f1(char **str_);

int main(int argc, char **argv)
{
char *str = NULL;

f1(&str);
printf("str : %s\n", *str);

str = realloc(str, (size_t) 0); /* (3) Undefined behaviour */
assert(str == NULL); /* (4) Implementation-defined behaviour */

return 0;
}

int f1(char **str_)
{
if ((*str_ = realloc(*str_, sizeof(char) * 12)) == NULL) /* (1) Incipient leak */
{
fprintf(stderr,"realloc() failed\n");
exit(3);
}

(*str_) = "hello there"; /* (2) Actual leak */

return 0;
}

按编号顺序讨论这些:

  1. 如果内存重新分配失败,则会出现初期泄漏。 *str是唯一存储指向已分配内存的指针的先前值的地方,如果 realloc()失败,它返回 0(空指针)但不释放旧内存,但您不再拥有指向旧内存的指针。

    修复:

    char *new_mem = realloc(*str, 12);
    if (new_mem == 0)
    ...error handling...
    *str = new_mem;

    经验法则:不要分配 realloc() 的返回值到作为其第一个参数的变量。

  2. 实际泄漏的发生是因为您将指针分配给一个字符串常量,而不是指向新分配的内存的指针。最简单的修复是使用 strcpy() , 尽管您需要添加 #include <string.h>当你这样做时。通常,您还会确保为要复制的字符串分配足够的空间,从而导致:

    char const hello[] = "hello there";
    char *new_mem = realloc(str, sizeof(hello));
    //char *new_mem = realloc(str, strlen(hello)+1);
    if (new_mem == 0)
    ...handle error...
    *str = new_mem;
    strcpy(new_mem, hello);

    在这个例子中,我可以使用 sizeof(hello)因为字符串的大小包括空终止符,并且因为实际的数组定义在范围内。如果要复制的字符串作为指针传递给函数,则使用 strlen(hello)+1 的替代方法是正确的(并且使用 sizeof() 是不正确的),即使它需要运行时计算长度而不是编译时计算,如图所示。

  3. 由于 (2) 处的内存泄漏,出现未定义的行为。你试试realloc()一个字符串常量,不是 realloc() 返回的指针.这会导致未定义的行为;它可能会崩溃(因为 realloc() 试图将控制信息写入只读内存)或者它可能只是弄乱了内存系统,导致一段时间后崩溃。

    此问题的修复是对第 (2) 项的更正。

  4. 出现实现定义的行为是因为 C 标准说:

    §7.20.3 Memory management functions ¶1: [...] If the size of the space requested is zero, the behavior is implementation defined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object.

    您断言您的实现将选择第一个选项,但它可能会选择第二个。解决方法是删除无根据的断言。

所以,代码中总共有 5 个问题,编译器可能会帮助您解决其中的一个问题。

关于c - 指向 C 中指针的指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8074093/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com