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

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

问题描述

我已经得到回成C的东西,但我有很难记住这在很大程度上内存管理是如何工作的。我想有一个指向指针数组结构。

说我有:

 结构测试{
   int数据;
};

然后数组:

 结构测试**数组1;

这是正确的?我的问题正在与这件事情。所以阵列中的每个指针指向被单独分配的东西。但我想我需要做的这第一:

  ARRAY1 =的malloc(MAX *的sizeof(结构测试*));

我无法理解之上。我需要做,为什么我要这么做?尤其是,这是什么意思为指针分配内存,如果我要对每个事情被分配内存的指针指向?

说现在我已经指针的指针数组结构。我现在希望它指向我前面创建的同一个数组。

 结构测试**数组2;

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

 数组2 = ARRAY1


解决方案

分配的数组

随着分配的数组它足够简单效仿。

您的声明指针数组。在这阵点每一个元素结构测试

 结构测试*阵列[50];

然后分配和指定的指针不过你想要的结构。使用循环是简单的:

 数组[N] =的malloc(sizeof的(结构测试));

然后指针声明这个数组:

  //一个明确的指向数组的指针
结构测试*(* P)[] =&放大器;阵列; //指针,以结构

这使您可以使用(* P)[N] - >数据;以引用的第n个构件。

如果这个东西是混乱的,不要担心。这可能是C的最困难的方面。


动态线阵

如果你只是想分配结构块(有效结构的数组,的的指针结构),并有一个指针来将挡,你可以更容易地做到这一点:

 结构测试* P =的malloc(100 * sizeof的(结构测试)); //分配100线
                                                     //结构

然后,您可以指向这个指针:

 结构测试** PP =安培,P

您没有指针数组结构了,但是它大大简化了整个事情。


分配结构体动态的动态数组

最灵活的,但不是经常需要的。这是非常相似于第一实施例,但需要一个额外的分配。我写了一个完整的程序来证明这一点,应该编译罚款。

 的#include<&stdio.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;&time.h中GT;结构测试{
    int数据;
};INT主(INT ARGC,字符** argv的)
{
    函数srand(时间(NULL));    //分配100指针,有效的数组
    结构测试** t_array =的malloc(100 * sizeof的(结构测试*));    //分配100结构,并有阵点给他们
    的for(int i = 0; I< 100;我++){
        t_array [I] =的malloc(sizeof的(结构测试));
    }    //让填充每个Test.data一个随机数!
    的for(int i = 0; I< 100;我++){
        t_array [I] - >数据=兰特()%100;
    }    //现在定义的指针数组
    结构测试*** P =安培; t_array;
    的printf(p指向数组的指针。\\ n
       阵列指向一个结构的第三个元件,的\\ n
       与该结构的数据成员是:%d个\\ N,(* p)的[2] - >数据);    返回0;
}

输出:

 > p指向数组的指针。
>阵列的点的第三元件的结构中,
>与该结构的数据成员是:49

或者整套:

 的for(int i = 0; I< 100;我++){
    如果(I%10 == 0)
        的printf(\\ n);
    的printf(%三维,(* p)的[I] - GT;数据);
} 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 22 6 76 97 87 93
 75 19 24 47 55 43 9 69 86 6
 61 17 23 38 8 55 65 16 90 12
 87 46 46 25 42 48 4 70 53 35
 64 29 6 40 76 13 71 1 82 88
 78 44 57 53 47 4 8 70 63 98
 34 51 44 33 28 39 37 76 91 9


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

这最后一个例子是相当具体。这是因为我们在previous例子已经看到指针的动态数组,但不像那些的元素都在的分配分配。这有它的用途,最引人注目的是在不同的配置排序数据,同时离开原来的分配不受干扰。

我们开始通过分配元素的单块正如我们在最基本的单块分配做的:

 结构测试* ARR =的malloc(N * sizeof的(* ARR));

现在我们分配的独立的指针块:

 结构测试**师生比=的malloc(N * sizeof的(*师生比));

我们然后填充每个时隙在我们与原始数组中的一个的地址指针列表。由于指针运算允许我们从元素元素地址动,这是直接的:

 的for(int i = 0; I< N ++ I)
    师生比[I] =改编+ I;

此时以下指的是相同的元件字段

 改编[1]。数据= 1;
师生比[1] - >数据= 1;

和审查上述过后,我希望它是明确的为什么

当我们用指针数组,他们被释放的原始块阵列完成的:

 免费(师生比);
免费(ARR);

请注意:我们不单独释放师生比[] 阵列中的每个项目。这不是他们是如何分配的。他们被分配作为一个单独的块(指向改编),这是他们应该如何被释放。

那么,为什么会有人想这样做?几个原因。

首先,它从根本上减少了存储器分配的呼叫的数量。而不是 N + 1 (一个用于指针数组,N为单个结构),你现在只有的两个:一个用于阵列块,和一个用于指针数组。内存分配是最昂贵的操作的程序可以要求之一,并在可能的情况,最好是尽量减少他们(注:文件IO是另一种,仅供参考)

还有一个原因:数据相同的基本阵列的多个重presentations。假设你想将数据升序和降序排序,并同时拥有重新排序$ P $在同一时间提供的 psentations 的。您可以复制数据数组,但这需要大量的复制,吃显著内存使用情况。相反,只是分配一个额外的指针数组,并从基本阵列地址填写,然后进行排序的指针数组。这有特别显著的好处时被排序的数据量较大(可能是千字节,甚至更大,每件)原项目保持在基本阵列中的原始位置,但现在你有一个非常有效的机制,可以在其中对它们进行排序而无需实际移动的他们。您排序指针项目的数组;项目没有得到根本感动。

我意识到这是一个可怕的很多参加,但指针的用法是理解许多强大的东西,你可以用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.

Say I have:

struct Test {
   int data;
};

Then the array:

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.

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

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

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


Dynamic Linear Array

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.


Dynamic Array of Dynamically Allocated Structs

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.\n"
       "The third element of the array points to a structure,\n"
       "and the data member of that structure is: %d\n", (*p)[2]->data);

    return 0;
}

Output:

> 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

Or the whole set:

for (int i = 0; i < 100; i++) {
    if (i % 10 == 0)
        printf("\n");
    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 


Dynamic Pointer Array of Single-Dynamic Allocated Structs

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);

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.

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.

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天全站免登陆