【问题标题】:How to use multiple pointers to a struct that contains a pointer to another struct with mutiple pointers?如何使用指向一个结构的多个指针,该结构包含指向另一个具有多个指针的结构的指针?
【发布时间】:2021-03-11 04:55:54
【问题描述】:

我正在尝试使用指向一个结构的指针数组,该结构中包含指向另一个与指针数组一起使用的结构的指针。

我可以为两个单独的结构编写代码并且它可以工作。但是,我不确定如何处理指针数组的引入。 示例代码:

typedef struct {
    double vx;
} particle_t;
    
typedef struct {
    int m;
    int n;
    particle_t *inparticles;    // Pointer to particles inside grid
} grid_t;
    
particle_t *particles = (particle_t*) malloc( 3 * sizeof(particle_t) );
grid_t *grid = (grid_t*) malloc( 3 * sizeof(grid_t) ); // trying 3 pointers

if( particles==NULL || grid==NULL ){
    puts("Unable to allocate memory");
    exit(1);}

// fill the structure 
grid[1].inparticles = particles[1]; // I am not sure how to link these
grid[2].inparticles = particles[2]; // these lines give incompatible types error
grid[3].inparticles = particles[3];
grid[1].m = 5;
grid[1].n = 3;
grid[1].inparticles -> vx = 15;

提前谢谢你!

更新:

我意识到我应该做的是使用inparticles指针指向同一个网格指针中的多个粒子?我如何更改代码以便能够做到这一点? 例如:

grid[0].inparticles[0] = particles[0];
grid[0].inparticles[1] = particles[1];
grid[0].inparticles[2] = particles[2];

以某种方式将其声明为数组?我也需要为它分配内存吗?

【问题讨论】:

标签: c pointers struct


【解决方案1】:

particles 的每个成员都有particle_t 类型。 grid_tinparticles 成员的类型为 particle_t *。所以你想要:

grid[1].inparticles = &particles[1];
grid[2].inparticles = &particles[2];
grid[3].inparticles = &particles[3];

针对您的更新,如果您想让inparticles 指向particles 的各个成员,您需要将inparticles 更改为指向指针的指针:

typedef struct {
    int m;
    int n;
    particle_t **inparticles;
} grid_t;

然后你必须为指针数组分配空间,然后分配每个指针:

grid[0].inparticles = malloc(3 * sizeof(particle_t *));
grid[0].inparticles[0] = &particles[0];
grid[0].inparticles[1] = &particles[1];
grid[0].inparticles[2] = &particles[2];

【讨论】:

  • 我不确定是否应该在这里问这个问题。但是,我将如何使用 inparticles 指针指向同一个网格指针中的多个粒子?以某种方式将其声明为数组?我也需要为它分配内存吗? @dbush
  • @YaserBaqi 查看我的编辑。只需将inparticles 指向particles
  • 澄清,我只是试图指向所有粒子的一个子集。 @dbush
  • @YaserBaqi 它会一直指向 3,还是它指向的粒子数会发生变化?
  • 可能会有所不同。 @dbush
【解决方案2】:

问题

设计

我正在尝试使用指向一个结构的指针数组,该结构中包含指向另一个与指针数组一起使用的结构的指针。

换句话说,我们必须找到一种方法来设计“一个指针数组指向一个结构,其中包含一个指向另一个指针 结构 用作数组".

我会专注于此。

指针数组

但是,我不确定如何处理指针数组的引入。

好吧,我们的代码中没有任何个指针数组……你必须先创建一个。

C 指针、数组、结构及其所有组合在互联网上遍布无数个线程,这些线程被回答了数次。我将向您展示一些基本示例,以便您可以启动并运行,只是不要指望我给您一堂指导课。


解决方案

设计

这是代码(我更改了一些变量名以使其更具可读性):

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

typedef struct
{
    double value;
}Particle;

typedef struct
{
    int width;
    int height;
    Particle *particles;
}Grid;

Grid *createGrid(int width, int height)
{
    Grid *result = malloc(sizeof(Grid));
    if (result == NULL)
    {
        printf("Error while allocating memory for the grid structure!\n");
        exit(1);
    }else
    {
        result->width = width;
        result->height = height;
        result->particles = malloc(sizeof(Particle) * width*height);
    }
    return result;
}

void destroyGrid(Grid *grid)
{
    free(grid->particles);
    free(grid);
}

int main()
{
    Grid *grids[3];
    for (int i = 0; i < 3; i++)
        grids[i] = createGrid(5, 3);
    
    /* Assign, modify, read or copy values from the array of pointers here */
    
    for (int i = 0; i < 3; i++)
        destroyGrid(grids[i]);
    return 0;
}

如您所见,我介绍了 2 个函数让您的生活更轻松:createGriddestroyGrid

第一个需要您指定 2 个参数:网格的 widthheight(代码中的 mn)。然后该函数将分配内存并返回一个指针指向它刚刚创建的网格。

第二个需要你指定 1 个参数:一个 pointer 指向一个网格。然后该函数将释放第一个函数分配的所有内存,避免任何内存泄漏。

我还在主函数中添加了一个指针数组grids。这结合上述函数的使用(都在 main 函数中),解决了第一个问题。

最终设计如下:
"我们有一个 指针数组 指向一个 struct (grids),其中包含一个 指针 指向另一个 struct (particles) 应该用作数组"。

指针数组

您现在可能想知道:“好的,那么我应该如何使用这个指向结构混乱的指针数组?”正如我之前所说,我将仅向您展示一个实际示例。

假设您要将第一个网格的第三个粒子的值设置为 2.7182:(您应该将此代码插入我注释为 /* Assign, modify, read or copy values from the array of pointers here */ 的位置)

grids[0]->particles[2].value = 2.7182;

这可以从左到右读为:“从指针数组grids,获取索引为0的元素(指向Grid结构的第一个指针)。访问其结构成员@987654336 @,它是一个指针。将该指针视为一个数组并获取索引为 2 的元素(第三个 Particle 结构)。访问其成员 value 并为其分配值 2.7182"

然后你可以做一些事情,比如将一个粒子复制到另一个粒子:

grids[1]->particles[1] = grids[0]->particles[2];

这里有一些链接可以更好地理解指针、数组和结构。实践和实验是处理它们的最佳方式:


更新

我意识到我应该做的是使用inparticles指针指向同一个网格指针中的多个粒子

我需要使用一个单独的指向粒子的指针数组。网格结构内部的数组只是指向粒子的一个子集。

目标:“使用 inparticles 指针指向多个(顺序或非顺序?)粒子的子集(在其他地方进行管理)”。

如果您想要顺序解决方案,您可以使用指针,表示指向数组的基地址(或偏移,如果您只想要一个子集)的指针(这是一个指向数组的指针)。这样做的好处是不需要你为每个指针分配额外的内存(因为只需要基地址),但它的缺点是你只能访问彼此相邻的粒子。

例子:

typedef struct
{
    int width;
    int height;
    Particle *subparticles; //Represents a pointer to an array subset
}Grid;
    /*...*/

    grids[0]->subparticles = &particles[0];
    grids[1]->subparticles = &particles[1];

    printf("%f equals %f", grids[0]->subparticles[1].value, grids[1]->subparticles[0].value);

    /*...*/

但是,如果您想要非顺序解决方案,您可以使用双指针(表示指针数组),同时必须手动为数组分配内存。这为您提供了更大的灵活性,但代价是内存分配开销。

typedef struct
{
    /*...other members...*/
    Particle **subparticles;
}Grid;

Grid *createGrid(int subparticlesCount)
{
    Grid *result = malloc(sizeof(Grid));
    if (result == NULL)
    {
        printf("Error while allocating memory for the grid structure!\n");
        exit(1);
    }else
    {
        result->subparticles = malloc(sizeof(Particle *) * subparticlesCount);
    }
    return result;
}
    /*...*/

    grids[0]->subparticles[0] = &particles[1];
    grids[0]->subparticles[1] = &particles[5];
    grids[0]->subparticles[2] = &particles[3];
    grids[1]->subparticles[0] = &particles[3];

    printf("%f equals %f", grids[0]->subparticles[2]->value, grids[1]->subparticles[0]->value);

    /*...*/

【讨论】:

  • 感谢您的来信。但是,我需要使用一个单独的指向粒子的指针数组。网格结构里面的数组只是指向粒子的一个子集。
  • @YaserBaqi 我理解错了,现在更新了答案。
【解决方案3】:

如果该字段是其struct最后一个,则可以将其设为flexible array member,而不是作为指针(指向某个数组)的字段。所以声明

typedef struct {
  int m;
  int n;
  unsigned count;
  particle_t inparticle_arr[];    // flexible array of count elements
} grid_t;

有关示例和详细信息,请参阅 this answer,以及 C 标准(如 n1570 §6.7.2.1)或 this C reference

一些情况下,避免使用指针和间接可能稍微加速你的代码(因为CPU cache)。灵活数组成员还可以避免为该内部灵活数组添加额外的free

为了调试和避免 buffer overflows,编译您的 C 代码,将 GCC 调用为 gcc -Wall -Wextra -g 并使用 valgrind(或 address sanitizer)。

【讨论】:

    【解决方案4】:

    基于问题和后续的 cmets,我的理解是您要创建一个网格,该网格应包含一个指向 指针数组(即多个指针)的指针,其中每个指针指向particle_t 类型的结构体。

    在此理解的基础上,我修改了您的原始代码,并在必要时在代码本身中提供了适当的 cmets。但是,如果我误解了您的问题,请告诉我,我会相应地更新答案。

    #include<stdio.h>
    #include<stdlib.h>
    
    typedef struct {
        double vx;
    } particle_t;
    
    typedef struct {
        int m;
        int n;
        particle_t **inparticles;    // inparticles is a pointer to (array of 
                                    // pointers to inparticle)
        int size; // max number of particles in the grid
    } grid_t;
    
    grid_t *new_grid(int size) { // A helper function to create grid
        grid_t *grid = (grid_t*)malloc(sizeof(grid_t));
        grid->inparticles = (particle_t**)malloc(sizeof(particle_t*));
    
        if(grid == NULL || grid->inparticles == NULL) return NULL;
    
        grid->size = size;
    
        for(int i=0;i<size;++i) {
            grid->inparticles[i] = (particle_t*)malloc(sizeof(particle_t));
            if(grid->inparticles[i] == NULL) {
                return NULL;
            }
        }
    
        return grid;
    }
    int main() {
        particle_t *particles = (particle_t*)malloc( 3 * sizeof(particle_t) );
    
        //create a new grid which can contain multiple particles --- Use a for 
        //loop for creating multiple grids 
        grid_t *grid = new_grid(3);
    
        if( particles==NULL || grid==NULL ){
            puts("Unable to allocate memory");
            exit(1);
        }
    
        grid->inparticles[0] = &particles[0];
        grid->inparticles[1] = &particles[1];
        grid->inparticles[2] = &particles[2];
    
        return 0;
    }
    

    【讨论】:

      【解决方案5】:

      当事情变得复杂时,分而治之是最好的方法。

      在堆上创建一个 particle_t 类型的结构数组:

      particle_t* partAddr = malloc(sizeof(particle_t) * numParticles);
      

      在堆上创建一个grid_t 类型的结构数组:

      grid_t* gridAddr = malloc(sizeof(grid_t) * numGrids);
      

      使grid_t 类型数组的一个元素指向particle_t 类型的已分配元素:

      gridAddr[n].inparticles = partAddr;
      

      为网格第一个元素的数组的第一个元素的vx字段赋值:

      grid[0].inparticles[0].vx= 3;
      

      一切都在一起(粒子的数量可以变化):

      // Define the size of each array of particles
      #define ELEMENTS_ARRAY_PARTICLE_A 5
      #define ELEMENTS_ARRAY_PARTICLE_B 2
      #define ELEMENTS_ARRAY_PARTICLE_C 7
      
      // Create indexes and size to avoid out of boundaries accesses
      enum GRID_PARTICLES {
          ARRAY_PARTICLE_0 = 0,
          ARRAY_PARTICLE_1,
          ARRAY_PARTICLE_2,
          GRID_SIZE
      };
      
      typedef struct {
          double vx;
      } particle_t;
      
      typedef struct {
          particle_t *inparticles;
      } grid_t;
      
      particle_t* allocateArrayOfParticles(int numParticles) {
          particle_t* partAddr = malloc(sizeof(particle_t) * numParticles);
          if(partAddr == NULL){
              // trigger an error
          }
          return partAddr;
      }
      
      void deallocateArrayOfParticles(particle_t *partAddr) {
          free(partAddr);
      }
      
      
      grid_t* allocateGridOfParticles(int numGrids) {
          grid_t* gridAddr = malloc(sizeof(grid_t) * numGrids);
          if(gridAddr == NULL) {
              // trigger an error
          }
          return gridAddr;
      }
      
      void deallocateGridOfParticles(grid_t *gridAddr) {
          free(gridAddr);
      }
      
      int main(void) {    
          grid_t *grid = allocateGridOfParticles(GRID_SIZE);
          particle_t *partA = allocateArrayOfParticles(ELEMENTS_ARRAY_PARTICLE_A);
          particle_t *partB = allocateArrayOfParticles(ELEMENTS_ARRAY_PARTICLE_B);
          particle_t *partC = allocateArrayOfParticles(ELEMENTS_ARRAY_PARTICLE_C);
        
          grid[ARRAY_PARTICLE_0].inparticles = partA;
          grid[ARRAY_PARTICLE_1].inparticles = partB;
          grid[ARRAY_PARTICLE_2].inparticles = partC;
      
          deallocateArrayOfParticles(partA);
          deallocateArrayOfParticles(partB);
          deallocateArrayOfParticles(partC);
          deallocateGridOfParticles(grid);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-07-13
        • 2018-04-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-09
        • 2013-08-26
        相关资源
        最近更新 更多