2

以前の質問(Jonathan Lefflerに感謝します)のように、コード(2番目の2ブロックのコード)を編集しましたが、かなり奇妙な問題が発生しました。

次のものは予期せず壊れます...

void free_array(array_info *A)
{
    int i;
    for(i = 0; i < (A->height); ++i)
    {
        printf("About to free: %x\n", A->dat_ptr[i]);//for debugging purposes
        free(A->dat_ptr[i]);
        printf("Freed row %i\n", i);//for debugging purposes
    }
    free(A->dat_ptr);
}

私は最初にcreate_array直接テストした後free_array、かなり大きなアレイ(10 ^ 8)で問題なく動作しました。ただし、その間に計算を行ってからfree()配列を試してみると、アクセス違反の例外(c00000005)が発生します。デバッグしているときに、「free_array」ループ内にブレークポイントがあり、すべての行を個別に実行すると、プログラムが毎回完全に実行されることに気付きました。ただし、コンパイルされたコードは、それ自体では2番目の配列のrow6を超えて実行されることはありません。コンパイラですべての最適化をオフにしましたが、実行時にエラーが発生しました。

追加情報

typedef struct {
    int    height;
    int    width;
    int    bottom;//position of the bottom tube/slice boundary
    unsigned int**  dat_ptr;//a pointer to a 2d array
    } array_info;

ここで、dat_ptrは適切な2Dポインタになります。create_array構造体に配置される配列を作成する関数は次のとおりです(読みやすさのためにNULLチェックを削除しました)。

int create_array(array_info *A)
{
int i;
unsigned int **array = malloc(sizeof(*array) * A->height);

for (i = 0; i < A->height; ++i)
{
    array[i] = malloc(sizeof(**array) * A->width);
}

A->dat_ptr = array;
return 0;
}

この関数は期待どおりに機能します。

詳細追加情報

ジョナサン、クリス、ラリソンの回答の後に追加33

ジョナサン、ありがとうございました。あなたの投稿のすべてで、プログラミングについて多くのことを知りました:)ついに犯人を見つけました。例外の原因となったコードは次のとおりです。

void fill_number(array_info* array,  int value,  int x1,  int y1,  int x2,  int y2)//fills a rectangular part of the array with `value`
    {
    int i, j;
    for(i=y1 ; ((i<=y2)&&(i<array->height)) ; i++)//start seeding the values by row (as in vertically)
    {
        for(j=x1 ; ((i<=x2)&&(i<array->width)) ; j++)//seed the values by columns (as in horizontally)
        {
        array->dat_ptr[i][j]=value;
        }
    }
}

そして((i<=x2)&&(i<=array->width))、私が期待したように評価されていませんでした(クリス・ドッド、あなたは正しかったです)。両方の条件をその順序で評価するか、順序に関係なくどちらかが「FALSE」の場合は停止すると思いました。(i<array->width)しかし、それはそのようには機能せず、部品を正しく評価することを単に拒否していたことが判明しました。また、配列範囲外のメモリにアクセスしようとすると例外が発生すると思いましたが、発生しませんでした。ともかく、

コードを次のように変更しました。

void fill_number(array_info* array,  int value,  int x1,  int y1,
                                                    int x2,  int y2)
{
    int i, j;
    if(y1>=array->height){ y1=array->height-1;}
    if(y2>=array->height){ y1=array->height-1;}
    if(x1>=array->width) { x2=array->width-1;}
    if(x2>=array->width) { x2=array->width-1;}
    for(i=y1 ; i<=y2 ; i++)//start seeding the values by row
    {
        for(j=x1 ; j<=x2 ; j++)//seed the values by column
        {
        array->dat_ptr[i][j]=value;
        }
    }
}

そして今、それは機能します。sのブロックはif()、他のコードと比較して関数を頻繁に呼び出さないためにあり、チェックがそこにあることを視覚的に思い出させる方法が必要です。

繰り返しになりますが、ジョナサン・レフラー、クリス・ドッド、そしてラリソンに感謝します33 :)

4

2 に答える 2

2

このコードは、あなたが私から得たものとあなたが上で書いたものに密接に基づいており、期待どおりに機能しているようです。<inttypes.h>and PRIXPTR(およびキャストto )の使用に注意してください(uintptr_t)。ポインターのサイズについての仮定を回避し、32ビットシステムと64ビットシステムで同等に機能します(ただし、%.832ビットコンパイルで完全な8桁の16進値を取得し、12(最大16のうち)この特定の64ビットプラットフォームで)。

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

typedef struct
{
    int    height;
    int    width;
    int    bottom;
    unsigned int **dat_ptr;  // Double pointer, not triple pointer
} array_info;

static void create_array(array_info *A)
{
    unsigned int **array = malloc(sizeof(*array) * A->height);
    printf("array (%zu) = 0x%.8" PRIXPTR "\n",
           sizeof(*array) * A->height, (uintptr_t)array);
    for (int i = 0; i < A->height; ++i)
    {
        array[i] = malloc(sizeof(**array) * A->width);
        printf("array[%d] (%zu) = 0x%.8" PRIXPTR "\n",
               i, sizeof(**array) * A->width, (uintptr_t)array[i]);
    }
    A->dat_ptr = array;
}

static void free_array(array_info *A)
{
    int i;
    for(i = 0; i < (A->height); ++i)
    {
        printf("About to free %d: 0x%.8" PRIXPTR "\n",
               i, (uintptr_t)A->dat_ptr[i]);
        free(A->dat_ptr[i]);
    }
    printf("About to free: 0x%.8" PRIXPTR "\n", (uintptr_t)A->dat_ptr);
    free(A->dat_ptr);
}

int main(void)
{
    array_info array = { .height = 5, .width = 10, .dat_ptr = 0 };
    create_array(&array);
    if (array.dat_ptr == 0)
    {
        fprintf(stderr, "Out of memory\n");
        exit(1);
    }
    free_array(&array);
    puts("OK");
    return(0);
}

サンプル出力

array (40) = 0x7FAFB3C03980
array[0] (40) = 0x7FAFB3C039B0
array[1] (40) = 0x7FAFB3C039E0
array[2] (40) = 0x7FAFB3C03A10
array[3] (40) = 0x7FAFB3C03A40
array[4] (40) = 0x7FAFB3C03A70
About to free 0: 0x7FAFB3C039B0
About to free 1: 0x7FAFB3C039E0
About to free 2: 0x7FAFB3C03A10
About to free 3: 0x7FAFB3C03A40
About to free 4: 0x7FAFB3C03A70
About to free: 0x7FAFB3C03980
OK

私はvalgrindこのマシンに乗ったことがありませんが、割り当てられて解放されているアドレスを目で見て、そこに明らかな問題がないことを示すことができます。アレイのサイズがすべて40バイトになるようにサイズ設定したのは偶然です(64ビットマシンの場合)。

フォローアップの質問

  • データで他に何をしていますか?
  • 割り当てているアレイの大きさはどれくらいですか?
  • 算術オーバーフローが発生していないことを確認しますか?

Mac OSX10.8.2およびXCodeバージョンのGCC/Clangでのテスト:

i686-apple-darwin11-llvm-gcc-4.2(GCC)4.2.1(Apple Inc.ビルド5658に基づく)(LLVMビルド2336.11.00)


アレイ設定および印刷機能

static void init_array(array_info *A)
{
    unsigned int ctr = 0;
    printf("D       = 0x%.8" PRIXPTR "\n", (uintptr_t)A->dat_ptr);
    for (int i = 0; i < A->height; i++)
    {
        printf("D[%d]    = 0x%.8" PRIXPTR "\n",i, (uintptr_t)A->dat_ptr[i]);
        for (int j = 0; j < A->width; j++)
        {
            printf("D[%d][%d] = 0x%.8" PRIXPTR " (%u)\n",
                   i, j, (uintptr_t)&A->dat_ptr[i][j], ctr);
            A->dat_ptr[i][j] = ctr;
            ctr += 7;
        }
    }
}

static void print_array(array_info *A)
{
    printf("D       = 0x%.8" PRIXPTR "\n", (uintptr_t)A->dat_ptr);
    for (int i = 0; i < A->height; i++)
    {
        printf("D[%d]    = 0x%.8" PRIXPTR "\n",i, (uintptr_t)A->dat_ptr[i]);
        for (int j = 0; j < A->width; j++)
        {
            printf("D[%d][%d] = 0x%.8" PRIXPTR " (%u)\n",
                   i, j, (uintptr_t)&A->dat_ptr[i][j], A->dat_ptr[i][j]);
        }
    }
}

成功した後の呼び出しとinit_array(&array);その後の呼び出しで、期待どおりの出力が得られました。ここに表示するには退屈すぎます。main()create_array()print_array(&array);

于 2012-11-05T04:05:33.610 に答える
2

私はあなたが間違ってmallocしていると信じています。create_array関数を次のように変更してみてください。

int create_array(array_info *A)
{
  int i;
  unsigned int **array = malloc(sizeof(unsigned int*) * A->height);

  for (i = 0; i < A->height; ++i)
  {
    array[i] = malloc(sizeof(unsigned int) * A->width);
  }

  A->dat_ptr = array;
  return 0;
}
于 2012-11-05T03:29:22.963 に答える