web-dev-qa-db-ja.com

Mallocコンパイルエラー: "int"型の値を使用して、int型(*)[30]のエンティティを初期化することはできません

これまでに20通りの方法を試したに違いありません。どうしてもこのようなエラーが発生します。

a value of type "int" cannot be used to initialize an entity of type "int (*)[30]"

つまり、このようなエラーが発生します

int(*array)[160] = malloc((sizeof *array) * 10);

そして、このようなことをしています

int** Make2DintArray(int arraySizeX, int arraySizeY) {
    int** theArray;
    theArray = (int**) malloc(arraySizeX*sizeof(int*));
    int i;
    for (i = 0; i < arraySizeX; i++)
    {
        theArray[i] = (int*) malloc(arraySizeY*sizeof(int));
    }
    return theArray;
}

これを手に入れます

"void *(size_t)" in "memory.c" at line 239 and: "int()" 

int [160] [10]の2dArrayを正常に割り当てる方法の解決策はありますか

13
WIllJBD

これらはどちらも問題なくコンパイルできます。最初のエラーは、同じことを宣言した関数(malloc(size_t)など)を使用する前に_#include <stdlib.h>_を忘れたときによく起こりますしないすることを忘れないでください。

Cには興味深いコンパイル時の動作がいくつかあります。その中には、これまでにない機能(プロトタイプ定義nor実装)を呼び出す機能があります。そのような呼び出しに遭遇すると、Cは関数が次のとおりであると想定します。

  • intを返すもの
  • 不明な数の引数をとるので、呼び出し側は何でも(間違ったものも含めて)渡すことができます。

たとえば、関数は暗黙的に次の形式であると想定されます。

_int func();
_

多くの場合、気付かないこともあります。コンパイラからの警告を保存して、次のような影響を報告します。

_Warning: implicit declaration of `func` assumed to return `int`
_

そして、あなたがオンザボールの場合は、警告レベルをエラーとしての警告を有効にして、これをキャッチします。

しかし、そうでない場合はどうなりますか?そして、関数から返された「もの」が、実装のデータサイズによってコンテンツで表現できない場合はどうでしょうint?たとえば、intが32ビットで、データポインターが64ビットの場合はどうなりますか?たとえば、char *get_str()を含まないヘッダーファイルで宣言され、コンパイルしてプログラムとリンクする.cファイルに実装されていると仮定します。 、これは次のようになります。

_#include <stdio.h>

// Note: NO prototype for get_str
int main()
{
    char *s = get_str();
    printf("String: %s\n", s);
    return 0;
}
_

まあ、コンパイラは吐き出して、intと_char*_は互換性がないことを通知します(警告の直後に_get_str_はintを返すと想定されます)。しかし、コンパイラにtellingさせて、何らかの方法で_char*_を作成するとどうなるでしょうか。

_#include <stdio.h>

// Note: NO prototype for get_str
int main()
{
    char *s = (char*)get_str(); // NOTE: added cast
    printf("String: %s\n", s);
    return 0;
}    
_

これで、エラーとしての警告を有効にしないと、暗黙の宣言警告が表示されます。コードがコンパイルされます。しかし、それはrunでしょうか? sizeof(int)!= sizeof(char*)の場合、(32ビットと64ビット)はそうではない可能性があります。 _get_str_から返される値は64ビットポインターですが、callerは32ビットのみが返されると想定し、それを64ビットポインターに強制します。要するに、キャストはエラーを隠し、未定義の動作のPandoraの箱を開きました。


では、これらすべてがコードとどのように関連しているのでしょうか。 _<stdlib.h>_を含めないことにより、コンパイラはmallocが何であるかを認識しません。したがって、次の形式であると想定しています。

_int malloc();
_

次に、結果を_(int**)_にキャストすることで、コンパイラーに「これから出てくるものはすべて_int**_にする」と伝えます。リンク時に、__malloc_が見つかり(C++のような名前のマ​​ングリングによるパラメーターシグネチャはありません)、配線され、プログラムをパーティする準備が整います。しかし、プラットフォームではintとデータポインターは同じサイズではないので、いくつかの望ましくない結果が生じます。

  • キャストは実際のエラーを隠します。
  • 偽のポインタは、realが返すポインタの半分のビットから製造されます。
  • 傷への残酷な塩分として、割り当てられたメモリがリークされます。それを参照する有効なポインタがどこにもないためです(半分だけを保持することによって、1つだけを破壊しました)。
  • おそらくmost望ましくない、コードは実装wheresizeof(int) == sizeof(int**)でコンパイルされた場合、通常の動作を示します。

したがって、これを32ビットDebianボックスでビルドすると、すべてが問題なく見えます。 64ビットMacでビルドする教授に宿題を提出すると、クラッシュし、課題に失敗し、授業に失敗し、大学を中退し、次の10年間は​​、母親の地下室でサインフェルドが再走するのを見ながら猫とふれあいます。何が悪かったのかしら。痛い。

キャスティングを銀の弾丸のように扱わないでください。そうではありません。 Cでは、必要なfar人々がそれを使用するよりも少ない頻度で使用され、間違った場所で使用された場合、致命的なエラーを隠すことができます。コードでハードキャストなしにコンパイルできない箇所を見つけた場合は、もう一度見てください。あなたが絶対に、確かにキャストが正しいことだと確信していない限り、オッズはその間違っています

この場合、mallocが実際に何をしているのかを知るためにコンパイラーに十分な情報を提供することを怠っていたという本当のエラーを隠しました。

12
WhozCraig

これを試して:

int **array;
array = malloc(rows * sizeof(int *));
for (i = 0; i < rows; i++)
  array[i] = malloc(cols * sizeof(int));

// Some testing
for (i = 0; i < rows; i++) {
  for (j = 0; j < cols; j++)
    array[i][j] = 0; // or whatever you want
}

for (i = 0; i < rows; i++) {
  for (j = 0; j < cols; j++)
    printf("%d ", array[i][j]);
}

あなたの場合、rows = 160とcols = 10です。

このアプローチでは、2つのインデックスを使用できます。

17
rendon

配列を割り当てるには:

int *array = malloc(sizeof(int) * 160 * 10);

次に、次のようなコードを使用します。

array[10 * row + column] = value;

rowは0から159までで、columnは0から9までです。)

5
David Schwartz

私はレンドンの答えについてメモがあります:

彼のコードでは、Visual C++はすべての「=」操作に対して次のように言っています:error C2440: '=' : cannot convert from 'void *' to 'int **'

いくつかの変更を加えることで、私にとってはうまくいきますが、同じように機能するかどうかはわかりません。そのため、彼のコードを編集することを恐れています。代わりに、ここに私のコードを示します。これは第一印象で機能するようです。

int **a;    

a = (int **)malloc(rows * sizeof(int));

for (i = 0; i < rows; i++)
{
    a[i] = (int *)malloc(cols * sizeof(int));
}

for (j=0;j<rows;j++)
{
    for (i=0;i<cols;i++)
    {
        a[i][j] = 2;
    }
}

実際、私はstructsの代わりにカスタムintを使用してそれを行いましたが、どちらの方法でも機能すると思います。

0
Zoltán Schmidt

気にしないで、callocを使用した例を追加します

void allocate_fudging_array(int R, int C)
{
    int **fudging_array = (int **) calloc(R, sizeof(int *));
    for(int k = 0; k < R; k++)
    {
        fudging_array[k] = (int*) calloc(C, sizeof(int));
    }
}


// a helper function to print the array 
void print2darr(int **arr, int R, int C)
{
    for(int i = 0; i < R; i++)
    {
        for(int j = 0; j < C; j++)
        {
            printf(" %d  ", arr[i][j]);
        }
        printf("\n");
    }
}
0
Reno