【问题标题】:Are "malloc(sizeof(struct a *))" and "malloc(sizeof(struct a))" the same?“malloc(sizeof(struct a *))”和“malloc(sizeof(struct a))”是一样的吗?
【发布时间】:2012-01-06 18:01:29
【问题描述】:

这个问题是Malloc call crashing, but works elsewhere的延续

我尝试了以下程序,发现它可以正常工作(即没有崩溃 - 上面提到的链接中也提到了这一点)。我可能很幸运能够让它工作,但我正在寻找 SO 专家的合理解释,说明为什么它有效?!

这里是使用malloc() w.r.t structurespointers分配memory的一些基本理解

  • malloc(sizeof(struct a) * n) 分配 n 类型的数量 struct a 元素。并且,可以使用pointer-to-type-"struct a" 存储和访问此内存位置。基本上是struct a *
  • malloc(sizeof(struct a *) * n) 分配 n 类型的数量 struct a * 元素。然后每个元素都可以指向struct a 类型的元素。基本上malloc(sizeof(struct a *) * n) 分配一个array(n-elements)-of-pointers-to-type-"struct a"。而且,分配的内存位置可以使用pointer-to-(pointer-to-"struct a") 进行存储和访问。基本上是struct a **

所以当我们创建array(n-elements)-of-pointers-to-type-"struct a"时,是不是

  1. 将其分配给struct a * 而不是struct a ** 是否有效?
  2. 使用pointer-to-"struct a"访问/取消引用分配的array(n-elements)-of-pointers-to-type-"struct a"有效吗?

data * array = NULL;

if ((array = (data *)malloc(sizeof(data *) * n)) == NULL) {
    printf("unable to allocate memory \n");
    return -1; 
}   

sn-p代码如下:

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

int main(void) 
{
    typedef struct { 
        int value1;
        int value2;
    }data;

    int n = 1000;
    int i;
    int val=0;

    data * array = NULL;

    if ((array = (data *)malloc(sizeof(data *) * n)) == NULL) {
        printf("unable to allocate memory \n");
        return -1; 
    }   
    printf("allocation successful\n");

    for (i=0 ; i<n ; i++) {
        array[i].value1 = val++;
        array[i].value2 = val++;
    }   

    for (i=0 ; i<n ; i++) {
        printf("%3d %3d %3d\n", i, array[i].value1, array[i].value2);
    } 

    free(array);
    printf("freeing successful\n");

    return 0;
}

编辑: 好的,如果我按照 错误

执行以下操作
data * array = NULL;
if ((array = (data *)malloc(sizeof(data *) * n)) == NULL) {

有没有办法捕获(在编译时使用任何GCC 标志)这些意外的编程错字有时可能会起作用并且可能随时爆发!我使用-Wall 编译了它,但没有发现任何警告!

【问题讨论】:

  • 您的问题标题似乎与您上面其余文本中的实际问题不符...
  • 另外,为什么要将malloc 的结果分配给错误的东西,然后取消引用呢?我不明白问题的前提。
  • @OliCharlesworth 我这样做是错误的,不是故意的!所以当我这样做时程序不会崩溃吗?!
  • 关于编辑:不要写array = malloc(sizeof(data) * n)。而是写array = malloc(sizeof(*array) * n);。它对编译器没有任何帮助,但它可以帮助您分配正确的类型,因为您不必命名类型,您只需要记住在您分配的指针名称之前放置 * .我认为 GCC 中没有任何东西可以强制执行此操作,但是如果您环顾四周,您可能会发现一个 lint 样式工具,该工具将围绕使用 malloc 执行样式规则。
  • @SangeethSaravanaraj 你的代码不正确它正在工作,因为 val 变量太小,如果它更大它会失败

标签: c pointers struct


【解决方案1】:

似乎存在根本性的误解。

malloc(sizeof(struct a) * n) 分配 n 个类型 struct a 元素。

不,这正是人们通常在这样的电话之后使用它的方式。 malloc(size) 分配size 字节的内存区域。您对该区域的处理完全取决于您。唯一重要的是不要超出分配内存的限制。假设有4个字节floatint和8个字节double,在malloc(100*sizeof(float));成功后,可以将400个字节中的前120个作为15个doubles的数组,后120个作为数组30 个floats,然后在其后面放置一个包含 20 个chars 的数组,如果您愿意,用 35 个ints 填充剩余的 140 个字节。这是完全无害的定义行为。

malloc 返回一个void*,可以隐式转换为任何类型的指针,所以

some_type **array = malloc(100 * sizeof(data *)); // intentionally unrelated types

很好,它可能不是您想要的内存量。在这种情况下,很可能是这样,因为无论指针指向什么,它们都倾向于具有相同的大小。

更有可能给你错误的内存量是

data *array = malloc(n * sizeof(data*));

如你所愿。如果您将分配的内存块用作data 类型的n 元素数组,则有三种可能性

  1. sizeof(data) &lt; sizeof(data*)。那么你唯一的问题就是浪费了一些空间。
  2. sizeof(data) == sizeof(data*)。一切都很好,没有浪费空间,就好像你根本没有错字一样。
  3. sizeof(data) &gt; sizeof(data*)。然后,您将访问在触摸以后的数组元素时不应该访问的内存,这是未定义的行为。根据不同的情况,它可以始终如一地工作,就好像你的代码是正确的一样,立即因段错误或介于两者之间的任何东西而崩溃(从技术上讲,它的行为方式可能无法有意义地置于这两者之间,但这是不寻常的)。

如果你故意这样做,知道第 1. 或 2. 点适用,这是不好的做法,但不是错误。如果您无意中这样做,则无论哪个点适用,它都是错误的,无害但很难找到,而 1. 或 2. 适用,有害但通常在 3. 的情况下更容易检测。

在你的例子中。 data 分别是 4 个。 8 个字节(可能),在 64 位系统上将它们放入 1。 2. 以高概率,在 32 位系统上分为 2 位。 3.

避免此类错误的推荐方法是

type *pointer = malloc(num_elems * sizeof(*pointer));

【讨论】:

    【解决方案2】:

    没有。

    sizeof(struct a*)指针的大小
    sizeof(struct a) 是整个结构的大小。

    【讨论】:

    • 感谢您的回答。但是您能否详细说明为什么上面的代码 sn-p 有效! ..这不是假设崩溃吗?
    • @SangeethSaravanaraj:未定义的行为并不意味着程序总是会崩溃,它只是意味着程序格式不正确,您无法定义它的行为。
    • @SangeethSaravanaraj:未定义的行为是应该发生的。
    【解决方案3】:

    这个array = (data *)malloc(sizeof(data *) * n) 为结构data 分配了一个sizeof(data*)指针),如果你想这样做,你需要一个array 成为data** array

    在您的情况下,您希望指针指向内存中的结构 sizeof(data),而不是另一个指针。这需要data**(指向指针的指针)。

    【讨论】:

      【解决方案4】:

      将其分配给 struct a * 而不是 struct a ** 是否有效?

      嗯,从技术上讲,这样赋值是有效的,但是取消引用这样的指针是错误的(UB)。你不想这样做。

      使用pointer-to-“struct a”访问/取消引用分配的array(n-elements)-of-pointers-to-type-“struct a”是否有效?

      不,未定义的行为。

      【讨论】:

      • malloc() 的调用结果强制转换(或直接分配)到“错误”指针类型当然是安全的。 malloc() 没有类型的概念,它只是分配字节序列。未定义的行为仅由写入超过您要求malloc() 提供给您的字节序列的末尾引起。
      猜你喜欢
      • 2019-11-23
      • 2021-12-26
      • 1970-01-01
      • 2013-02-19
      • 1970-01-01
      • 2014-08-13
      • 1970-01-01
      • 1970-01-01
      • 2014-11-18
      相关资源
      最近更新 更多