ポインタ

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
大工

ポインタ

#1

投稿記事 by 大工 » 18年前

こんばんわ、大工です。

過去のログを検索しても引っかからなかったので質問します。

配列の引数についてなのですが

func( (*p)[2] )とfunc( p[/url][2] )が同じ扱いになることを本を呼んで学びました.( 最外周の添字は書いても無視され, ポインタの扱いになる. ex: func(*p) func(p[/url]) )しかし, なぜ, 前者が要素を2個もつint配列へのポインタの扱いになっているのは何故なのでしょうか?つまり, 最外周の添字が無視されてポインタの扱いになるのなら. func( p[/url][2] )とfunc( *p[2] ) が同じなんじゃないんですか??

また, func( p[/url][/url] )やfunc( p[2][/url] )はどういった扱いになるのでしょうか???func( **p )と同じになるのでしょうか???

いったいどれがどれと同じ扱いになるのか教えてください。
#include <stdio.h>

//void my_dice(int (*d)[7]);
void my_dice(int d[/url][/url]);

int main(void){

  int dice[7][7];
  int n, cnt;
  int x, y;

  srand(time(NULL));       //乱数の初期化.

  //配列の初期化.
  for(x = 0; x < 7; x++) {

      for(y = 0; y < 7; y++) {

         dice[y][x] = 0;
      }
  }

  printf("試行回数:");
  scanf(" %d", &n);

  for(cnt = 0; cnt < n; cnt++) {

     my_dice(dice);
  }

  return 0;
}
void my_dice(int d[/url][/url]) {
//void my_dice(int (*d)[7]) {

  int x, y;

  x = rand() % 6 + 1;
  y = rand() % 6 + 1;

  d[y][x] += 1;//←ここです

  return;
}
あと, 上記の様なソースでは矢印で示している部分において"invalid use of array with unspecified bounds"とエラーが返ってきます。(コメントアウトした部分でコンパイルするとうまくいきます)これは, 要素数が明確でないのが原因なのでしょうが, コメントアウトした部分でも不明確な部分(最外周の部分です)があるのになぜコンパイルできてしまうのでしょうか???

ご協力お願いします。

box

Re:ポインタ

#2

投稿記事 by box » 18年前

> func( p[/url][2] )とfunc( *p[2] ) が同じなんじゃないんですか??

演算子の優先順位の関係で、
func((*p)[2])
と、*pの前後にカッコが必要です。

> また, func( p[/url][/url] )やfunc( p[2][/url] )はどういった扱いになるのでしょうか???func( **p )と同じになるのでしょうか???

第2次元以降の要素数を書いていないため、
コンパイルできないはずです。

たかぎ

Re:ポインタ

#3

投稿記事 by たかぎ » 18年前

> 演算子の優先順位の関係で、

型名を構成する括弧類は演算子ではありません。

大工

Re:ポインタ

#4

投稿記事 by 大工 » 18年前

box様>

func( p[2][/url] )でもコンパイルはできました。。。

box

Re:ポインタ

#5

投稿記事 by box » 18年前

>たかぎ様

> 型名を構成する括弧類は演算子ではありません。

これは大変失礼いたしました。
素人の浅はかさで、ボロが出てしまいました。

*p[2]と書くと*(p[2])と解釈するため、
「配列へのポインタ」として書くには
(*p)[2]と書かねばならない、と
言いたかったのでありました。


>大工様

> func( p[2][/url] )でもコンパイルはできました。。。

たまたま、各々のコンパイラが違う動きをしただけだったのですね。

大工

Re:ポインタ

#6

投稿記事 by 大工 » 18年前

補足です。

>func( p[/url][2] )とfunc( *p[2] ) が同じなんじゃないんですか??



最外周がポインタに読み替えられるなら配列へのポインタ( (*P)[2] )ではなくポインタ配列( *p[2] )になるのでは??という意味です。

失礼しました。

box

Re:ポインタ

#7

投稿記事 by box » 18年前

最外周という言葉を含んで、
添字の外とか内の概念が今一つ
よくわからないです。

左とか右ならよくわかるのですけれど。

box

Re:ポインタ

#8

投稿記事 by box » 18年前

> 最外周がポインタに読み替えられるなら配列へのポインタ( (*P)[2] )ではなくポインタ配列( *p[2] )になるのでは??

「最外周」が仮に「いちばん左の添字」という意味だとして、
「~読み替えられるなら」までとそこから後ろがつながらないです。

「配列へのポインタ」は、結局のところポインタです。
また、「ポインタの配列」は、結局のところ配列です。

そうすると、おっしゃっている内容は
「最外周をポインタに読み替えるなら、ポインタではなく配列になるのでは??」となり、
意味が通じなくなっています。

大工

Re:ポインタ

#9

投稿記事 by 大工 » 18年前

説明が中と半端ですみません。

func(p[/url])では添字を書いても書かなくてもfunc(*p)となるので, func(p[/url][2])だと左半分が先ほどと同じ形なのでポインタになり p[/url] → *p つまりfuncの中ではfunc(*p[2])といった配列のポインタの扱いになるはずなのにどうしてfunc( (*p)[2] )と配列へのポインタになってしまうのでしょうか??という意味です。

あと, 最外周は一番左の配列のことを言います。

[3][2]だと配列の要素が2つあるものが3つある の3です。

box

Re:ポインタ

#10

投稿記事 by box » 18年前

(*p)[2] と *(p[2]) との違いはおわかりですね?

大工

Re:ポインタ

#11

投稿記事 by 大工 » 18年前

はい、もちろんです。

box

Re:ポインタ

#12

投稿記事 by box » 18年前

*p[2] と、() を使わずに書いたとき、
言語仕様上、(*p)[2] と *(p[2]) のどちらとみなしますか?

大工

Re:ポインタ

#13

投稿記事 by 大工 » 18年前

*(p[2])です。

box

Re:ポインタ

#14

投稿記事 by box » 18年前

void func1(int (*p)[2]);
と、
void func2(int *p[2]);
という2つのプロトタイプ宣言があるとします。

このとき、func1関数とfunc2関数のそれぞれの引数pの説明を
日本語で行なうとどうなりますか?

大工

Re:ポインタ

#15

投稿記事 by 大工 » 18年前

func1:要素を2個持つint配列へのポインタ
func2:int型へのポインタを2つ要素にもつ配列

こんなかんじでどうでしょうか?

box

Re:ポインタ

#16

投稿記事 by box » 18年前

void func(p[/url][2]);
というプロトタイプ宣言と同じ意味を持つのは、
先ほどのfunc1関数、func2関数のどちらでしょうか?

大工

Re:ポインタ

#17

投稿記事 by 大工 » 18年前

。。。。わからないです。

どうしても, p[/url] → *p が気になってしまいます。。

演算子の優先順位からだと。。。

func1(*p[2]);とどうしてもなってしまいます。

YuO

Re:ポインタ

#18

投稿記事 by YuO » 18年前

追加質問的に。

一つ目。
void func3(int a[2][2]);
という関数宣言があるとします。

この関数の引数aの説明を,配列がポインタになるという規則を無視して,日本語で行うとどうなりますか?
※できれば説明の一部を抜き出した場合に別の型の説明になる場合はその部分の末尾に「~型」と書いておいてください。


二つ目。
No.10867でboxさんが質問されたfunc1の引数のpおよびfunc2の引数のp,それから私の上の質問のfunc3のa,の3つの日本語の解説に,
説明の一部が別の型の説明になっているものを見つけ出して,それを括弧等で括ってみてください。
# 配列型派生,ポインタ型派生の派生元の型を括弧で括ろう,ということ。
例)int ** p
→『「int型」へのポインタ型』へのポインタ型
※int型,「int型」へのポインタ型はそれぞれint, int *という別の型になります。


三つ目。
二つ目と同様に,以下の二つについて日本語の括弧等入りの解説を作ってみてください。
・int a[3]
・int *p


二つ目と三つ目を比べると,boxさんのNo.10869の質問の解答が見えてくるかな,と思うのですが。

一応,先に関数引数の配列型に関して書いておくと,
引数が
・「~型」への配列型
という型を持っているとき,コンパイラはこれを
・「~型」へのポインタ型
と読み替えます。
この時,「~型」はたとえ配列型であっても変更されません。
# この説明のための二つ目と三つ目の質問です。

閉鎖

“C言語何でも質問掲示板” へ戻る