C 需要一个二维数组;变量";结构中的大小
我试图实现一个网格的细胞,类似于康威的生活游戏 虽然每个单独的网格在两个维度上都应该有固定的大小,但我想要一个网格结构,它允许两个维度上的任何大小 这类似于数组可以是任意大小,但数组一旦初始化就有固定大小 这就是我到目前为止所做的:C 需要一个二维数组;变量";结构中的大小,c,arrays,multidimensional-array,struct,dynamic-memory-allocation,C,Arrays,Multidimensional Array,Struct,Dynamic Memory Allocation,我试图实现一个网格的细胞,类似于康威的生活游戏 虽然每个单独的网格在两个维度上都应该有固定的大小,但我想要一个网格结构,它允许两个维度上的任何大小 这类似于数组可以是任意大小,但数组一旦初始化就有固定大小 这就是我到目前为止所做的: typedef struct Cell { int data; // stuff to be added later } Cell; typedef struct Grid { unsigned width; unsigned he
typedef struct Cell {
int data;
// stuff to be added later
} Cell;
typedef struct Grid {
unsigned width;
unsigned height;
Cell cell[][];
} Grid;
Grid initGrid(unsigned width, unsigned height) {
Grid g;
g.width = width;
g.height = height;
g.cell = malloc( sizeof(Cell)*width*height );
return g;
}
但是,我得到以下编译时错误:
main.c|12|note: declaration of `‘cell’ as multidimensional array must have bounds for all dimensions except the first|
如何定义大小灵活的网格
数据类型
Post scriptum:作为一名C新手,我认为以下方法可以奏效:
typedef struct Grid {
unsigned width;
unsigned height;
Cell cell[width][height];
} Grid;
后脚本:每当我使用
malloc
时,我总是感到不安。我在做(或试图做)什么可怕的错误吗?在C中,使用双索引(cell[x][y]
)无法做到这一点,无法表示每行要跳转的字节数是动态的
所以,最好的方法(在我看来)是使用一维数组手动建立索引
简单地说:
Cell *cell;
在struct
(保持width
和height
)中,然后像这样索引:
set_cell(Grid *g, unsigned int x, unsigned int y, Cell value)
{
g->cell[y * g->width + x] = value;
}
编译器不太可能将其内联,而且它将非常紧凑。可能比使用更多内存和另一层间接寻址的“锯齿数组”方法更快
分配很简单:
Grid initGrid(unsigned int width, unsigned int height)
{
Grid g;
g.width = width;
g.height = height;
g.cell = malloc(width * height * sizeof *g.cell);
// add assert or error here, can't return NULL for value type
return g;
}
如果您也希望堆分配网格
,您可以将其与其元素共同分配
是的,您需要free()
分配完成后,才能避免内存泄漏。严格来说,在现代系统上,无论程序如何结束,操作系统都会释放所有资源,但无论如何释放都是一种好形式:
void destroyGrid(Grid g)
{
free(g.cell);
}
在这里,您的运气很差,因为在C中,无法在
结构定义中使用可变数组长度。您可以做的是:
typedef struct Grid {
unsigned width, height;
void* cell_internal; //Type: Cell(*)[height]
} Grid;
#define cell(myGrid) ((Cell(*)[(myGrid).height])(myGrid).cell_internal)
//in the constructor of Grid
newGrid->width = ...;
newGrid->height = ...;
cell(*newGrid) = malloc(newGrid->width*sizeof(*cell(*newGrid)));
for(unsigned x = 0; x < newGrid->width; x++) {
for(unsigned y = 0; y < newGrid->height; y++) {
cell(*newGrid)[x][y] = ...;
}
}
这种方法的缺点是,您需要在处理单元格数据的每个函数中为cell\u internal
指针显式创建别名指针
Cell (*cells)[myGrid->height] = myGrid->cell_internal;
这可能是更好的方法,因为它似乎对更多的人来说是可读的。使用灵活的数组。使用两个malloc()就很简单了
调用,如果您想要突破对齐限制或严格别名的限制,或者想要编写代码强制用于存储单元格
结构的malloc()
'd部分对齐,则可以只调用一个
typedef struct Grid {
unsigned width;
unsigned height;
Cell *cell[];
} Grid;
Grid *initGrid(unsigned width, unsigned height )
{
// the Grid structure itself
size_t bytesNeeded = sizeof( Grid );
// space for pointers
bytesNeeded += height * sizeof( Cell * );
Grid *g = malloc( bytesNeeded );
g->width = width;
g->height = height;
// get all the data needed with one malloc call
g->cell[ 0 ] = malloc( width * height * sizeof( Cell ) );
// fill in the pointers
for ( unsigned ii = 1; ii < height; ii++ )
{
g->cell[ ii ] = g->cell[ 0 ] + ii * width;
}
return g;
}
void freeGrid( Grid *g )
{
free( g->cell[ 0 ] );
free( g );
}
在这一出色的职位之后:
阅读@JensGustedt post并关注他的链接
实际上有一种方法——我按照他的帖子写了一个小测试程序来验证:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char ** argv)
{
unsigned int height = 100;
unsigned int width = 10;
int (*array)[width] = malloc (sizeof(int[height][width]));
array[90][2] = 1231;
printf("%d", array[90][2]);
}
我承认这令人惊讶-我不知道这存在
编辑-使用结构:
#include <stdio.h>
#include <stdlib.h>
typedef struct Cell {
int data;
// stuff to be added later
} Cell;
typedef struct Grid {
unsigned width;
unsigned height;
Cell *cell;
} Grid;
Grid initGrid(unsigned width, unsigned height) {
Grid g;
g.width = width;
g.height = height;
g.cell = malloc( sizeof(Cell[height][width]) );
return g;
}
int main(int argc, char ** argv)
{
unsigned int height;
unsigned int width;
int i,j;
Grid test;
printf("enter width: ");
scanf("%d", &width);
printf("enter height: ");
scanf("%d", &height);
test = initGrid (width, height);
Cell (*array)[width] = test.cell;
for (i = 0; i < height; i++ )
for (j = 0; j < width; j++ )
array[i][j].data = i;
for (i = 0; i < height; i++ ) {
for (j = 0; j < width; j++ )
printf("%d ", array[i][j].data);
printf("\n");
}
}
有一个铸造警告,我没有时间来解决,但一个人可以实现这个想法-只需干净地做…再次它是一个POC而不是一个实际的程序不,你不能在C中有如此强大的VLA。这是一个遗憾。如果你不知道任何一个维度,只需替换Cell[][]
byCell*Cell;
并使用指针算法。在C语言中,对于一维数组的特殊使用,二维数组只不过是语法上的糖分而已。您需要使用指向指针的指针,并至少调用一次malloc()
,以模拟多维数组的行为。或者使用动态分配的一维数组,大小为width*height
,使用(比如)cell[i+height*j]
而不是cell[i][j]
访问元素。忽略所有告诉您使用某种指针解决方案和额外的malloc调用的人-他们还不了解问题所在。这些数据不会像灵活的数组成员那样相邻分配。谢谢。我需要malloc
单元格数组吗?如果需要,我必须在结束时释放它吗de>main
?无法表示一行中的元素数在结构中是动态的。可以在C中完成,在结构之外,有多种方法可以与结构结合使用。@EricPostChil否,没有任何方法可以表示二维数组索引在没有显式中间体的情况下工作指针数组(“锯齿数组”)。#include
,#include
,intmain(intargc,char*argv[]){intr=atoi(argv[1]),C=atoi(argv[2]);inta[R];for(intr=0;R
使用Apple LLVM 9.0.0 clang-900.0.39.2编译和运行,使用C 2011中指定的可变长度数组。@EricPostChil A right,good point,VLA可以是2D,但当然不能存在于结构中。感谢您的澄清。这不是动态的。您的程序可以工作,因为宽度在编译时已知。@bfontaine感谢您的帮助他回答说,但至少在这种情况下你是错的…看我的编辑…现在用Cell(*array)[width]=test.cell;
。并启用所有编译器警告。首先,我提到了警告,我认为这是不可解决的-但在某些情况下可以使用它。其次,如果没有强制转换,则无法完成此操作,但可读性的附加好处可能会抵消警告。我不会在代码中使用此解决方案,但很高兴知道我不存在这与灵活数组成员有什么关系?我看不出这是如何回答这个问题的。
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char ** argv)
{
unsigned int height = 100;
unsigned int width = 10;
int (*array)[width] = malloc (sizeof(int[height][width]));
array[90][2] = 1231;
printf("%d", array[90][2]);
}
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char ** argv)
{
unsigned int height;
unsigned int width;
int i,j;
printf("enter width: ");
scanf("%d", &width);
printf("enter height: ");
scanf("%d", &height);
int (*array)[width] = malloc (sizeof(int[height][width]));
for (i = 0; i < height; i++ )
for (j = 0; j < width; j++ )
array[i][j] = i;
for (i = 0; i < height; i++ ) {
for (j = 0; j < width; j++ )
printf("%d ", array[i][j]);
printf("\n");
}
}
enter width: 10
enter height: 6
0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2 2
3 3 3 3 3 3 3 3 3 3
4 4 4 4 4 4 4 4 4 4
5 5 5 5 5 5 5 5 5 5
#include <stdio.h>
#include <stdlib.h>
typedef struct Cell {
int data;
// stuff to be added later
} Cell;
typedef struct Grid {
unsigned width;
unsigned height;
Cell *cell;
} Grid;
Grid initGrid(unsigned width, unsigned height) {
Grid g;
g.width = width;
g.height = height;
g.cell = malloc( sizeof(Cell[height][width]) );
return g;
}
int main(int argc, char ** argv)
{
unsigned int height;
unsigned int width;
int i,j;
Grid test;
printf("enter width: ");
scanf("%d", &width);
printf("enter height: ");
scanf("%d", &height);
test = initGrid (width, height);
Cell (*array)[width] = test.cell;
for (i = 0; i < height; i++ )
for (j = 0; j < width; j++ )
array[i][j].data = i;
for (i = 0; i < height; i++ ) {
for (j = 0; j < width; j++ )
printf("%d ", array[i][j].data);
printf("\n");
}
}
enter width: 20
enter height: 10
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8
9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9