web-dev-qa-db-ja.com

Cでサイズを宣言せずに配列を作成する方法は?

私は新しいCにかなり慣れていないので、これに関連するものを見つけることができませんでした(おそらく、探しているものが本当にわからないためです)。

サイズなしでintとfloat配列を作成しようとしています(0になるか、ユーザーがプログラムを使用している間に増分する可能性があります)。

私は次のことをしようとしていました:

int bills[];

float totalAmount[];

Forループを使用して各配列を印刷しているため、最大サイズを割り当てることができません(99のサイズを割り当てた場合、99行を印刷しますが、それは望ましくありません)。

これは可能だと確信していますが、方法はわかりません。

ありがとう!

5
user8871219

Cは、動的な要素数を持つ配列をサポートしていません。配列の要素の数は、コンパイル時に決定するか、C99を作成時に実行時に評価できるため、決定する必要があります。アレイが作成されると、そのサイズは固定され、変更できません。配列定義または配列宣言のいずれかで_[]_の間でサイズが明示的に指定されない場合がいくつかあります。

define初期化子を提供する場合、左端の次元の明示的なサイズなしで配列を指定できます。コンパイラーは初期化子からサイズを推測します。

_int a[] = { 1, 2, 3 };              // equivalent to int a[3] = { 1, 2, 3 };
int m[][2] = {{ 1, 2 }, { 3, 4 }};  // equivalent to int m[2][2] = {{ 1, 2 }, { 3, 4 }};
char s[] = "Hello world\n";         // equivalent to char s[13] = "Hello world\n";
_

コンパイラーがストリングの場合に暗黙のヌル終了文字を追加する方法に注意してください。

宣言複数の場合の左端の次元のサイズ指定子なしの配列:

  • externクラスストレージを持つグローバル変数として(配列は他の場所で定義されています)、
  • 関数パラメーターとして:int main(int argc, char *argv[])。この場合、左端の次元に指定されたサイズはとにかく無視されます。
  • structの最後のメンバーとして。これは、フレキシブルアレイと呼ばれるC99拡張です。

コンパイラには、これらの配列の実際のサイズに関する情報はありません。プログラマは、他の情報を使用して、別の変数または配列の内容から長さを決定します。

関数の引数の場合、配列はポインターとして渡され、要素の数が指定されていても、sizeof(argv)はポインターのサイズに評価されます。

5
chqrlie

これを達成するには、malloc()(またはcalloc())、realloc()、およびfree()の組み合わせを使用できます。

メモリは、保存する各番号にメモリを再割り当てするのではなく、固定サイズのブロックとして割り当てることができます。

マクロ(または必要に応じてconst)_BLOCK_SIZE_を定義しましょう。

_#define BLOCK_SIZE 10
_

最初に適切なタイプのポインターを宣言し、最初のブロックを割り当てます。

メモリ不足などの理由で何らかのエラーが発生した場合、malloc()realloc()NULLを返すことに注意してください。

_int *ptr=malloc(sizeof(int)*BLOCK_SIZE);    
if(ptr==NULL)
{
    perror("some error");
    return 1;
}
_

次に、現在割り当てられているメモリごとに可能な最大インデックスを格納する変数を宣言します(不正なメモリアクセスを回避するため)。

_int max_index = BLOCK_SIZE-1;
_

ループを使用します。

_for(int i=0; ; ++i)
{
    if(i > max_index)
    {
        ptr=realloc(ptr, (max_index+1 + BLOCK_SIZE)*sizeof(int));
        if(ptr == NULL)
        {
            perror("insufficient memory!");
            break;
        }
        printf("\nRealloced!");
        max_index += BLOCK_SIZE;
    }
    scanf("%d", &ptr[i]);
    printf("\n%d: %d", i, ptr[i]);
}
_

各反復で、iが_max_index_より大きいかどうかを確認します。そうである場合、値を読み取る前にrealloc()を使用して別のブロックが割り当てられます。

使用後は、メモリの割り当てを解除することを忘れないでください。

_free(ptr);
_

また、 this postで説明したように、malloc()realloc()と実質的に同じで、後者の最初の引数NULLを持ちます。

また、投稿したコードでは、calloc()の戻り値を明示的にキャストする必要はありません。返されるのは、暗黙的にターゲットポインター型に変換されるvoidポインターです。

this および this を参照してください。

3
J...S

サイズなしで配列を宣言するのではなく、多数のレコードへのポインターを宣言します。

あなたがやりたいなら

int bills[];

Cでこれを行う適切な方法は

int* bills;

そして、ある時点でサイズを割り当てて、配列を初期化する必要があります。

bills = (int*)malloc(sizeof(int)*items);

他のデータ型の配列についても同様です。実行時まで配列のサイズがわからない場合は、実行時に正しいサイズに割り当てられたメモリへのポインターを使用する必要があります。

1
Edwin Buck