【问题标题】:Trying To Learn Dynamic Memory Allocation in C尝试学习 C 中的动态内存分配
【发布时间】:2014-01-02 16:33:28
【问题描述】:

我正在尝试学习动态内存分配和结构,但我有一些问题。

首先

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

int main()
{
    int *number;
    number = malloc(1*sizeof(int));
    int a;
    for(a=0;a<150;a++)
    {
        number[a]=a;
        printf("%d ",number[a]);
    }
    return 0;
 }

在这个示例中,我计划它给我错误。因为我将它分配给 1 个整数的大小,所以我写的整数太多了。它不应该给我一个错误吗?可以详细解释一下吗?

struct people 
{
    char *name;
    int age;
    char *personalInfo;
} human[3];

当我定义这样的结构时,如何分配它以保持 3 个人以上?如何将其更改为人类 [20] 或更多?如果答案是写 *human 而不是 human[3],我应该如何分配它?喜欢malloc(number*sizeof(char)*sizeof(int)*sizeof(char))

还有一件事,在第二个示例中,我需要分配 name 和 personalInfo 指针吗?

【问题讨论】:

  • 您在第一个示例中调用了 未定义的行为,因此假设 anything 正式不在讨论范围内。
  • 注意:DMA 更常用作 Direct Memory Access 的缩写,因此用它来表示动态内存分配很可能会引起混淆。
  • malloc(number*sizeof(char)*sizeof(int)*sizeof(char)) -- 不。 想想看。这没有意义。如果您将intchar 并排放置,总尺寸会是它们尺寸的乘积吗?当然不会——这将是它们大小的总和,所以malloc(number* (sizeof(char)+sizeof(int)+sizeof(char))) 会更有意义。 但是,这仍然是错误和危险的,因为结构可以包含内部填充,所以你最好写sizeof(the_struct_name)
  • @hyde 感谢您提及这一点。我很困惑。

标签: c malloc dynamic-allocation


【解决方案1】:

在这个示例中,我计划它给我错误。

您不能“计划给出错误”。您说代码是错误的是正确的,因为您正在编写超出数组末尾的内容,但是 C 没有边界检查 - 访问数组只是 未定义的行为, 这意味着它可以做任何事——它可以假装工作正常,也可以崩溃,or it can cause demons to fly out of your nose

如何将其更改为人类[20] 或更多?

嗯……就是这样:

struct people {
   // members here
} human[20];

我不明白为什么数字“3”如此特别。如果您想动态分配内存,您可以像处理其他所有数据类型一样进行操作:使用sizeof 运算符:

struct people *human = malloc(sizeof(human[0]) * number_of_people);

struct people *human = malloc(sizeof(struct people) * number_of_people);

【讨论】:

  • 请注意(安慰任何 4 岁的读者)虽然恶魔鼻学的例子很常见,但计算机实际上并没有能力对你鼻窦中的超自然生物产生任何影响。
  • @WilliamPursell:计算机可能是制药厂内的嵌入式设备......所以它可能对鼻窦造成真正的损害(通过一些不受控制的危险物质释放)。
  • @BasileStarynkevitch 我从来没有遇到过如此巧妙地捍卫“UB 可以做任何事”的论点! :P
  • @H2CO3:实际上,它有点复杂;在几个工业标准(DOI178C、ASIL D 的 ISO26262 ......)中,对于某种关键的嵌入式软件 malloc 只是禁止(但一些未定义的行为可能发生) .
  • @H2CO3:我绝对同意。但是,当我知道已经应用了最新的静态分析技术(请参阅ASTREE...)时,我会觉得爬上空中客车更安全。但它不是灵丹妙药。请参阅J.Pitrat's blog 了解另一种(和未来的)方法。
【解决方案2】:

C 不提供数组的编译时或运行时边界检查。程序必须执行自己的边界检查。如果你写超出数组的末尾,你的程序将有未定义的行为。实际上,这意味着您通过写入未初始化的区域或分配器用于簿记的区域来破坏进程的内存。这可能导致程序立即崩溃、退出时崩溃,或者覆盖堆中其他(可能不相关)变量的值。

要分配可变数量的people 结构,您可以这样做:

struct people *humans;
humans = malloc(N * sizeof(struct people));
// humans now points to an array of N `people`

对于您的最后一个问题,是的,您必须为这些字符串分配空间,除非您只是使用这些指针指向在其他地方定义/分配的字符串。请注意,这意味着即使在上面分配 N 个对象的代码中,我仍然没有为字符串分配任何空间,并且在我这样做之前无法写入它们。

【讨论】:

  • +1,但 struct people 在 OP 的示例中没有类型定义,并且不要强制转换 malloc(问题标记为 C)
  • @AlterMann 好的,已修复。 (对于其他人)请参阅stackoverflow.com/questions/605845/… 以讨论此...
  • 现在看起来是 C 类型的答案。
【解决方案3】:
struct people 
{
  char *name;
  int age;
  char *personalInfo;
};

struct people *human;

human = malloc(sizeof(*human) * 20);

【讨论】:

    【解决方案4】:

    在这个示例中,我计划它给我错误。因为我将它分配给 1 个整数的大小,所以我写了太多整数。它不应该给我一个错误吗?可以详细解释一下吗?

    不,不应该。这是未定义的行为,可能会导致运行时崩溃,但编译器既不会警告您,也不会产生任何错误。您可以通过在内存分析器(例如 valgrind)中运行程序来检测此类错误。

    当我定义这样的结构时,我如何分配它来保持超过 3 个人?我怎样才能将其更改为人类 [20] 或更多?

    像这样:

    struct people *human = malloc(20 * sizeof(struct people));
    

    喜欢malloc( number*sizeof(char)*sizeof(int)*sizeof(char) )

    除了太不方便之外,将各个字段的大小相加可能不会产生正确的大小,因为允许编译器填充您的 struct 以优化对其字段的访问。这就是为什么你需要使用sizeof(struct people)

    【讨论】:

    • “将单个字段的大小相加可能不会产生正确的大小”——将它们相乘会更少(我想知道 OP 是从哪里得到这个想法的——它只是没有意义.)
    【解决方案5】:

    第一个示例调用未定义的行为。

    §6.5.6/8: If both the pointer operand and the result point to elements of the same array
     object, or one past the last element of the array object, the evaluation shall not 
    produce an overflow; otherwise, the behavior is undefined
    

    如果你想分配给 20 个人,你可以这样做......

    typedef struct people 
    {
        char *name;
        int age;
        char *personalInfo;
    }People;
    

    人 *人类;

    human = malloc(sizeof(*human) * 20);
    

    【讨论】:

      猜你喜欢
      • 2019-04-28
      • 1970-01-01
      • 1970-01-01
      • 2018-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-07
      相关资源
      最近更新 更多