带指针的多维数组元素赋值

Multidimensional array element assignment with pointer

我有一个参差不齐的二维结构数组和一个分配函数 return mystruct*:

mystruct** arr;
mystruct* foo();

arr 元素赋值的语法是什么?以下内容不起作用,但我想要类似的东西:

&arr[i][j]=foo();

这是一个简化的例子:

typedef struct mystruct{
    int a,b,c,d;
} mystruct;

mystruct* foo()
{
    mystruct* x = (mystruct*)malloc(sizeof(mystruct));
    x->a=1;
    x->b=1;
    x->c=1;
    x->d=1;
    return x;
}

int main()
{
    int rows=3;
    int cols=4;

    mystruct** arr;
    arr = (mystruct**) malloc(sizeof(mystruct*)*rows);
    for(int i=0;i<rows;i++)
    {
        arr[i]=(mystruct*)malloc(sizeof(mystruct)*cols);
    }

    for (int i=0;i<rows;i++)
    {
        *(arr[i][0]) = foo();
    }

    return 0;
}

我已经删除了大部分主程序,但上面的代码仍然给我 error: no match for ‘operator*’ (operand type is ‘mystruct’)

在实际代码中 mystruct 很大,数组的维度也很大。

*(arr[i][j]) = foo(); 会将二维数组中指向结构的指针的值设置为指向 foo 返回的结构的指针,如果这是您真正想要的。

如果您只想保留指向结构的二维指针数组,那么您可以将数组声明更改为 mystruct* arr[3][4] 并使用 arr[i][j] = foo().

如果您真的希望 mystruct 的所有实例都在一个分配中(即保持 foo 不变),那么数组可以是:

int main()
{
    int rows=3;
    int cols=4;

    mystruct *(*arr)[cols] = malloc( rows * sizeof *arr );

    for(int i=0; i<rows; i++)
        arr[i][0] = foo();

    // note: arr[i][1] etc. are uninitialized 

    free(arr);
}

当每一行的长度相同时,无需为数组的每一行使用单独的 malloc,而是可以 malloc 单个块。还有 don't cast malloc.


如果您不需要每行分配一次,并且您很乐意用 void bar(mystruct *p) 构造 mystruct 并使用指向某个已分配存储的指针调用,那么您的数组可以存储 mystruct 直接对象:

mystruct (*arr)[cols] = malloc( rows * sizeof *arr );

for ( int i = 0; i < rows; ++i )
    bar( &arr[i][0] );

我认为在这种情况下使用一些抽象会有所帮助。我匆忙写了下面的例子,希望对你有帮助。

更新:根据评论修改。仍然在 gcc 下编译,现在通过 Valgrind 干净地运行。

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

typedef struct SomeStruct SomeStruct;
struct SomeStruct {
  int foo;
  int bar;
};
typedef SomeStruct* SomeStruct_ptr;
typedef struct SomeStructMat SomeStructMat;
typedef SomeStructMat* SomeStructMat_ptr;
struct SomeStructMat {
  int rows;
  int cols;
  SomeStruct_ptr** data;
};

SomeStruct_ptr somestruct_new(int foo, int bar) {
  SomeStruct_ptr ssp = malloc(sizeof(SomeStruct));
  ssp->foo = foo;
  ssp->bar = bar;
  return ssp;
}

void somestruct_destroy(SomeStruct_ptr ssp) {
  free(ssp);
}

SomeStruct_ptr** somestructmat_new(int rows, int cols) {
  int r, c;
  SomeStruct_ptr** mat = malloc( rows * sizeof(SomeStruct_ptr*) );

  for(r = 0; r < rows; ++r) {
    mat[r] = malloc(sizeof(SomeStruct_ptr) * cols);
    for(c = 0; c < cols; ++c) {
      mat[r][c] = somestruct_new(0,0);
    }
  }
  return mat;
}

SomeStructMat_ptr SomeStructMat_new(int rows, int cols) {
  SomeStructMat_ptr mat = malloc(sizeof(SomeStructMat));
  mat->rows = rows;
  mat->cols = cols;
  mat->data = somestructmat_new(rows, cols); 
  return mat;
}

void SomeStructMat_destroy(SomeStructMat_ptr mat) {
  int r,c;
  for(r = 0; r < mat->rows; r++) {
    for(c = 0; c < mat->cols; c++) {
      free(mat->data[r][c]);
    }
    free(mat->data[r]);
  }
  free(mat->data);
  free(mat);
}

int SomeStructMat_overwrite(SomeStructMat_ptr ssm, int r, int c, SomeStruct_ptr ssp) {
  // TODO: Check that r and c are within bounds!
  somestruct_destroy(ssm->data[r][c]);
  ssm->data[r][c] = ssp;
}

void SomeStructMat_print(SomeStructMat_ptr mat) {
  int r,c;
  for(r = 0; r < mat->rows; r++) {
    for(c = 0; c < mat->cols; c++) {
      printf("[%d, %d] ", mat->data[r][c]->foo, mat->data[r][c]->bar);
    }
    printf("\n");
  }
}

int main(int argc, char** argv) {
  SomeStructMat_ptr ssm = SomeStructMat_new(2,3);

  SomeStructMat_print(ssm);

  printf("----------------\n");

  SomeStructMat_overwrite(ssm, 0, 1, somestruct_new(5,6));

  SomeStructMat_print(ssm);

  printf("----------------\n");

  SomeStructMat_destroy(ssm);

  return 0;
}

更新:要在 g++ 下编译,您需要强制转换来自 malloc 的 void 指针。像这样:

#include <cstdio>
#include <cstdlib>

typedef struct SomeStruct SomeStruct;
struct SomeStruct {
  int foo;
  int bar;
};
typedef SomeStruct* SomeStruct_ptr;
typedef struct SomeStructMat SomeStructMat;
typedef SomeStructMat* SomeStructMat_ptr;
struct SomeStructMat {
  int rows;
  int cols;
  SomeStruct_ptr** data;
};

SomeStruct_ptr somestruct_new(int foo, int bar) {
  SomeStruct_ptr ssp = (SomeStruct_ptr) malloc(sizeof(SomeStruct));
  ssp->foo = foo;
  ssp->bar = bar;
  return ssp;
}

void somestruct_destroy(SomeStruct_ptr ssp) {
  free(ssp);
}

SomeStruct_ptr** somestructmat_new(int rows, int cols) {
  int r, c;
  SomeStruct_ptr** mat = (SomeStruct_ptr**) malloc( rows * sizeof(SomeStruct_ptr*) );

  for(r = 0; r < rows; ++r) {
    mat[r] = (SomeStruct_ptr*) malloc(sizeof(SomeStruct_ptr) * cols);
    for(c = 0; c < cols; ++c) {
      mat[r][c] = somestruct_new(0,0);
    }
  }
  return mat;
}

SomeStructMat_ptr SomeStructMat_new(int rows, int cols) {
  SomeStructMat_ptr mat = (SomeStructMat_ptr) malloc(sizeof(SomeStructMat));
  mat->rows = rows;
  mat->cols = cols;
  mat->data = somestructmat_new(rows, cols); 
  return mat;
}

void SomeStructMat_destroy(SomeStructMat_ptr mat) {
  int r,c;
  for(r = 0; r < mat->rows; r++) {
    for(c = 0; c < mat->cols; c++) {
      free(mat->data[r][c]);
    }
    free(mat->data[r]);
  }
  free(mat->data);
  free(mat);
}

int SomeStructMat_overwrite(SomeStructMat_ptr ssm, int r, int c, SomeStruct_ptr ssp) {
  // TODO: Check that r and c are within bounds!
  somestruct_destroy(ssm->data[r][c]);
  ssm->data[r][c] = ssp;
}

void SomeStructMat_print(SomeStructMat_ptr mat) {
  int r,c;
  for(r = 0; r < mat->rows; r++) {
    for(c = 0; c < mat->cols; c++) {
      printf("[%d, %d] ", mat->data[r][c]->foo, mat->data[r][c]->bar);
    }
    printf("\n");
  }
}

int main(int argc, char** argv) {
  SomeStructMat_ptr ssm = SomeStructMat_new(2,3);

  SomeStructMat_print(ssm);

  printf("----------------\n");

  SomeStructMat_overwrite(ssm, 0, 1, somestruct_new(5,6));

  SomeStructMat_print(ssm);

  printf("----------------\n");

  SomeStructMat_destroy(ssm);

  return 0;
}