91375


ポインタの配列について学習していたところ、よくわからない結果となりました。  
どなたかご教示いただけますと幸いです。

ポインタの配列の学習のため、以下コードを作成していました。

[code]

    #include <stdio.h>
    static char *symbol0[] = { "I", "W", "E" } ;
    
    int main ( void )
    {
        char *symbol1[3] ;
    
        symbol1[0] = "I" ;
        symbol1[1] = "W" ;
        symbol1[2] = "E" ;  
    
        printf( " symbol0 ( %%p )   : %p\n", symbol0 ) ;
        printf( " symbol1 ( %%p )   : %p\n", symbol1 ) ;
        printf( " *symbol0      %%s : %s\n", *symbol0 ) ;
        printf( " *symbol0[0]   %%c : %c\n", *symbol0[0] ) ;
        printf( " *symbol0      %%p : %p\n", *symbol0 ) ;
        printf( " *symbol1      %%s : %s\n", *symbol1 ) ;
        printf( " *symbol1[0]   %%c : %c\n", *symbol1[0] ) ;
        printf( " *symbol1      %%p : %p\n", *symbol1 ) ;
    
        return 0 ;
    }
    
[/code]

gcc でコンパイル後にプログラムを実行したところ、以下のような出力となりました。

[code]

    出力例
     symbol0 ( %p )   : 0x55c47cc02010
     symbol1 ( %p )   : 0x7ffd368c6780
     *symbol0      %s : I
     *symbol0[0]   %c : I
     *symbol0      %p : 0x55c47ca00b28
     *symbol1      %s : I
     *symbol1[0]   %c : I
     *symbol1      %p : 0x55c47ca00b28
    
[/code]

出力された結果について、私の疑問は全部で3つです。

#### 1つ目

`printf( " *symbol0 %%p : %p\n", *symbol0 )` と `printf( " *symbol1 %%p :
%p\n", *symbol1 )` が同じ値を出力するのはなぜか？

`symbol0[0]` と `symbol1[1]` には同じ文字列である "I"
が格納されているため、格納されている値をポインタとして出力したためかと考えました。  
しかし、別プログラムを実行したのちに再度このプログラムを実行すると、前度出力時の結果と再度出力時の結果に差異がありました。  
そのため、この出力はポインタ値を返していると思ったのですが、仮にポインタ値を返していると考えた場合、2つのポインタが同じ値を返すのはおかしい、と判断しています。  
なぜ同じ値が出力されるのか、ご教示ください。

#### 2つ目

`printf( " *symbol0 %%p : %p\n", *symbol0 )` と `printf( " *symbol1 %%p :
%p\n", *symbol1 )` で出力される値は、何を意味しているのか？

ここで出力されている値は何でしょうか？（ポインタ値でしょうか？変数の値でしょうか？）

#### 3つ目

`printf("%p",*symbol0) , printf("%p", *symbol1)` は、そもそも出力が期待できる関数か？

`symbol0`, `symbol1`
ともにポインタの配列として定義しているため、コンパイルでエラーが出ず、実行後になんらかの値が出力されることは個人的には期待していた結果でした。  
ただし、`*symbol0` と `*symbol1` で異なる値が出力されることを期待していたため、同じ値が出力されたのは期待した結果とはことなりました。  
そのため、本来はコンパイル時にエラーになるはずの内容が、なんらかの理由によりコンパイルを通ってしまった可能性もあるのかな、と考えています。  
2つの printf 関数は本来出力が期待できる関数であるのか、ご教示ください。

よろしくお願いいたします。


CC BY-SA 4.0
2022-09-29T12:11:32.373
91374
2022-09-30T02:57:28.177
2022-09-30T02:57:28.177
3060
54619
question
c ポインタ
printf( "%p", *ポインタの配列) で出力される結果は何を意味するのか


① 文字列リテラルについては同じ内容のものを統合するような最適化が言語仕様上は許されています。
どのように配置されるかは処理系に任されており、統合されることもされないこともあります。  
② ポインタです。 `char *symbol1[3];` という宣言は `char*` がみっつという意味であり、配列の要素はポインタです。  
③ 問題ありません。 仕様通りの結果です。

ポインタと配列まわりの事情に関しては

  * 配列の型は配列型
  * 式中に配列型が現れた場合には配列の先頭要素を指すポインタに暗黙に型変換される
  * ただし `sizeof` や単項 `&` のオペランドは暗黙に型変換されない

というルールで勝手に型変換されるのがややこしさの根源だと考えられています。

つまり、たとえば質問中にあるような `"I"` という文字列リテラルの型は `char[2]` (ヌル終端を含むので文字数よりひとつ多い)
ですが、この文字列はプログラムの最初から最後まで存在するどこかの領域にあって、暗黙の型変換ルールによって式の値としては `char*` 型が返されるのです。

`*symbol0` という式の場合、まず `symbol0` の型は `char*[3]` ですが上述の型変換ルールによって `char**` となり、
`*` 演算子を適用することで `char*` になります。 `*symbol0` の型は `char*` です。


CC BY-SA 4.0
2022-09-29T12:24:52.180
91375
2022-09-29T13:11:45.460
2022-09-29T13:11:45.460
3364
3364
91374
answer