32469


C言語で`文字列`の配列(`文字`の配列 _ではない_ )をchar **に直接代入しようとするとコンパイル時に警告が表示されるのですが、  
charポインタの配列を作り、そこに`文字列`の配列を代入した後で、charポインタをchar **に代入すると警告が表示されません。  
この違いは何が原因なのでしょうか?

[code]

    #include <stdio.h>
    
    int main() {
        char *p_arr[] = {"XXXX", "DDDD"}; // ポインタの配列に文字列の配列を代入
        char **p2; // charポインタのポインタを宣言
        p2 = p_arr; 
        printf("%s\n", p2[0]); // 警告なし
    
        char **p3 = {"XXXX", "DDDD"}; //ポインタのポインタに文字列の配列を直接代入する (警告あり)
        printf("p3[0] = %s\n", p3[0]);
    
    }
    
[/code]

警告の内容:

[code]

    
    p2.c:9:18: warning: incompatible pointer types initializing 'char **' with an expression of type 'char [5]' [-Wincompatible-pointer-types]
        char **p3 = {"XXXX", "DDDD"};
                     ^~~~~~
    p2.c:9:26: warning: excess elements in scalar initializer
        char **p3 = {"XXXX", "DDDD"};
                             ^~~~~~
    
    
[/code]


CC BY-SA 3.0
2017-02-07T12:18:52.327
32461
2017-02-07T15:39:28.270
5246
question
c ポインタ
Cで文字列の配列をchar **に直接代入するとエラーになる理由


`char **p3 = {"XXXX", "DDDD"};`  
ですが、  
`{"XXXX", "DDDD"}` は初期化リストで文字列リテラルの並びです。  
文字列リテラルの型は`const char *`で、  
`char **`の変数を`char *`で初期化しようとしているので  
（一つの変数に初期化しようとする値が２つあるので２つ目の`"DDDD"`は捨てられる、これが余分だと言われている）  
「型が異なる」と怒られています。

`p2 = p_arr;`の場合、  
`p_arr`の型は`char*[2]`（要素が２コのポインタ配列）ですが、ポインタとして評価される時の型は`char**` なので代入出来ます。


CC BY-SA 3.0
2017-02-07T15:22:12.843
32466
2017-02-07T15:27:48.033
2017-02-07T15:27:48.033
5044
5044
32461
answer


**大雑把に言うと・・・**

[code]

    T x = {...};
    
[/code]

という文は配列(や構造体)に対して有効な初期化構文であり、ポインタの初期化には使えません。勝手に右辺を配列化してそのポインタを左辺の初期値とする、という機能はありません。

* * *

**細かく言うと・・・**  
(gccの前提です)

まず2つ目の警告について。

[code]

    p2.c:9:26: warning: excess elements in scalar initializer
        char **p3 = {"XXXX", "DDDD"};
                             ^~~~~~
    
[/code]

これは

[code]

    int a = {1, 2};
    
[/code]

と書いたときにも同様の警告が出ます。つまりスカラー変数に複数の初期値が指定されているという旨の警告です。

なぜこれがエラーにならずに警告なのか、という点については正直よくわかりません。  
Stack Overflowの質問[Excess elements in scalar initializer code compiles with gcc
but not
g++の回答](https://stackoverflow.com/a/25004801/3782011)によれば、歴史的な経緯があるようです。Cコンパイラではこの式の妥当性をコンパイル時に決定できない・・・？

次に1つ目の警告について。

[code]

    p2.c:9:18: warning: incompatible pointer types initializing 'char **' with an expression of type 'char [5]' [-Wincompatible-pointer-types]
        char **p3 = {"XXXX", "DDDD"};
                     ^~~~~~
    
[/code]

スカラー変数に複数の初期値を与えると、最初の値だけが有効と見なされます。  
つまり

[code]

    char **p3 = "XXXX";
    
[/code]

と書いたのと同じことです。  
当然型が不整合なので該当の警告となります。

* * *

**ちなみに**

C99以降では[複合リテラル](http://seclan.dll.jp/c99d/c99d07.htm#dt19991101)を使って

[code]

    char **p3 = (char*[]){"XXXX", "DDDD"};
    
[/code]

のように書くことはできます。


CC BY-SA 3.0
2017-02-07T15:39:28.270
32469
2017-02-07T15:39:28.270
2017-05-23T12:38:56.083
-1
4765
32461
answer