3

プログラムに小さなメモリ アクセスの問題があり、エラーが見つかりません。誰かが助けてくれるかもしれません。

RGB カラー値を格納する新しい型を作成しました。そのタイプは次のようになります。

typedef struct pixel {
    unsigned char r;
    unsigned char g;
    unsigned char b;
} pixel;

私のメイン プログラムでは、calloc を使用して 2D 動的配列を作成し、赤色の情報を格納します。

pixel **pixelvalue = (pixel **) calloc(imginformation.width, sizeof(pixel));
for (i = 0; i < imginformation.width; i++) {
    pixelvalue[i] = (pixel *) calloc(imginformation.height, sizeof(pixel));
}

その後、色の値を読み取り、それらを配列に保存する関数を呼び出します。この関数は、配列をパラメーターとして取得します。

ReadFile(file, imginformation (Stuff like height and so one), pixelvalue (The calloc array));

その関数では、値を書き込もうとします

pixelvalue[i][j].r = (unsigned char)fgetc(in);

ここでメモリアクセスエラーが発生します。何が間違っていましたか?

編集

こんにちは、まず言語が抜けていて申し訳ありません。昨日は少し疲れていました :)。

理解するために、ピクセルの配列を作成しましたが、要素は別のピクセルの配列を指していますか? みたいな[Point to another 1D array pixel]

ピクセルを使用して、タイプピクセルから多数のポインター**pixelvalue = calloc(imginformation.width, sizeof(pixel *));を作成し、各ポインターをピクセルに表示しますよね?imginformation.width

もし間違っていたら、もう少し詳しく説明していただけると助かります。私は本当にそれを理解したいです。

@ carl-norum とはどういう意味ですか:

「calloc() の戻り値をキャストするべきではありません。そうすることで、#include を使用してバグを隠すことができます。バグが戻ってきて、後で噛み付く可能性があります」.

? 戻り値としてではなく、関数のパラメーターとして割り当て領域を使用します。

ご協力いただきありがとうございます!

グリーツ

4

4 に答える 4

3

実際には 2D 配列を作成しているのではなく、ピクセルの配列を指すポインターの配列を作成しています。つまり、最初のcalloc呼び出しでは、ピクセルではなくポインターに十分なスペースを割り当てる必要があります。

pixel **pixelvalue = calloc(imginformation.width, sizeof(pixel *));

質問に言語のタグを付けませんでしたが、それが C であると仮定すると (C++ では必要ない に基づいてtypedef)、 の戻り値をキャストするべきではありませんcalloc()。そうすることで#include、戻ってきてあなたを噛む可能性のあるバグを隠すことができます.

編集:

あなたはいくつかのフォローアップの質問をしました。最初のものは、他のいくつかの回答によってかなりよく回答されていると思いますが、要約しようと思います。割り当てを行う方法では、最初にポインターの配列を割り当てます。これらのポインターのそれぞれは、配列の 1 つの行を指します。次に、行自体を割り当てる必要があります。各pixelオブジェクトのスペースがそこに移動し、行へのポインターがポインターの最初の配列に格納されます。

2 番目の質問ですが、からの戻り値calloc()は非常に簡単です。戻り値をキャストすると、暗黙の宣言のバグを自分で隠すことができます。の戻り値の型はcallocisvoid *であるため、次のようにすると:

my_ptr = calloc(1, 2);

すべてがうまく機能します。を含めなかったので、翻訳単位にstdlib.hのプロトタイプがなかったとします。calloc()これにより、コンパイラは の署名が であると想定するcalloc()ようになりますがint calloc(int, int)、これは正しくありません。上記の同じコード行は、その関数のデフォルトの署名を想定することについての警告をスローします。コードにあるようなタイプキャストを使用すると、その警告がマスクされ、その#include行が欠落していることに気付かない可能性があります。

于 2012-02-03T00:13:11.083 に答える
1

説明については、図を参照してくださいここに画像の説明を入力

したがって、最初にpixel *calloc を使用して配列を作成します。callocwithを使用してその配列にデータを入力しpixelます。

于 2012-02-03T09:12:46.807 に答える
0

コード

pixel **pixelvalue = (pixel **) calloc(imginformation.width, sizeof(pixel)); 

pixelvalueピクセルへのポインタへのポインタ - あなたのtypedefです。

あなたは書く必要があります

pixel **pixelvalue = calloc(imginformation.width, sizeof(pixel *)); 

代わりは。

于 2012-02-03T08:33:16.683 に答える
0

pixel*他の投稿者は、メモリの最初のブロックを の単位ではなく の単位で割り当てる必要があることを正しく認識していますpixel

しかし、なぜこの問題が segfault を引き起こすのでしょうか?

32 ビット マシンでは、上で定義したピクセル構造体は 3 バイトを使用しますが、ポインターは 32 ビット (4 バイト) を使用します。

あれは、

  • sizeof(pixel) == 3
  • しかしsizeof(pixel*) == 4

したがって、必要なメモリの 75% しか割り当てていません。画像の下 4 分の 1 にアクセスすると、割り当てられていないメモリにアクセスすることになります。

(一部の 64 ビット プラットフォームでは、問題は確実に悪化するだけです。一部の 16 ビット プラットフォームでは、これでうまくいくかもしれませんが、それでもずさんです)

于 2012-02-03T09:27:24.407 に答える