我有一个结构"cell"定义为
typedef struct{
int id;
terrainType terrain;
} cell;
然后我用制作了一个二维细胞阵列
cell** makeCellGrid(int sizeX, int sizeY)
{
cell** theArray;
int i;
theArray = (cell**) malloc(sizeX*sizeof(cell*));
for ( i = 0; i < sizeX; i++)
{
theArray[i] = (cell*) malloc(sizeY*sizeof(cell));
}
return theArray;
}
一开始我认为这很好,但后来出现了一些seg错误,我发现在某些值(例如makeCellGrid(32,87))下它会崩溃。我对C指针和内存垃圾还很熟悉,希望有人能给我指明正确的方向。
有了较低的数字边界,我用访问它没有问题
map[i][j].id = x;
等等
编辑:忘记添加,从测试来看,seg故障源自
theArray[i] = (cell*) malloc(sizeY*sizeof(cell));
代码缺少对malloc()
系统调用的错误检查。
因此,如果对malloc()
的第一次调用失败,第二次调用(在循环中)会尝试将内存分配给NULL
,这确实会导致您正在目睹的分段违规。
你可能会考虑这样修改你的代码:
#include <stdlib.h>
typedef struct {
int id;
TerrainType terrain;
} CellType;
void freeCellGrid(CellType ** ppCells, size_t sizeX)
{
size_t i = 0;
for (; i < sizeX; ++i)
{
free(ppCells[i]);
}
free(ppCells);
}
CellType ** makeCellGrid(size_t sizeX, size_t sizeY)
{
CellType ** ppCells = malloc(sizeX * sizeof(*ppCells));
if (ppCells)
{
size_t i = 0;
for (; i < sizeX; ++i)
{
ppCells[i] = malloc(sizeY * sizeof(**ppCells));
if (NULL == ppCells[i])
{
freeCellGrid(ppCells, i);
ppCells = NULL;
break;
}
}
}
return ppCells;
}
我的修改说明:
- 始终检查系统调用是否存在错误(在返回错误
NULL
的malloc()
的情况下) - 更好地使用
unsigned
类型来访问存储器/阵列标记;size_t
用于此 - 在C中,不需要强制转换
void *
函数(如malloc()
)返回的值 - 始终尝试尽快初始化变量;未初始化的变量很容易导致应用程序的"非理性"行为
- 如果使用指针,将间接级别"编码"到它们的名称中可能会很有帮助(我在这里使用前缀
pp
来表示这是一个2级间接) - 类型不同于变量:区分这一点的一种方法是用大写字母(
CellType
)开始类型名称,用小写字母(ppCells
)开始变量名称 - 如果将内存分配给指针,并且所分配内存的大小适合指针的类型很重要,那么使用(取消引用的)指针本身作为
sizeof
运算符的参数总是比使用某种类型更安全。由于内存分配给的指针的声明可能会在开发过程中发生变化,并且会忘记将参数调整为malloc()
。简而言之:像我那样做不太容易出错 - 如果封装结构(包括阵列)的动态创建,那么还可以实现一种取消分配的方法(此处:
freeCellGrid()
)。更好的做法是,首先对这个deallocator进行编码,因为在对分配器的错误处理进行编码时,您可以手动使用它(如对malloc()
的第二次调用所示)