54731


c言語のポインタの配列の受け渡しの勉強をしていて、疑問に思った点があります。  
以下のプログラムは、参考書の内容をそのまま貼りつけたものです。  
main関数最後の方の`print(p, 3);`ですが、なぜ`print(*p, 3)`ではないのかわかりません。  
int p[3]と定義したら、print(p, 3)で渡して(int x[], int no)で受け取るのは分かるのですが、類推したら、  
int *p[3]と定義したら、print(*p, 3)で渡すことにはならないのでしょうか？

[code]

    /*
        ポインタの配列の受渡し
    */
    
    #include  <stdio.h>
    
    /*--- ポインタの配列の値を表示 ---*/
    void print(int *x[], int no)
    {
        int  i;
    
        for (i = 0; i < no; i++)
            printf("x[%d]＝%p  *x[%d]＝%d\n", i ,x[i], i, *x[i]);
    }
    
    int main(void)
    {
        int  a = 5, b = 3, c = 7;
        int  *p[3];
    
        p[0] = &a;  p[1] = &b;  p[2] = &c;
        printf("&a＝%p  a＝%d\n", &a, a);
        printf("&b＝%p  b＝%d\n", &b, b);
        printf("&c＝%p  c＝%d\n", &c, c);
    
        print(p, 3);
    
        return (0);
    }
    
    
[/code]

実行例

[code]

    wn-003% ./a.out
    &a＝0x7fffd19cccd4  a＝5
    &b＝0x7fffd19cccd8  b＝3
    &c＝0x7fffd19cccdc  c＝7
    x[0]＝0x7fffd19cccd4  *x[0]＝5
    x[1]＝0x7fffd19cccd8  *x[1]＝3
    x[2]＝0x7fffd19cccdc  *x[2]＝7
    
[/code]

ちなみにprint(*p, 3)とすると、以下のエラーが出ます。

[code]

    junk1.c:22:8: warning: passing argument 1 of ‘print’ from incompatible pointer type [-Wincompatible-pointer-types]
      print(*p, 3);
            ^
    junk1.c:4:6: note: expected ‘int **’ but argument is of type ‘int *’
     void print(int *x[], int no)
    
[/code]


CC BY-SA 4.0
2019-05-05T02:41:07.467
54728
2019-05-05T04:49:08.513
2019-05-05T02:53:14.363
32582
32582
question
c array ポインタ
ポインタの配列の受け渡し

[code]

    int  *p[3];
    
[/code]

と宣言していますから、pはintへのポインターの配列です。

そして、このpを引数につかう関数 print の呼び出しは次のようになっています。

[code]

    print(p, 3);
    
[/code]

そしてprint関数は、以下のように定義されています。

[code]

    void print(int *x[], int no){
        int  i;
        for (i = 0; i < no; i++)
            printf("x[%d]＝%p  *x[%d]＝%d\n", i ,x[i], i, *x[i]);
    }
    
[/code]

第一引数 x はintへのポインターの配列だと宣言されていますよね。  
だから、print関数を呼び出す時の第一引数の型はintへのポインターの配列じゃないとダメなんです。


CC BY-SA 4.0
2019-05-05T03:25:49.170
54730
2019-05-05T03:25:49.170
217
54728
answer


`typedef int *intp;`と型定義してみるとコードを解釈しやすくなるでしょうか？
また、式`p`は配列の先頭を表す`&p[0]`と同じ意味です。

[code]

    typedef int *intp;
    
    void print(intp x[], int no)
    {
        int  i;
    
        for (i = 0; i < no; i++)
            printf("x[%d]＝%p  *x[%d]＝%d\n", i ,x[i], i, *x[i]);
    }
    
    int main(void)
    {
        int  a = 5, b = 3, c = 7;
        intp p[3];
    
        p[0] = &a;  p[1] = &b;  p[2] = &c;
        printf("&a＝%p  a＝%d\n", &a, a);
        printf("&b＝%p  b＝%d\n", &b, b);
        printf("&c＝%p  c＝%d\n", &c, c);
    
        print(&p[0], 3);
    
        return (0);
    }
    
[/code]

元のソースコードを見たときに、上記コードが頭に描けるようになれば理解が進むと思います。


CC BY-SA 4.0
2019-05-05T03:39:55.710
54731
2019-05-05T03:39:55.710
4236
54728
answer


C言語ではポインタに関係して`*`を使う場面が2つありますが、それぞれで意味が異なります。

> `int *p[3];`

で使われている`*`はポインタ型であることを意味しています。  
定義した`p`は以降 **特別な表現をしなければ常に`int`型のポインタの配列です。**

> `p[0] = &a; p[1] = &b; p[2] = &c;`

では、上記のように代入した後に例えば`*p[0] = 6;`とする場合の`*`はどういう意味なのか。  
こういう場合の`*`は`p[0]`に代入されているアドレスの中身であることを意味します。  
現在`p[0]`には`&a`、`int`型の変数`a`のアドレスが代入されています。従って、例示した`*p[0] = 6;`は`a =
6;`と言い換えることができます。

>
[code]

>     void print(int *x[], int no)
>     {
>     (中略)
>     print(p, 3);
>     (後略)
>  
[/code]

結論として、関数`print`の最初の引数は`int`型のポインタの配列なので`p`で良いということになります。


CC BY-SA 4.0
2019-05-05T04:49:08.513
54733
2019-05-05T04:49:08.513
25936
54728
answer