ご存知のように、配列名を割り当てることはできません。次のような文です。
char * array[], * point;
array = point; /* wrong */
array++; /* wrong */
しかし、main(int argc, char * argv[])
では、argv++
問題なく、うまく機能します。何が欠けていますか?
あなたの例array
では真の配列であるため、変更できない左辺値です。main では、パラメーター リストで宣言されているため、argv
実際にはchar **
、つまり変更可能なポインターです。
要するにchar *array[]
、文脈によって意味が異なるということです。
関数パラメーター宣言のコンテキストでは、T a[]
とは両方とも;T a[N]
として解釈されます。T *a
3 つのケースすべてで、 の配列ではなく、へのポインタa
として宣言されます。したがって、 inは、へのポインタの配列ではなく、 、または へのポインタへのポインタとして実際に宣言されます。 T
T
int main(int argc, char *argv[])
argv
char **
char
char
(編集-- これは、関数パラメーター宣言の場合にのみ当てはまることに注意してください。通常の変数宣言の場合T a[N]
、T a[]
両方ともa
の配列として宣言しT
ます)。
ポインタ値なので代入、インクリメントが可能です。
それを超えて、言語標準が言わなければならないことは次のとおりです。
5.1.2.2.1 プログラムの起動
... 2 それらが宣言されている場合、メイン関数の パラメーター
は次の制約に従うものとします
。プログラムの起動と終了の間。argc
argv
argv
編集
関数パラメーターの言語は次のとおりです。
6.7.6.3 関数宣言子 (プロトタイプを含む)
... 7 ''型
の配列'' としてのパラメータの宣言は、''型への修飾ポインタ'' に調整され ます。キーワードが配列型派生のand内にも現れる場合、関数の呼び出しごとに、対応する実引数の値によって、少なくともサイズで指定された数の要素を持つ配列の最初の要素へのアクセスが提供されます。表現。[
]
static
[
]
編集2
いくつかの例 (C99 コンパイラを想定):
void foo(int a[], size_t len)
{
size_t i;
printf("sizeof a = %zu\n", sizeof a);
printf("sizeof (int *) = %zu\n", sizeof (int *));
for (i = 0; i < len; i++)
printf("a[%zu] = %d\n", i, *a++);
}
int main(void)
{
int a1[5] = {0};
int a2[] = {0, 1, 2, 3, 4};
printf("sizeof a1 = %zu\n", sizeof a1);
printf("sizeof a2 = %zu\n", sizeof a2);
foo(a1, sizeof a1 / sizeof a1[0]);
foo(a2, sizeof a2 / sizeof a2[0]);
return 0;
}
標準語のもう 1 つの部分:
6.3.2.1 左辺値、配列、および関数指定子
... 3演算子、演算子、または単項演算子
のオペランドであるか、配列の初期化に使用される文字列リテラルである場合を除き、 ''型の配列'' 型を持つ式は式に変換されます配列オブジェクトの最初の要素を指し、左辺値ではない型「型へのポインター」を使用します。配列オブジェクトにレジスタ ストレージ クラスがある場合、動作は未定義です。sizeof
_Alignof
&
関数main
では、a1
とa2
の 5 要素配列として宣言されていますint
。a2
イニシャライザの要素数からサイズを取得します。したがって、これらの式 は「の 5 要素配列」の型を持ち、代入式のターゲットにすることも、or演算子のオペランドにすることもできません。これらの式が への呼び出しに現れると、それらの型は上記のルールに従って「へのポインタ」に変換されます。したがって、配列値ではなくポインター値を受け取ります(これは、配列パラメーターがポインター型に変換されるという規則によってカバーされます)。したがって、の式には type 、またはへのポインターがありますa1
a2
int
++
--
foo
int
foo
a
a
foo
int *
int
; したがって、a
は代入のターゲットである可能性があり、 および のオペランドである可能性が++
あり--
ます。
もう 1 つの違い: 上記の規則に従って、配列式が演算子のオペランドである場合、ポインター型への変換は行われませんsizeof
。sizeof a1
配列が占めるバイト数a1
(5 * sizeof int
) に評価される必要があります。ただし、a
infoo
は typeであるため、int *
notは(sizeof )へのポインターのバイト数にのみ評価する必要があります。 int [5]
sizeof a
int
(int *)
main(int argc, char * argv[])
また
main(int argc, char **argv)
同じで正しいです。関数の引数配列では、ポインターに減衰するためです
詳細については、これを読んでください
しかし、あなたが示したコードは実際の配列です。配列の名前は最初の要素のアドレスを示し、変更できないため、これを実行します。
array = point;
array++;
あなたがすでに述べたように間違っています。