Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C:指向结构指针数组的指针(分配/解除分配问题)_C_Pointers_Memory_Memory Management - Fatal编程技术网

C:指向结构指针数组的指针(分配/解除分配问题)

C:指向结构指针数组的指针(分配/解除分配问题),c,pointers,memory,memory-management,C,Pointers,Memory,Memory Management,我回到C是因为一些事情,但我很难记住这种内存管理是如何工作的。我想要一个指向指向结构的指针数组的指针 假设我有: struct Test { int data; }; 然后阵列: struct Test **array1; 这是正确的吗?我的问题是处理这件事。因此,数组中的每个指针都指向单独分配的对象。但我想我需要先这样做: array1 = malloc(MAX * sizeof(struct Test *)); 我很难理解上面的内容。我需要这样做吗?为什么我需要这样做?特别是,如

我回到C是因为一些事情,但我很难记住这种内存管理是如何工作的。我想要一个指向指向结构的指针数组的指针

假设我有:

struct Test {
   int data;
};
然后阵列:

struct Test **array1;
这是正确的吗?我的问题是处理这件事。因此,数组中的每个指针都指向单独分配的对象。但我想我需要先这样做:

array1 = malloc(MAX * sizeof(struct Test *));
我很难理解上面的内容。我需要这样做吗?为什么我需要这样做?特别是,如果我要为指针指向的每个对象分配内存,那么为指针分配内存意味着什么

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

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

array2 = array1

我建议您一次构建一个层,使用typdefs创建类型层。通过这样做,所需的不同类型将更加清晰

例如:

typedef struct Test {
   int data;
} TestType;

typedef  TestType * PTestType;
这将创建两个新类型,一个用于结构,另一个用于指向结构的指针

所以接下来,如果您想要一个结构数组,那么您将使用:

TestType array[20];  // creates an array of 20 of the structs
PTestType array2[20];  // creates an array of 20 of pointers to the struct
如果需要指向结构的指针数组,则可以使用:

TestType array[20];  // creates an array of 20 of the structs
PTestType array2[20];  // creates an array of 20 of pointers to the struct
然后,如果要将结构分配到数组中,可以执行以下操作:

PTestType  array2[20];  // creates an array of 20 of pointers to the struct
// allocate memory for the structs and put their addresses into the array of pointers.
for (int i = 0; i < 20; i++) {
    array2 [i] = malloc (sizeof(TestType));
}
接下来,我们将使用一个helper函数来创建对象,该函数被恰当地命名为
CreateTestData(int nArrayCount)

现在,我们可以使用下面的源代码段中的新对象。它应该检查CreateTestData()返回的指针是否有效,但这实际上只是为了说明可以做什么

PTestData  go = CreateTestData (20);
{
    int i = 0;
    for (i = 0; i < go->nStructs; i++) {
        go->pBlob[i].myData = i;
    }
}

已分配阵列

有了分配的数组,就足够简单了

声明指针数组。此数组中的每个元素都指向一个
结构测试

struct Test *array[50];
然后根据需要分配指针并将其分配给结构。使用循环很简单:

array[n] = malloc(sizeof(struct Test));
然后声明指向此数组的指针:

                               // an explicit pointer to an array 
struct Test *(*p)[] = &array;  // of pointers to structs
这允许您使用
(*p)[n]>数据
;引用第n个成员

如果这些东西让人困惑,不要担心。这可能是C语言中最困难的方面


动态线性阵列

如果您只想分配一个结构块(实际上是一个结构数组,而不是指向结构的指针),并有一个指向该块的指针,则可以更轻松地执行此操作:

struct Test *p = malloc(100 * sizeof(struct Test));  // allocates 100 linear
                                                     // structs
然后可以指向此指针:

struct Test **pp = &p
您不再有指向结构的指针数组,但它大大简化了整个过程


动态分配结构的动态数组

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

#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;
}
或整套:

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 
现在,我们分配一个单独的指针块:

struct Test **ptrs = malloc(N*sizeof(*ptrs));
struct Test *tmp = array1[2];  // Save the pointer to one struct.
array1[2] = array1[5];         // Aim the pointer at a different struct.
array1[5] = tmp;               // Aim the other pointer at the original struct.
然后,我们用一个原始数组的地址填充指针列表中的每个插槽。由于指针算法允许我们从一个元素移动到另一个元素地址,因此这是直截了当的:

for (int i=0;i<N;++i)
    ptrs[i] = arr+i;
在回顾了以上内容之后,我希望能弄清楚原因

完成指针数组和原始块数组后,它们被释放为:

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

那么为什么会有人想这么做呢?有几个原因

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

另一个原因是:同一基本数据数组的多个表示形式。假设您希望对数据进行升序和降序排序,并且两种排序表示形式同时可用。您可以复制数据数组,但这需要大量复制,并占用大量内存。相反,只需分配一个额外的指针数组并用基数组中的地址填充它,然后对该指针数组进行排序。当要排序的数据很大(每个项可能有千字节,甚至更大)时,这具有特别显著的好处原始项保留在基本数组中的原始位置,但现在有了一种非常有效的机制,您可以在不必实际移动它们的情况下对其进行排序。对指向项的指针数组进行排序;这些物品根本不会移动


我意识到这是一个很难理解的问题,但是指针的使用对于理解C语言可以做的许多强大的事情是至关重要的,所以请阅读相关书籍并不断刷新您的内存。它会回来的。

正如其他人所建议的那样,最好声明一个实际的数组,但您的问题似乎更多地是关于内存管理的,所以我将对此进行讨论

struct Test **array1;
这是指向
结构测试的地址的指针。(不是指向结构本身的指针;它是指向保存结构地址的内存位置的指针。)声明为指针分配内存,但不为指针指向的项分配内存。由于可以通过指针访问数组,因此可以使用
*array1
作为指向其元素类型为
struct Test
的数组的指针。但目前还没有一个实际的数组供它指向

array1 = malloc(MAX * sizeof(struct Test *));
这将分配内存来保存
MAX
指向
struct Test
类型项的指针。再说一次,它
free(ptrs);
free(arr);
struct Test **array1;
array1 = malloc(MAX * sizeof(struct Test *));
struct Test testStruct0;  // Declare a struct.
struct Test testStruct1;
array1[0] = &testStruct0;  // Point to the struct.
array1[1] = &testStruct1;
for (int i=0; i<MAX; ++i) {
  array1[i] = malloc(sizeof(struct Test));
}
struct Test **array2 = array1;
struct Test *array1 = malloc(MAX * sizeof(struct Test));  // Pointer to MAX structs
struct Test testStruct0 = array1[0];     // Copies the 0th struct.
struct Test testStruct0a= *array1;       // Copies the 0th struct, as above.
struct Test *ptrStruct0 = array1;        // Points to the 0th struct.

struct Test testStruct1 = array1[1];     // Copies the 1st struct.
struct Test testStruct1a= *(array1 + 1); // Copies the 1st struct, as above.
struct Test *ptrStruct1 = array1 + 1;    // Points to the 1st struct.
struct Test *ptrStruct1 = &array1[1];    // Points to the 1st struct, as above.
struct Test *tmp = array1[2];  // Save the pointer to one struct.
array1[2] = array1[5];         // Aim the pointer at a different struct.
array1[5] = tmp;               // Aim the other pointer at the original struct.
char *p;
p = malloc (CNT * sizeof *p);
char **pp;
pp = malloc (CNT * sizeof *pp);
struct something *p;
p = malloc (CNT * sizeof *p);
struct something **pp;
pp = malloc (CNT * sizeof *pp);