C:指向结构指针数组的指针(分配/解除分配问题) [英] C: pointer to array of pointers to structures (allocation/deallocation issues)

查看:35
本文介绍了C:指向结构指针数组的指针(分配/解除分配问题)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在重新学习 C 语言,但是我很难记住这种内存管理是如何工作的.我想要一个指向结构指针数组的指针.

I've been getting back into C for something, but I'm having trouble remembering much of how this memory management works. I'd like to have a pointer to an array of pointers to structures.

说我有:

struct Test {
   int data;
};

然后是数组:

struct Test **array1;

这是正确的吗?我的问题是处理这件事.所以数组中的每个指针都指向单独分配的东西.但我想我需要先这样做:

Is this correct? My issue is working with this thing. So each pointer in the array points to something that is allocated separately. But I think I need to do this first:

array1 = malloc(MAX * sizeof(struct Test *));

我无法理解上述内容.我是否需要这样做,为什么我需要这样做?特别是,如果我要为指针指向的每个事物分配内存,那么为指针分配内存意味着什么?

I am having trouble understanding the above. Do I need to do this, and why do I need to do this? In particular, what does it mean to allocate memory for pointers if I am going to be allocating memory for each thing that the pointer points to?

现在说我有一个指向结构指针数组的指针.我现在希望它指向我之前创建的同一个数组.

Say now I have pointer to an array of pointers to structures. I now want it to point to the same array that I've created earlier.

struct Test **array2;

我是否需要像上面那样为指针分配空间,或者我可以这样做:

Do I need to allocate room for pointers like I did above, or can I just do:

array2 = array1

推荐答案

Allocated Array

有了分配的数组,就很容易理解了.

With an allocated array it's straightforward enough to follow.

声明你的指针数组.这个数组中的每个元素都指向一个struct Test:

Declare your array of pointers. Each element in this array points to a struct Test:

struct Test *array[50];

然后根据需要分配和分配指向结构的指针.使用循环很简单:

Then allocate and assign the pointers to the structures however you want. Using a loop would be simple:

array[n] = malloc(sizeof(struct Test));

然后声明一个指向这个数组的指针:

Then declare a pointer to this array:

                               // an explicit pointer to an array 
struct Test *(*p)[] = &array;  // of pointers to structs

这允许您使用 (*p)[n]->data;引用第 n 个成员.

This allows you to use (*p)[n]->data; to reference the nth member.

不要担心这些东西是否令人困惑.这可能是 C 最困难的方面.

Don't worry if this stuff is confusing. It's probably the most difficult aspect of C.

动态线阵

如果你只想分配一个结构块(实际上是一个结构数组,不是指向结构的指针),并且有一个指向该块的指针,你可以更容易地做到:

If you just want to allocate a block of structs (effectively an array of structs, not pointers to structs), and have a pointer to the block, you can do it more easily:

struct Test *p = malloc(100 * sizeof(struct Test));  // allocates 100 linear
                                                     // structs

然后你可以指向这个指针:

You can then point to this pointer:

struct Test **pp = &p

您不再有指向结构的指针数组,但它大大简化了整个过程.

You don't have an array of pointers to structs any more, but it simplifies the whole thing considerably.

动态分配结构的动态数组

最灵活,但不经常需要.它与第一个示例非常相似,但需要额外的分配.我已经编写了一个完整的程序来演示这应该可以正常编译.

The most flexible, but not often needed. It's very similar to the first example, but requires an extra allocation. I've written a complete program to demonstrate this that should compile fine.

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

struct Test {
    int data;
};

int main(int argc, char **argv)
{
    srand(time(NULL));

    // allocate 100 pointers, effectively an array
    struct Test **t_array = malloc(100 * sizeof(struct Test *));

    // allocate 100 structs and have the array point to them
    for (int i = 0; i < 100; i++) {
        t_array[i] = malloc(sizeof(struct Test));
    }

    // lets fill each Test.data with a random number!
    for (int i = 0; i < 100; i++) {
        t_array[i]->data = rand() % 100;
    }

    // now define a pointer to the array
    struct Test ***p = &t_array;
    printf("p points to an array of pointers.
"
       "The third element of the array points to a structure,
"
       "and the data member of that structure is: %d
", (*p)[2]->data);

    return 0;
}

输出:

> p points to an array of pointers.
> The third element of the array points to a structure,
> and the data member of that structure is: 49

或者整套:

for (int i = 0; i < 100; i++) {
    if (i % 10 == 0)
        printf("
");
    printf("%3d ", (*p)[i]->data);
}

 35  66  40  24  32  27  39  64  65  26 
 32  30  72  84  85  95  14  25  11  40 
 30  16  47  21  80  57  25  34  47  19 
 56  82  38  96   6  22  76  97  87  93 
 75  19  24  47  55   9  43  69  86   6 
 61  17  23   8  38  55  65  16  90  12 
 87  46  46  25  42   4  48  70  53  35 
 64  29   6  40  76  13   1  71  82  88 
 78  44  57  53   4  47   8  70  63  98 
 34  51  44  33  28  39  37  76   9  91 

<小时>

单动态分配结构的动态指针数组

最后一个例子相当具体.正如我们在前面的示例中看到的那样,它是一个动态指针数组,但与那些不同的是,元素都在单个分配中分配.这有其用途,最显着的是对不同配置中的数据进行排序,同时保持原始分配不受干扰.

This last example is rather specific. It is a dynamic array of pointers as we've seen in previous examples, but unlike those, the elements are all allocated in a single allocation. This has its uses, most notable for sorting data in different configurations while leaving the original allocation undisturbed.

我们首先分配一个元素块,就像我们在最基本的单块分配中所做的那样:

We start by allocating a single block of elements as we do in the most basic single-block allocation:

struct Test *arr = malloc(N*sizeof(*arr));

现在我们分配一个单独的指针块:

Now we allocate a separate block of pointers:

struct Test **ptrs = malloc(N*sizeof(*ptrs));

然后我们用原始数组之一的地址填充指针列表中的每个插槽.由于指针算法允许我们从一个元素移动到另一个元素地址,这很简单:

We then populate each slot in our pointer list with the address of one of our original array. Since pointer arithmetic allows us to move from element to element address, this is straight-forward:

for (int i=0;i<N;++i)
    ptrs[i] = arr+i;

此时以下均指同一个元素字段

At this point the following both refer to the same element field

arr[1].data = 1;
ptrs[1]->data = 1;

在查看以上内容后,我希望您清楚为什么.

And after review the above, I hope it is clear why.

当我们处理完指针数组和原始块数组后,它们被释放为:

When we're done with the pointer array and the original block array they are freed as:

free(ptrs);
free(arr);

注意:我们不会单独释放 ptrs[] 数组中的每个项目.他们不是这样分配的.它们被分配为单个块(由 arr 指向),这就是它们应该被释放的方式.

Note: we do NOT free each item in the ptrs[] array individually. That is not how they were allocated. They were allocated as a single block (pointed to by arr), and that is how they should be freed.

那么为什么有人要这样做呢?几个原因.

So why would someone want to do this? Several reasons.

首先,它从根本上减少了内存分配调用的次数.而不是 N+1(一个用于指针数组,N 用于单个结构),您现在只有 两个:一个用于数组块,一个用于指针数组.内存分配是程序可以请求的最昂贵的操作之一,并且在可能的情况下,最好将它们最小化(注意:文件 IO 是另一个,仅供参考).

First, it radically reduces the number of memory allocation calls. Rather then N+1 (one for the pointer array, N for individual structures) you now have only two: one for the array block, and one for the pointer array. Memory allocations are one of the most expensive operations a program can request, and where possible, it is desirable to minimize them (note: file IO is another, fyi).

另一个原因:同一基本数据数组的多种表示.假设您想对数据进行升序和降序排序,并且同时使用两种排序表示.您可以复制数据数组,但这需要大量复制并占用大量内存.相反,只需分配一个额外的指针数组并用基数组中的地址填充它,然后对该指针数组进行排序.当要排序的数据很大(每个项目可能达到千字节,甚至更大)时,这具有特别显着的优势无需实际移动它们.您对指向项目的指针数组进行排序;项目根本不会移动.

Another reason: Multiple representations of the same base array of data. Suppose you wanted to sort the data both ascending and descending, and have both sorted representations available at the same time. You could duplicate the data array, but that would require a lot of copying and eat significant memory usage. Instead, just allocate an extra pointer array and fill it with addresses from the base array, then sort that pointer array. This has especially significant benefits when the data being sorted is large (perhaps kilobytes, or even larger, per item) The original items remain in their original locations in the base array, but now you have a very efficient mechanism in which you can sort them without having to actually move them. You sort the array of pointers to items; the items don't get moved at all.

我意识到这是一个非常多的东西,但是指针的使用对于理解你可以用 C 语言做的许多强大的事情是至关重要的,所以点击书本并不断刷新你的记忆.它会回来的.

I realize this is an awful lot to take in, but pointer usage is critical to understanding the many powerful things you can do with the C language, so hit the books and keep refreshing your memory. It will come back.

这篇关于C:指向结构指针数组的指针(分配/解除分配问题)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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