2

私は次のように定義された構造体「セル」を持っています

typedef struct{
int id;
terrainType terrain;
} cell;

次に、セルの2次元配列を作成します

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)); 
4

1 に答える 1

3

malloc()コードには、システムコールのエラーチェックがありません。

したがって、(ループ内の)2番目の呼び出しが失敗した場合、実際にセグメンテーション違反につながる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これのためのものです
  • void *Cでは、次のような関数によって返される値をキャストする必要はありません。malloc()
  • 常にできるだけ早く変数を初期化するようにしてください。初期化されていない変数は、アプリケーションの「不合理な」動作に非常に簡単につながります
  • ポインターを操作する場合は、間接参照のレベルを名前に「コーディング」すると役立つ場合があります(ここでは、接頭辞を使用してpp、2レベルの間接参照であることを示しています)。
  • タイプは変数とは異なります。これを区別する1つの方法は、大文字(CellType)を使用してタイプ名を開始し、小文字()を使用して変数を開始することppCellsです。
  • ポインタにメモリを割り当てる場合、割り当てられたメモリのサイズがポインタの型に適していることが重要な場合は、(逆参照された)ポインタ自体をsizeof演算子の引数として使用する方が常に安全です。メモリが割り当てられているポインタの宣言は、開発中に変更される可能性があり、引数の調整はmalloc()忘れられます。簡単に言うと、私が行ったように行うと、エラーが発生しにくくなります。
  • 構造体(配列を含む)の動的な作成をカプセル化する場合は、それを割り当て解除するメソッド(ここでは:)も実装することをお勧めしますfreeCellGrid()。アロケータのエラー処理をコーディングするときに手作業で行うので、最初にこのデアロケータをコーディングすることから始めるのがさらに良いでしょう(への2番目の呼び出しで示されているようにmalloc())。
于 2013-02-12T07:20:17.673 に答える