【问题标题】:Understanding pointers in a structure and malloc了解结构和 malloc 中的指针
【发布时间】:2013-05-14 05:27:21
【问题描述】:

我只是在学习 C(在 24 小时内阅读 Sam 的自学 C)。我已经了解了指针和内存分配,但现在我想知道它们在结构中。

我写了下面的小程序来玩,但我不确定它是否可以。使用 gcc 在 Linux 系统上编译,带有 -Wall 标志编译没有任何问题,但我不确定它是否 100% 值得信赖。

可以像我在下面所做的那样更改指针的分配大小,还是我可能踩到相邻的内存?我在结构中做了一些前后变量来尝试检查这一点,但不知道这是否有效以及结构元素是否连续存储在内存中(我猜是这样,因为指向结构的指针可以传递给一个函数和通过指针位置操作的结构)。另外,如何访问指针位置的内容并对其进行迭代,以便确保如果它是连续的,则不会覆盖任何内容?我想我要问的一件事是如何以这种方式调试内存混乱以知道它不会破坏任何东西?

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

struct hello {
    char *before;
    char *message;
    char *after;
};

int main (){
    struct hello there= {
        "Before",
        "Hello",
        "After",
    };
    printf("%ld\n", strlen(there.message));
    printf("%s\n", there.message);
    printf("%d\n", sizeof(there));
    there.message = malloc(20 * sizeof(char));
    there.message = "Hello, there!";
    printf("%ld\n", strlen(there.message));
    printf("%s\n", there.message);
    printf("%s %s\n", there.before, there.after);
    printf("%d\n", sizeof(there));
    return 0;
}

我在想有些不对劲,因为我的there 的大小没有改变.kj

亲切的问候,

【问题讨论】:

  • “在 24 小时内自学 C”... 哦,天哪。 C tag wiki 中有一个书籍清单。帮自己一个忙,远离任何宣传在 X 天/小时/分钟内教你 C 的广告。
  • 如果我只能在 24 小时内学会发射火箭!
  • @narnie 请尽情享受学习C的那一刻,无需着急。即使明天晚上世界末日来临,这真的是一段值得珍惜的回忆。
  • @BarathBushan 这是我开始的第二本 C 书。第一个是从新手到专业的 C,但因指针而陷入困境。 Sam 的书帮助澄清了这一点,然后我将回到 Apress 的书。感谢 C 标记 wiki 链接!
  • 我正在决定:)

标签: c pointers struct malloc


【解决方案1】:

不太好,您有内存泄漏,您可以使用valgrind 在运行时检测它(在 Linux 上)。

你正在编码:

there.message = malloc(20 * sizeof(char));
there.message = "Hello, there!";

第一次赋值调用malloc(3)。首先,当调用malloc 时,您应该始终测试它是否失败。但实际上它通常会成功。所以至少更好的代码:

there.message = malloc(20 * sizeof(char));
if (!there.message) 
  { perror("malloc of 20 failed"); exit (EXIT_FAILURE); }

第二个赋值将常量文字字符串"Hello, there!"的地址放入同一个指针there.message中,而你丢失了第一个值。你可能想复制那个常量字符串

strncpy (there.message, "Hello, there!", 20*sizeof(char));

(你可以只使用strcpy(3),但要注意缓冲区溢出)

您可以使用strdup(3) 获得一些字符串的新副本(在堆中)(GNU libc 也有asprintf(3) ...)

there.message = strdup("Hello, There");
if (!there.message) 
  { perror("strdup failed"); exit (EXIT_FAILURE); };

最后,在程序结束堆内存时free 是很好的品味。 (但操作系统会在_exit(2)时间抑制进程空间。

阅读更多关于C 编程,memory management,garbage collection。或许可以考虑使用Boehm's conservative GC

C 指针只是一个内存地址区。应用程序需要知道它们的大小。

PS。 C 中的手动内存管理很棘手,即使对于经验丰富的资深程序员也是如此。

【讨论】:

  • 哦,哇,您还回答了我的另一个问题。我一直在寻找函数的文档。不知道它在man 3页上。整个库是否在某个地方记录了每个函数?比如,数学库中都有哪些可用的函数?
  • man 页面在 Linux 和 Unix 系统上是旧式的。只需在 Linux 终端上输入 man man 即可查找。
  • 我喜欢手册页。实际上,我已经使用它们用于我以前编写的程序的语法编写了自己的手册页。有关如何查找所有库的文档的任何建议?我希望在 gcc 文档中找到它,但没有库描述。
  • 某些部分的intro man 页面可能会有所帮助。大多数免费软件库都有其文档。对于 GNU libc,开始 here
  • 好的,GNU libc 链接是完美的。正是我想要的。非常感谢!
【解决方案2】:

there.message = "Hello, there!" 不会将字符串复制到缓冲区中。它将指针设置为一个新的(通常是静态的)缓冲区,其中包含字符串“Hello, there!”。因此,编写的代码存在内存泄漏(分配的内存在程序退出之前永远不会被释放)。

但是,是的,malloc 本身就很好。您通常会使用 strncpy、sprintf 或类似函数将内容复制到分配的缓冲区中。

【讨论】:

    【解决方案3】:

    可以更改指针的分配大小 [...] 吗?

    嗯? “更改指针的分配大小”是什么意思?目前,您的代码所做的所有事情都是通过为指针分配不同的地址来泄漏您malloc()ated 的 20 个字节。

    【讨论】:

    • 我可能没有正确的术语,但我的意思是我初始化 there 时的 *message 指针是 5+1 字符长(“Hello”加上 \0) .如果我需要像以前那样将其更改为更长的字符串(将其更改为“Hello, there”),我该怎么做?
    • @narnie there.message = "Hello there"; 因为您正在使用字符串文字。
    • 啊,所以如果添加到字符串的较短指针的长度,我不必扩展内存?它不会踩到其他内存吗?有句柄的编译器吗?
    • @narnie 看,字符串文字是具有静态存储持续时间的常量字符串,它们存在于程序的整个生命周期中,并且您只是分配指针本身. 你不这样做memcpy()。如果您调用了memcpy() 或strcpy(),那么您将不得不为其分配内存,但这样您就不需要了。
    • 好的,它开始有点凝固了。我以前不了解字符串文字。显得比较浪费。我想没有办法释放那个备份?
    猜你喜欢
    • 2016-07-05
    • 2013-05-09
    • 2013-01-23
    • 1970-01-01
    • 1970-01-01
    • 2012-06-04
    • 1970-01-01
    • 2021-11-22
    • 2016-07-30
    相关资源
    最近更新 更多