【C/C++】配列ポインタ:配列アドレス&array *parrayの逆参照 **同じ値で2回parray

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;
}
  1. arrayこれは長さ 16 の配列の名前であり、配列オブジェクトとして理解できます。array+1 の場合、配列の最初の要素のアドレスに暗黙的に変換されます。
  2. &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;
}
  1. &*array長さ 4 のポインタ変数です。array は配列の名前、*array は配列の最初の要素であるため、&*array は配列の最初の要素のアドレス、長さは 4、型はポインター変数です。
  2. *&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;
}
  1. parrayこれは、長さ 4 の char int (*)[16] 型のポインター変数です。宣言からわかるように、ポインタは &array と同等です。つまり、配列オブジェクトの配列を指します。
  2. *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


  1. 2 ↩︎

  2. 4 ↩︎

おすすめ

転載: blog.csdn.net/Alpherkin/article/details/131482910