1. 質問する
#include <stdio.h>
int main()
{
char array[16] = {
'A', 'B'};
char (*parray)[16] = &array;
printf("========================\n");
printf(" array: \t%#lx\n", array);
printf("& array: \t%#lx\n", &array);
printf("&* array: \t%#lx\n", &*array);
printf("*& array: \t%#lx\n", *&array);
printf(" parray: \t%#lx\n", parray);
printf("* parray: \t%#lx\n", *parray);
printf("*& parray: \t%#lx\n", *&parray);
printf("&* parray: \t%#lx\n", &*parray);
printf("========================\n");
return 0;
}
上記のプログラムの array &array &*array *&array parray *parray *&parray &*parray の出力は同じです。テスト コンピューターではすべて0x61ff10です(下図を参照)。理由は何ですか? 以下は段階的な分析であり、結論は記事の最後にあります。
2. 解決策
最初のグループ: array は &array と同じ値を持ちます
#include <stdio.h>
int main()
{
char array[16] = {
'A', 'B'};
char (*parray)[16] = &array;
printf(" array: \t%#lx\n", array); // 输出 0x61ff10
printf("& array: \t%#lx\n", &array); // 输出 0x61ff10
printf("数组array的第二元素的地址: \t%#lx\n", array+1); // 输出 0x61ff11
printf("数组array的下一数组的地址: \t%#lx\n", &array+1); // 输出 0x61ff20
printf("数组array的第二元素的地址: \t%c\n", *(array+1)); // 输出字符 B
printf("数组array的下一数组的地址: \t%c\n", *(&array+1));// 输出为空
printf(" array: \t%d\n", sizeof(array)); // 输出 16,整个数组array的大小也为16,即array代表整个数组
printf(" array: \t%d\n", sizeof(&array)); // 输出 4,则 &array 应为指针变量
printf(" array: \t%d\n", sizeof(array+1)); // 输出 4,因为 array+1 时,array 隐式转换为指针变量了
return 0;
}
array
これは長さ 16 の配列の名前であり、配列オブジェクトとして理解できます。array+1 の場合、配列の最初の要素のアドレスに暗黙的に変換されます。&array
これは長さ 4 のポインタ変数で、配列全体のアドレスを示しますが、値は配列の最初の要素のアドレスと等しくなります。
値は同じですが、中身は異なります。上記のコードでは、array + 1 は配列の 2 番目の要素のアドレスを示し、&array + 1は配列全体の「次の配列」を示します。つまり、配列の末尾にある次のアドレスを指します。配列。
注: このマシンでテストするときのコンパイラは 32 ビットであるため、ポインタ変数の長さは 4 1です。
2 番目のグループ: &*array および *&array
#include <stdio.h>
int main()
{
char array[16] = {
'A', 'B'};
char (*parray)[16] = &array;
printf("&* array: \t%#lx\n", &*array); // 输出 0x61ff10
printf("*& array: \t%#lx\n", *&array); // 输出 0x61ff10
printf("&* array: \t%d\n", sizeof(&*array)); // 输出 4,数组首元素的地址
printf("*& array: \t%d\n", sizeof(*&array)); // 输出 16,*&array 等价为 array
printf("*&*array: \t%c\n", *&*array); // 输出 A
printf("**&array: \t%c\n", **&array); // 输出 A
return 0;
}
&*array
長さ 4 のポインタ変数です。array は配列の名前、*array は配列の最初の要素であるため、&*array は配列の最初の要素のアドレス、長さは 4、型はポインター変数です。*&array
長さ 16 の配列です。&array は配列全体を指すポインター変数です。配列全体を指すポインタ&array を一度逆参照し、配列全体のオブジェクトを取得します。
一方、* と & は相互演算子であり、表面上は互いに打ち消し合っていると理解できます。ただし、sizeof(&*array) の値は 4、つまり &*array はポインタ変数、sizeof(*&array) は 16、つまり *&array は array と同等であることに注意してください。配列オブジェクト。
3 番目のグループ: parray と *parray
#include <stdio.h>
int main()
{
char array[16] = {
'A', 'B'};
char (*parray)[16] = &array;
printf(" parray: \t%#lx\n", parray); // 输出 0x61ff10
printf("* parray: \t%#lx\n", *parray); // 输出 0x61ff10
printf(" parray: \t%#lx\n", parray+1); // 输出 0x61ff20,则 parray 指向整个数组
printf("* parray: \t%#lx\n", *parray+1); // 输出 0x61ff11,则*parray 指向数组首个元素
printf("**parray: \t%c\n", **parray); // 输出 A
printf(" parray: \t%d\n", sizeof(parray)); // 输出 4
printf(" parray: \t%d\n", sizeof(*parray)); // 输出 16
return 0;
}
parray
これは、長さ 4 の char int (*)[16] 型のポインター変数です。宣言からわかるように、ポインタは &array と同等です。つまり、配列オブジェクトの配列を指します。*parray
ポインタ変数 parray が一度逆参照されること、つまり配列 array のオブジェクトが取得されることを示し、その長さは配列名 array と同等の 16 です。たとえば、(*parray)[ の値0] と array[0] は両方とも a です。そして、 *array は、配列名の暗黙的な変換後、配列の最初の要素として表現されるため、再度逆参照された場合、つまり **parray は配列 array: A の最初の要素を意味します。
4 番目のグループ: *&parray と &*parray
#include <stdio.h>
int main()
{
char array[16] = {
'A', 'B'};
char (*parray)[16] = &array;
printf("*&parray: \t%#lx\n", parray); // 输出 0x61ff10
printf("*&parray: \t%#lx\n", *&parray); // 输出 0x61ff10
printf("&*parray: \t%#lx\n", &*parray); // 输出 0x61ff10
printf("*&parray: \t%d\n", sizeof(*&parray)); // 输出 4
printf("&*parray: \t%d\n", sizeof(&*parray)); // 输出 4
printf("*&parray的下一单元: %#lx\n", *&parray+1); // 输出 0x61ff20
printf("&*parray的下一单元: %#lx\n", &*parray+1); // 输出 0x61ff20
return 0;
}
このグループでは話すことは何もありません。*& offset として理解してください。コード内の parray は 0x61ff10 ですが、*&parray+1 と &*parray+1 は両方とも 0x61ff20 であることに注意してください。これは、parray が配列全体を指しており、その関数が &array と同等であることを再度証明しています。
3. 結論
char array[16] = {
'A', 'B'};
char (*parray)[16] = &array;
上記のコードではarray
配列の名前ですが、配列のオブジェクトとして理解しましょう。配列に対して演算を行うと「暗黙の変換」が発生します。sizeof(array) を介すると、その長さは 16、つまり配列の長さになります。したがって、配列は本質的にポインタであるべきではありませんが、配列 + 1 などの演算を実行すると、配列は暗黙的に配列の最初の要素を指すポインタ変数に変換され、配列 + 1 は配列の 2 番目の要素を指します。配列。&array
これは配列全体を指すポインタ変数を意味し、その型は int (*)[16] で、&array + 1 は配列 array 全体に広がり、次の "array" (存在する場合) を指します。これは、変数宣言が&array と同等であり、配列の名前であり配列オブジェクトを表す *&array (つまり、配列) と同等であることが
わかります。操作を実行するとき、*parray は配列と同様に暗黙的に変換されます。parray
*parray
次の抜粋は、書籍「C++ Primer Plus」2の 213 ページからの抜粋です。
補助延長
#include <stdio.h>
int main()
{
char array[16] = {
'A', 'B'};
char (*parray)[16] = &array;
printf(" array: \t%c\n", (&array[0])[0]); // 输出 A
printf(" array: \t%c\n", (&array[0])[1]); // 输出 B
printf(" array: \t%c\n", (&array[1])[0]); // 输出 B
printf(" array: \t%c\n", (&array[1])[1]); // 输出 空
return 0;
}
#include <stdio.h>
int main()
{
char array[16] = {
'A', 'B'};
char (*parray)[16] = &array;
printf(" parray: \t%#lx\n", parray); // 输出 0x61ff10
printf("* parray: \t%#lx\n", *parray); // 输出 0x61ff10
printf(" parray: \t%c\n", parray[0][0]); // 输出 A
printf(" parray: \t%c\n", parray[0][1]); // 输出 B
// printf(" parray: \t%c\n", parray[1][0]); // 输出 空
// printf(" parray: \t%c\n", parray[1][1]); // 输出 乱码
printf(" parray: \t%c\n", *parray [0]); // 输出 A
printf(" parray: \t%c\n", (*parray)[1]); // 输出 B
printf(" parray: \t%c\n", **parray ); // 输出 A
printf(" parray: \t%c\n", **parray+1); // 输出 B
return 0;
}
上記の問題と解決策はテスト結果に基づいていますが、私の知識が乏しいため、本文中の間違いをご指摘ください。
参考リンク
[1] C 言語のポインタ変数は何バイトを占めますか[ ?な場合に暗黙の変換は
]2