web-dev-qa-db-ja.com

Cのconst配列

元の質問:私が定義すると:

const int z[5] = {10, 11, 12, 13, 14}; 

それはどういう意味ですか?

  1. これは整数の定数配列です。つまり、zが指すアドレスは常に定数であり、決して変更できませんが、zの要素は変更できます。

OR

  1. Zの各要素は定数です。つまり、それらの値は決して変更できません。

編集:

より詳しい情報:

別の変数があります:

const int *y = z;
func((int *) y);

ここで、funcは次のように定義されています。

void func(int y[]) {
    int i;
    for(i = 0; i < 5; i++) {
        y[i] = i; //y[i] can be set to any integer; used i as example
    }
}

funcでは、yを使用して配列が走査され、各要素が変更されます。 zのすべての要素がconstであっても、これは有効ですか?

14
sandeeps

これは、zの各要素が読み取り専用であることを意味します。

オブジェクトzは、ポインターオブジェクトではなく配列オブジェクトです。それは何も指し示していない。他のオブジェクトと同様に、zのアドレスはその存続期間中は変化しません。

objectzは配列なので、expressionzは、すべてではないがほとんどのコンテキストで、z[0]を指すポインター式に暗黙的に変換されます。配列オブジェクトz全体のアドレスと同様に、そのアドレスはオブジェクトの存続期間中は変化しません。この「変換」は、式の意味に対するコンパイル時の調整であり、実行時の型変換ではありません。

配列とポインターの(しばしば混乱する)関係を理解するには、 comp.lang.c FAQ のセクション6を読んでください。

「定数」とconstは2つの異なるものであることを理解することが重要です。何かがconstantの場合、コンパイル時に評価されます。たとえば、42および(2+2)定数式です。

オブジェクトがconstキーワードで定義されている場合、それは読み取り専用であり、定数である必要はありません。これは、オブジェクトを名前で変更することはできず、他の方法で(たとえば、アドレスを取得して非constポインターにキャストすることによって)変更しようとすると、未定義の動作が発生することを意味します。たとえば、次のことに注意してください。

const int r = Rand();

有効です。 rは読み取り専用ですが、その値は実行時まで判別できません。

19
Keith Thompson

あなたの場合の答えは:

  1. Zの各要素は定数です。つまり、それらの値は変更できません。

配列はオブジェクトであり、実行時にのみ作成でき、constエンティティはコンパイル時に解決されるため、const配列を作成することはできません。

したがって、constは、以下の最初の例のように解釈されます。つまり、配列の要素に適用されます。つまり、以下は同等です。 あなたの例の配列は初期化する必要があります。

 int const z[5] = { /*initial (and only) values*/};
 const int z[5] = { /*-//-*/ };

constの例では、int指定子と型指定子の型 可換プロパティ です。

以下は、定数の使用法を明確にするためのいくつかの例です。

1.定数整数の定義:(再割り当てできません)。以下の2つの式では、constの使用は同等です。

int const a = 3;  // after type identifier
const int b = 4;  // equivalent to before type qualifier

2.定数ポインターの定義(ポインター演算や再割り当てはできません):

int * const p = &anInteger;  // non-constant data, constant pointer

定数intへのポインター定義(ポイントされた整数の値は変更できませんが、ポインターは変更できます):

const int *p = &anInteger;  // constant data, non-constant pointer
3
Ziezi