何const char** x
が何で、どのように使用するかについての簡単な説明を理解したり見つけたりするのに苦労していますか?
char* x[]
それがcharポインターの配列であることは理解しています。
私が見つけた の説明の 1 つchar** x
は、「それらは変数ポインタの配列への変数ポインタであるconst chars
」というものです。
私は混乱しています。ポインターの配列ですかx
、それともポインターの配列を指す 1 つのポインターですか?
何const char** x
が何で、どのように使用するかについての簡単な説明を理解したり見つけたりするのに苦労していますか?
char* x[]
それがcharポインターの配列であることは理解しています。
私が見つけた の説明の 1 つchar** x
は、「それらは変数ポインタの配列への変数ポインタであるconst chars
」というものです。
私は混乱しています。ポインターの配列ですかx
、それともポインターの配列を指す 1 つのポインターですか?
私が書いたならT *x
、あなたはそれを理解すると思いますか? x
型のオブジェクトへの単なるポインタT
です。そして、そのオブジェクトはの配列の最初の要素である可能性がありT
ます。一方T x[10]
、実際には 10 の配列ですT
。
あなたの場合、T
ですconst char *
。x
へのポインタも同様ですconst char *
。
使用するすべての型について*
、その型へのポインタです。1 つの要素またはメモリ上の一連の要素の最初の要素 (最初に割り当てたとき) を指す場合があります。ポインターを使用すると、たとえばポインター演算x++
を使用して次の要素に移動できます。また、インデックス演算子を使用することもできますx[1]
。ポインター演算は const ポインターに適用できません。定数であると宣言したので、魔女は明らかです。
使用するすべてのタイプ[]
は配列です。配列では、ポインター演算を使用できません[]
。配列の要素にアクセスできるのは、演算子だけです。
const ポインターは、要素へのアクセスに関しては配列に似ていると言えます。
コンパイル時に必要なサイズがわかっている場合は、配列を使用します。これらはスタックに常駐します。
実行時にメモリを割り当てる必要がある場合、またはポインター演算を使用する必要がある場合は、ポインターを使用します。実行時に割り当てられるメモリはヒープ上にあります。
ここで、理解を深めるのに役立つかもしれない講義を行います。
間違いがなかったらいいのですが、最後に C を使ってからしばらく経ちました :/
一例を次に示します。
char ch;
char *pch = &ch;
char **ppch = &pch;
この場合、配列は関与しません。
文字 ( ) を保持する変数が 1 つありますch
。
次に、ポインター ( ) を保持する 1 つの変数がありますpch
。これは、データを保持するメモリ内の場所のアドレスです。ただし、コンパイラとプログラマは、その場所に格納されている値の型にも関心があります (たとえば、値が何バイトかかるか、その値に対してどの操作が許可されているかを知るため)。したがって、ポインターには、それが指している値の型に関連する型があります。この場合、pch
は文字値を指しているため、型はchar *
です。
そして、ポインター ( ppch
) を保持する別の変数があります。これもメモリ内の場所のアドレスですが、今回はその場所に格納されている値はポインタです。したがって、2 つのポインターが関与し、ppch
それが指しているポインターがあります。どちらのポインターにも型があります。ppch
-は、char **
char へのポインターへのポインターです。それが指している値はchar *
、文字へのポインターです。
ポインターは単一の値を指すことができますが、場合によっては、同じ型 (配列) の値のシーケンスがある場合にも役立ちます。その場合、ポインターはシーケンス内の任意の値を指すことができ、ポインター演算を使用して、同じシーケンス内の他の値を指すように変更できます。
文字を指すことができるポインターと同じようchar *
に、一連の文字の任意の値を指すこともできます。多くの場合、シーケンスの最初の値を指すと便利です。
char **
値を指しchar *
ます。この値も、単一の値または一連の値の 1 つ (より具体的には、シーケンスの最初の値) です。
char *array[]
これは、実際のポインターのシーケンスと同じではありません。違いは重要です。
char *pointers[5];
char **pp;
ここでchar *pointers[5]
は、5 つのポインターの配列です。実際の配列です。sizeof(pointers)
1 つのポインターの 5 倍のサイズです。
しかし、これpp
は単なるポインターです。これは、単一のポインターを保持する変数であり、単一のポインターsizeof(pp)
のサイズです。これはポインターへのポインターであるため、 の最初の要素pointers
(またはchar *
の他の要素を含む他の値) を指すこともできpointers
ます。
あとは の質問だけですconst
。これは、表示される型にのみ影響します (C では異なる順序が許可const char
され、 と同じであるため、これは少し混乱しますchar const
)。非constconst char **pp
ポインター (ポインターが変更できることを意味する) から非 const ポインター (ポインターも変更できること) から const char (文字の値を で変更できないことを意味する) も同様pp
です。
したがって、pp
それ自体はプログラムによって変更できます-異なるポインターを指すことができます。指しているポインターも変更できます。別の文字を指している可能性があります。ただし、 を使用して文字自体を変更することはできませんpp
。
合理的な例として、いくつかのconst char
ポインターと、ポイントするためのいくつかの文字が必要です。それらを取得する最も簡単な方法は、配列を使用することです。
char seq1[5] = { 'a', 'b', 'c', 'd', 'e' };
char seq2[3] = { 'x', 'y', 'z' };
const char *p1;
const char *p2;
const char **pp;
p1 = &seq1[0]; /* valid, same as p1 = seq1 */
p1 = &seq1[3]; /* valid */
*p1 = 's'; /* invalid - the character that p1 points to cannot be changed by p1 */
p2 = seq2; /* valid */
pp = &p1; /* valid */
*pp = &seq1[2]; /* valid - pp is a non-const pointer, so the value it points to can change */
pp = &p2; /* valid - pp itself is non-const */
**pp = 't'; /* invalid - same as *(*pp) which is *p2 which is const when accessed by pp */
の意味はconst
、値が変更できないということではなく、const 変数 (または const ポインター) によって変更できないことに注意してください。次の例は、明確にする必要があります。
char ch;
char *pch = &ch;
const char *cpch = &ch;
ch = 'a'; /* fine - ch is not const */
*pch = 'b'; /* fine - pch does not point to a const value */
*cpch = 'c'; /* invalid - cpch points to a const value */
[]
これは主に配列を宣言するためのショートカットであり、実際には型ではありません。配列の要素を宣言するとき、またはその配列が持つ「スロット」の数を指定するときに使用されます。
しかし、C は配列全体を単一のものであるかのように処理しないため、その操作から得られる結果の変数は、char *
その配列の最初の要素を指すポインターであるため、char x[]
とchar *x
が同じ型であることが多少暗示されます。
char x[] = "string";
たとえば、が配列の最初の要素を指すx
型の変数であると宣言する場合、その値はです。char *
x[0]
's'
この概念を行列または配列の配列に再適用できます。これは、ポインターのコレクションへのポインターと同じです。
whilechar *x
は文字列の場合もあれば、文字列char **x
のリストの場合もあります。