【问题标题】:seg fault from 2d array allocation二维数组分配的段错误
【发布时间】:2013-02-12 06:45:51
【问题描述】:

我有一个结构“单元格”定义为

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;  
}  

起初我认为这工作正常,但后来出现了一些段错误,我发现使用某些值(例如 makeCellGrid(32, 87) )它会中断。 我对 C 指针和内存垃圾相当新鲜,希望有人能在这里为我指明正确的方向。

使用较低的数字界限我可以毫无问题地访问它

map[i][j].id = x;

等等

编辑:忘记添加,从测试中,段错误源自

theArray[i] = (cell*) malloc(sizeY*sizeof(cell)); 

【问题讨论】:

  • 这段代码看起来不错。您确定不会意外交换 X 和 Y 索引吗?
  • ij的值是多少?
  • 您是否在可以使用valgrind 的Linux 等系统上?如果是这样,请使用它。您显示的代码显然不是问题所在。因此,这可能与您如何使用代码返回的数据有关。
  • (1) Take out the casts on your malloc() calls. (2) 确保包含&lt;stdlib.h&gt;。如果您遇到的第一个malloc()'ed 地址取消引用在您的编辑评论中看起来像这样,您可能没有存储完整的指针,这比您隐藏隐含的malloc() 函数声明时更常见像这样的演员。
  • @alk 可能,但函数名称另有说明。它只是游戏中使用的某种地图。此外,使用单个内存块可能会提高代码速度,因为大部分地图总是会加载到缓存中,这对于碎片内存是不可能的

标签: c pointers malloc


【解决方案1】:

代码缺少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;  
} 

关于我的修改的注释:

  • 始终检查系统调用是否有错误(在 malloc() 的情况下返回错误 NULL
  • 最好使用unsigned 类型来访问内存/数组索引; size_t 就是为此而生的
  • 在 C 中,不需要转换 void * 函数返回的值,如 malloc()
  • 始终尝试尽快初始化变量;未初始化的变量很容易导致应用程序的“非理性”行为
  • 如果使用指针,将间接级别“编码”到它们的名称中可能会有所帮助(我在这里使用前缀 pp 表示这是一个 2 级间接)
  • 类型与变量不同:区分这一点的一种方法是使用大写字母 (CellType) 开头类型名称和使用小写字母 (ppCells) 开头的变量。
  • 如果将内存分配给指针,并且分配的内存大小与指针的类型匹配很重要,那么使用(取消引用的)指针本身作为sizeof 运算符的参数总是比使用某种类型更安全。由于分配内存的指针的声明可能会在开发过程中发生更改,并且将忘记将参数调整为malloc()。简而言之:像我做的那样做更不容易出错。
  • 如果封装结构(包括数组)的动态创建,也可以实现一个解除分配的方法(这里:freeCellGrid())。最好先编写此释放器,然后在编写分配器的错误处理时手动编写(如第二次调用 malloc() 所示)。

【讨论】:

  • 谢谢。非常棒的帖子,有很多有用的信息。
猜你喜欢
  • 2021-10-11
  • 1970-01-01
  • 2015-11-11
  • 2013-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-07
相关资源
最近更新 更多