是“malloc(sizeof(struct a *))"吗?和“malloc(sizeof(struct a))"相同? [英] Are "malloc(sizeof(struct a *))" and "malloc(sizeof(struct a))" the same?

查看:28
本文介绍了是“malloc(sizeof(struct a *))"吗?和“malloc(sizeof(struct a))"相同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题是 Malloc 调用崩溃的延续,但在其他地方有效

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

这里是使用malloc()wrt structurespointers来分配内存的一些基本理解>

  • malloc(sizeof(struct a) * n) 分配nstruct a 类型元素.并且,可以使用 pointer-to-type-"struct a" 存储和访问该内存位置.基本上是一个 struct a *.
  • malloc(sizeof(struct a *) * n) 分配 nstruct 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("无法分配内存
");返回-1;}

代码片段如下:

#include #include int main(void){类型定义结构{整数值1;整数值2;}数据;整数 n = 1000;国际我;int val=0;数据 * 数组 = NULL;if ((array = (data *)malloc(sizeof(data *) * n)) == NULL) {printf("无法分配内存
");返回-1;}printf("分配成功
");对于 (i=0 ; i

<小时>

好吧,如果我以错误

执行以下操作

data * array = NULL;if ((array = (data *)malloc(sizeof(data *) * n)) == NULL) {

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

解决方案

似乎存在根本性的误解.

<块引用>

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 个 char 紧随其后,如果您愿意,可以用 35 个 int 填充剩余的 140 个字节.这是完全无害的定义行为.

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

some_type **array = malloc(100 * sizeof(data *));//故意不相关的类型

完全没问题,只是可能不是您想要的内存量.在这种情况下,它很可能是,因为指针往往具有相同的大小,无论它们指向什么.

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

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

正如你所拥有的.如果将分配的内存用作 ndata 类型元素的数组,则存在三种可能性

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

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

在你的例子中.data 分别为 4 个.8 个字节(可能),在 64 位系统上将它们放入 1.resp.2. 很有可能,在 32 位系统上分成 2 个.3.

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

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

This question is a continuation of Malloc call crashing, but works elsewhere

I tried the following program and I found it working (i.e. not crashing - and this was mentioned in the above mentioned link too). I May be lucky to have it working but I'm looking for a reasonable explanation from the SO experts on why this is working?!

Here are some basic understanding on allocation of memory using malloc() w.r.t structures and pointers

  • malloc(sizeof(struct a) * n) allocates n number of type struct a elements. And, this memory location can be stored and accessed using a pointer-to-type-"struct a". Basically a struct a *.
  • malloc(sizeof(struct a *) * n) allocates n number of type struct a * elements. Each element can then point to elements of type struct a. Basically malloc(sizeof(struct a *) * n) allocates an array(n-elements)-of-pointers-to-type-"struct a". And, the allocated memory location can be stored and accessed using a pointer-to-(pointer-to-"struct a"). Basically a struct a **.

So when we create an array(n-elements)-of-pointers-to-type-"struct a", is it

  1. valid to assign that to struct a * instead of struct a ** ?
  2. valid to access/de-reference the allocated array(n-elements)-of-pointers-to-type-"struct a" using pointer-to-"struct a" ?

data * array = NULL;

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

The code snippet is as follows:

#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 
");
        return -1; 
    }   
    printf("allocation successful
");

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

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

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

    return 0;
}


EDIT: OK say if I do the following by mistake

data * array = NULL;
if ((array = (data *)malloc(sizeof(data *) * n)) == NULL) {

Is there a way to capture (during compile-time using any GCC flags) these kind of unintended programming typo's which could work at times and might blow out anytime! I compiled this using -Wall and found no warnings!

解决方案

There seems to be a fundamental misunderstanding.

malloc(sizeof(struct a) * n) allocates n number of type struct a elements.

No, that's just what one usually does use it as after such a call. malloc(size) allocates a memory region of size bytes. What you do with that region is entirely up to you. The only thing that matters is that you don't overstep the limits of the allocated memory. Assuming 4 byte float and int and 8 byte double, after a successful malloc(100*sizeof(float));, you can use the first 120 of the 400 bytes as an array of 15 doubles, the next 120 as an array of 30 floats, then place an array of 20 chars right behind that and fill up the remaining 140 bytes with 35 ints if you wish. That's perfectly harmless defined behaviour.

malloc returns a void*, which can be implicitly cast to a pointer of any type, so

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

is perfectly fine, it might just not be the amount of memory you wanted. In this case it very likely is, because pointers tend to have the same size regardless of what they're pointing to.

More likely to give you the wrong amount of memory is

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

as you had it. If you use the allocated piece of memory as an array of n elements of type data, there are three possibilities

  1. sizeof(data) < sizeof(data*). Then your only problem is that you're wasting some space.
  2. sizeof(data) == sizeof(data*). Everything's fine, no space wasted, as if you had no typo at all.
  3. sizeof(data) > sizeof(data*). Then you'll access memory you shouldn't have accessed when touching later array elements, which is undefined behaviour. Depending on various things, that could consistently work as if your code was correct, immediately crash with a segfault or anything in between (technically it could behave in a manner that cannot meaningfully be placed between those two, but that would be unusual).

If you intentionally do that, knowing point 1. or 2. applies, it's bad practice, but not an error. If you do it unintentionally, it is an error regardless of which point applies, harmless but hard to find while 1. or 2. applies, harmful but normally easier to detect in case of 3.

In your examples. data was 4 resp. 8 bytes (probably), which on a 64-bit system puts them into 1. resp. 2. with high probability, on a 32-bit system into 2 resp. 3.

The recommended way to avoid such errors is to

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

这篇关于是“malloc(sizeof(struct a *))"吗?和“malloc(sizeof(struct a))"相同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆