web-dev-qa-db-ja.com

Cの動的配列— mallocとreallocの理解は正しいですか?

私はCで動的な1D配列を作成する方法を学んでいます。以下のコードは次のことを試みます。

  1. mallocを使用して、タイプdoubleの値を保持する長さ10の動的配列を作成します。
  2. j/100の場合、配列の各エントリをj = 0, 1,..., 9に設定します。次に、印刷します。
  3. reallocを使用して、配列の最後に追加の空のエントリを追加します。
  4. 新しいエントリをj/100に設定し、各エントリを再度印刷します。

テスト:

 double* data = (double*)malloc(10*sizeof(double));

 for (j=0;j<10;j++)
 {
      data[j]= ((double)j)/100;
      printf("%g, ",data[j]);
 }

 printf("\n");

 data = (double*)realloc(data,11*sizeof(double));

 for (j=0;j<11;j++)
 {
     if (j == 10){ data[j]= ((double)j)/100; }
     printf("%g, ",data[j]);
 }

 free((void*) data);

質問

  1. 私はこれを正しくコーディングしていますか?

  2. 私が見つけたチュートリアルでは、(double*)を前に置かずにmallocを使用しています。例えば。、

    int * pointer;
    pointer = malloc(2 * sizeof(int));

これは、Visual Studio 2010、Windows 7ではコンパイルされません。エラーメッセージは

void型の値は、int型のエンティティに割り当てることはできません。

私ではなく、なぜそれらのチュートリアルで機能するのですか?私の例では、使用しているコンパイラが(int*)を自動的に埋めているためだと推測できますか?

28
Legendre

あなたは近いです。

Cでは(少なくとも1989年の標準バージョン以降)、mallocおよびreallocの前のキャストは不要です。Cは、型なしでvoid *型の値をint *に変換できるためです。これはnot trueであるため、発生しているエラーに基づいて、このコードをCではなくC++としてコンパイルしているように聞こえます。VS2010のドキュメントを参照して、コードのコンパイル方法を確認してくださいCとして.

以下は、malloc呼び出しを記述するための私の好みのスタイルです。

double *data = malloc(10 * sizeof *data);

*dataの型はdoubleであるため、sizeof *datasizeof (double)と同等です。これは、mallocのタイプが変更された場合、data呼び出しを調整する必要がないことも意味します。

realloc呼び出しに関しては、結果を一時ポインター値に割り当てる方が安全です。 reallocは、バッファーを拡張できない場合にNULLを返すため、記述する方が安全です。

double *tmp;
...
tmp = realloc(data, 11 * sizeof *data);
if (!tmp)
{
  // could not resize data; handle as appropriate
}
else
{
  data = tmp;
  // process extended buffer
}

MicrosoftのCのサポートは、1989年版の言語で終了することに注意してください。それ以来、言語標準の2つの改訂版があり、いくつかの新しい機能が導入され、古い機能が廃止されました。そのため、一部のCコンパイラは、宣言とコードの混合、可変長配列などのC99機能をサポートしますが、VS2010はサポートしません。

34
John Bode

1)これを正しくコーディングしていますか?

主に。ただし、reallocが失敗した場合、data = (double*)realloc(data,11*sizeof(double));は割り当てられたメモリへの参照を失います。一時ポインタを使用してreallocの戻り値を保持し、NULL(およびmallocの戻り値も確認する必要があります)。

2)私が見つけたチュートリアルでは、(double *)を前に置かずにmallocを使用しています。

Cでは、mallocvoid*を返しますが、これは暗黙的に他のポインター型に変換できるため、キャストは必要ありません(キャストによってエラーが隠される可能性があるため、広く推奨されません)。 Visual Studioは、キャストが必要なC++としてコードを明らかにコンパイルします。

12
Daniel Fischer

Cでは、malloc()の戻り値をキャストしないでください。

また、malloc()引数で型をエンコードすることはお勧めできません。これはより良い方法です:

double* data = malloc(10 * sizeof *data);
5
unwind