54

C の配列は、順次格納されたデータへの単なるポインターであることを知っています。しかし、[] と * の表記の違いにはどのような違いがあるのでしょうか。私はすべての可能な使用状況を意味します。例えば:

char c[] = "test";

関数本体でこの命令を提供すると、スタックに文字列が割り当てられます

char* c = "test";

データ (読み取り専用) セグメントを指します。

明確な全体像を形成するために、すべての使用状況におけるこれら 2 つの表記法の違いをすべて挙げていただけますか。

4

5 に答える 5

34

C99 標準によると、次のようになります。

配列型は、要素型と呼ばれる特定のメンバー オブジェクト型を持つ連続して割り当てられた空でないオブジェクトのセットを記述します。

  1. 配列型は、要素の型と配列内の要素の数によって特徴付けられます。配列型はその要素型から派生したと言われ、その要素型がの場合、配列型は の配列Tと呼ばれることがあります。要素型から配列型を構築することを配列型派生と呼びます。T

ポインター型は、関数型、オブジェクト型、または参照型と呼ばれる不完全な型から派生する場合があります。ポインタ型は、参照される型のエンティティへの参照を提供する値を持つオブジェクトを記述します。参照される型から派生したポインター型は、 へのポインターT と呼ばれることがあります。参照される型からポインター型を構築することを、ポインター型の派生と呼びます。T

標準宣言によると…</p>

char s[] = "abc", t[3] = "abc";
char s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' };

...同一です。配列の内容は変更可能です。一方、宣言は…</p>

const char *p = "abc";

…型を定数へのポインタcharとして p を定義し、要素が文字列リテラルで初期化される長さ 4の型定数配列char( C++ では) を持つオブジェクトを指すように初期化します。を使用pして配列の内容を変更しようとした場合の動作は未定義です。

6.3.2.1によると、配列添字の逆参照と配列添字は同一です。

添字演算子の定義[]E1[E2]と同じです(*((E1)+(E2)))

配列とポインターの違いは次のとおりです。

  • ポインターには、その背後にあるメモリサイズの情報がありません (それを取得する移植可能な方法はありません)
  • 不完全な型の配列は構築できません
  • ポインター型は不完全な型から派生している可能性があります
  • ポインターは再帰構造を定義できます (これは前の 2 つの結果です)

このテーマに関するさらに役立つ情報は、http://www.cplusplus.com/forum/articles/9/にあります。

于 2012-07-19T08:19:41.120 に答える
11
char c[] = "test";

これにより、文字列テストを含む配列が作成されるため、任意の文字を変更/変更できます。

c[2] = 'p';

しかし、

char * c = "test"

これは文字列リテラルです -- これは const char です。
したがって、この文字列リテラルを変更すると、segfault が発生します。そう

c[2] = 'p';

現在は違法であり、segfault が発生します。

于 2012-07-19T08:33:54.490 に答える
4

char []は「char の境界が不明な配列」char *型を示し、「char へのポインタ」型を示します。ご覧のとおり、「char の境界が不明な配列の配列」型の変数の定義が文字列リテラルで初期化されると、型は「char の配列 [N]」に変換されます。ここで、N は適切なサイズです。一般に、配列集約からの初期化にも同じことが当てはまります。

int arr[] = { 0, 1, 2 };

arr は「array[3] of int」型に変換されます。

ユーザー定義型定義 ( structclassまたはunion) では、C++ ではバインドされていない型の配列は禁止されていますが、C の一部のバージョンでは、割り当てられたアクセスに使用できる構造体の最後のメンバーとして許可されています。構造体の終わりを過ぎたメモリ。この使用法は「柔軟な配列」と呼ばれます。

もう 1 つの違いは、再帰型の構築です。char *(例えばchar **, )へのポインタと配列を構築することはできますがchar (*)[10]、境界が不明な配列に対しては不正です。char []*orを書くことはできませんchar [][10](ただしchar (*)[]andchar [10][]は問題ありません)。

最後に、cv 修飾の動作は異なります。typedef char *ptr_to_charおよびが与えられtypedef char array_of_unknown_bound_of_char[]た場合、ポインター バージョンを cv 修飾すると期待どおりに動作しますが、配列バージョンを cv 修飾すると cv 修飾が要素型に移行されます。つまり、架空の とconst array_of_unknown_bound_of_char同等であり、ではありません。これは、プロトタイプを構築する前に、配列からポインタへの減衰が引数に対して作用する関数定義では、const char []char (const) []

void foo (int const a[]) {
    a = 0;
}

合法です。array-of-unknown-bound パラメーターを変更不可にする方法はありません。

于 2012-07-19T08:20:28.200 に答える
1

ポインター変数を宣言しても変数の型が作成されないことを知っていれば、すべてが明らかになります。ポインター変数を作成します。

したがって、実際には、文字列が必要な場合は、文字の配列を指定する必要があり、ポインターは後で使用できます。

于 2012-07-19T08:21:02.640 に答える
0

実際、配列は定数ポインタと同等です。

また、char c[] は、ベース アドレスが c 自体である配列にメモリを割り当てます。そのアドレスを格納するための別のメモリは割り当てられません。

char *c を書き込むと、ベース アドレスが c に格納されている文字列にメモリが割り当てられます。また、c を格納するために別のメモリ位置が使用されます。

于 2012-07-19T08:11:47.197 に答える