【问题标题】:How do you know how much space to allocate with malloc()?你怎么知道用 malloc() 分配多少空间?
【发布时间】:2009-08-08 04:22:50
【问题描述】:

我是一个 C 新手,我来自 C#。我一直在学习内存管理和malloc() 函数。我也遇到过这段代码:

char *a_persons_name = malloc(sizeof(char) + 2);

我不明白这是为a_persons_name 分配了多少空间。它是分配2个字符(例如AB)还是其他?

我还知道,您有时可以通过malloc 获得“幸运”并使用未分配的空间(这可能导致数据损坏和段错误)。那么我如何知道我分配了多少空间以及需要多少空间?

【问题讨论】:

    标签: c memory-management malloc char sizeof


    【解决方案1】:

    sn-p 为 2 个字符的名称分配了足够的空间。

    通常,字符串缓冲区将从某个地方填充,即 I/O。如果事先不知道字符串的大小(例如从文件或键盘读取),通常使用以下三种方法之一:

    • 为任何给定字符串定义最大大小,分配该大小 + 1(用于空终止符),最多读取那么多字符,如果提供的字符过多,则错误或盲目截断。不是非常用户友好。

    • 分阶段重新分配(最好使用几何级数,例如加倍,以避免二次行为),并继续阅读直到到达终点。编码不是很容易。

    • 分配一个固定大小并希望它不会被超过,并且当这个假设失败时会可怕地崩溃(或被拥有)。易于编码,易于破解。例如,请参阅标准 C 库中的 gets。 (切勿使用此功能。

    【讨论】:

    • 为什么所有分配足够空间的方法都很糟糕?有没有简单的方法!
    • 字符串是 C 语言中最破碎的部分。我建议编写一个伪 OO 'StringBuilder' 结构或类似结构,并创建例如StrBufPrintf、StrBufGets、StrBufScanf 等来集中这些操作。标准 C 库没有多大帮助。 C++ 稍微好一些,因为您通常有 10 种不同的字符串类可供选择,每个使用的不同框架都有一个。是的,我在讽刺。
    • 简单的方法是(1)使用字符串是基本类型的语言; (2) 使用提供字符串行为的库;或 (3) 学习您正在使用的语言。如果你不想学习如何使用这些工具,你为什么还要尝试。找另一种更适合你的语言(我不是想在这里侮辱,只是务实)。
    • 当然,只要您自己构建适当的抽象,字符串在 C 中是很容易的。但作为一个语言设计者和实现者,我相信 C 几乎单枪匹马地为数百万甚至数十亿美元的损失负责,因为它对字符串的处理特别弱。
    【解决方案2】:

    嗯,首先,sizeof(char) 始终为 1,因此您可以只使用 malloc(3)

    您在其中分配的空间足以容纳三个字符。但请记住,您需要一个用于 C 字符串的空终止符。

    你往往会找到类似的东西:

    #define NAME_SZ 30
    : : :
    char *name = malloc (NAME_SZ+1);
    

    为名称和终止字符获得足够的存储空间(请记住,字符串“xyzzy”在内存中存储为:

    +---+---+---+---+---+----+
    | x | y | z | z | y | \0 |
    +---+---+---+---+---+----+
    

    有时使用非基于字符的数组,您会看到:

    int *intArray = malloc (sizeof (int) * 22);
    

    这将为 22 个整数分配足够的空间。

    【讨论】:

    • (类型和方便)int *intArray = malloc(sizeof(*intArray) * 22);
    • "好吧,首先,sizeof(char) 总是 1" FALSE。 C 指定 1 个字节作为 char 大小的 LOWER BOUNDS。实际大小取决于架构和编译器。在一些更晦涩的架构中,char 是 16 位。
    • 不,实际上,sizeof(char) 总是 1.来自 c1x,“6.5.3.4 sizeof 运算符”,第 3 段:当应用于具有类型的操作数时char、unsigned char 或 signed char(或其限定版本)结果为 1。
    • 更多细节请参见stackoverflow.com/questions/1535131/…:C 标准定义字节为可寻址单元,但它不一定是 8 位字节(八位字节)。
    【解决方案3】:

    malloc() 将分配一块内存,如果成功则返回指向该内存的指针,如果不成功则返回 NULL。内存块的大小由malloc 的参数指定,以字节为单位。

    sizeof 运算符以字节为单位给出其参数的大小。

    char *someString = malloc(sizeof(char) * 50)
    

    这将为不包括 NULL 字符的 49 个字符的字符串(C 样式的字符串必须以 NULL ('\0') 字符终止)分配足够的空间,并将 someString 指向该内存。

    看起来您问题中的代码应该是malloc(sizeof(char) * 2);,因为sizeof(char) + 2 没有意义。

    请注意,sizeof(char) 保证始终等于 1(字节)——但其他类型(如 long)的内存表示可能因编译器而异。

    如果您尝试在已分配的内存之外进行读/写,那么您对动态分配的内存感到(不)幸运。

    例如,

    char *someString = malloc(10);
    strcpy(someString, "Hello there, world!");
    printf("%s\n", someString);
    

    第一行为 9 个字符和一个 NULL 字符分配了足够的空间。
    第二行尝试将 20 个字符(19 + NULL)复制到该内存空间中。这会超出缓冲区,并可能导致一些非常机智的事情,例如覆盖相邻的内存或导致段错误。

    第三行可能会起作用,例如,如果在 someString 旁边分配了内存,并且“Hello there, world!”跑进那个内存空间,它可能会打印你的字符串加上下一个内存空间中的任何内容。如果第二个空格被 NULL 终止,它就会停止——除非它不是,在这种情况下它会跑掉并最终出现段错误。

    这个例子是一个非常简单的操作,但是很容易出错。 C 很棘手——要小心。

    【讨论】:

      【解决方案4】:

      您对malloc 的调用将分配3 个字节的内存。 sizeof(char) 是 1 个字节,明确指出 2 个字节。这为您提供了足够的空间来容纳大小为 2 的字符串(以及终止字符)

      【讨论】:

        【解决方案5】:

        这将分配三个字节; 1 表示 sizeof(char),再加上 2。只是断章取义地看到那条线,我无法知道为什么它会以这种方式分配,或者它是否正确(对我来说看起来很可疑)。

        您需要分配足够的内存来容纳您需要放入其中的任何内容。例如,如果您要分配内存来保存字符串,则需要分配足够的内存来保存预期的最长字符串以及一个用于终止 null 的字节。如果您正在处理 ASCII 字符串,这很容易:每个字符一个字节加一个。如果您使用的是 unicode 字符串,事情会变得更加复杂。

        【讨论】:

          【解决方案6】:

          第一点 - 永远不要将绝对数字放在 malloc 的参数中,始终使用 sizeof 和倍数是一个好习惯。如上所述,为某些类型分配的内存因编译器和平台而异。为了保证为 'blob' 类型的数组提供足够的空间,最好使用如下内容:

          blob *p_data = malloc(sizeof(blob) * length_of_array);
          

          这样,无论类型是什么,无论它在内存中看起来如何,您都会得到完全正确的数量。

          其次,段错误等。 C 作为一种低级语言,没有边界检查。这意味着没有什么可以检查您正在查看的索引实际上不在数组中。实际上,即使它不属于您的程序,它也不会阻止您在任何地方访问内存(尽管您的操作系统可能,这就是段错误)。这就是为什么每当你在 C 中传递一个数组时,你也需要传递它的长度,以便接收数组的函数知道它有多大。不要忘记“数组”实际上只是指向第一个元素的指针。 这在传递字符串时非常无用 - 每个字符串参数都会变成两个参数,因此使用了作弊。任何标准 C 字符串都以 NULL 结尾。字符串中的最后一个字符应该是 ASCII 值 0。任何字符串函数都沿着数组工作,直到它们看到然后停止。这样他们就不会超出阵列,但如果由于某种原因它不存在,他们会。 被理解了

          strlen("Hello")
          

          是 5,但要存储它,您还需要一个字符。例如:

          const char str1 = "Hello";
          char *str2 = malloc(sizeof(char) * (strlen(str1) + 1));
          strcpy(str2, str1);
          

          是的,sizeof(char) 是不必要的,因为它被定义为 1,但我发现它更清晰,这绝对是一个好习惯。

          【讨论】:

          • 1) 不同意“最好使用这样的东西:”p_data = malloc(sizeof(blob) * length_of_array);p_data = malloc(sizeof *p_data * length_of_array);,因为它不依赖于正确编码类型并在代码更改时保持正确。 2) 用法示例:str2 = malloc(sizeof *str2 * (strlen(str1) + 1));
          猜你喜欢
          • 1970-01-01
          • 2012-09-02
          • 1970-01-01
          • 2022-12-09
          • 2019-07-27
          • 2021-11-26
          • 1970-01-01
          • 2011-08-23
          • 1970-01-01
          相关资源
          最近更新 更多