質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

2回答

471閲覧

2次元配列のポインタ

txty

総合スコア298

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2020/09/27 03:24

int a[3][3]
のポインタの引数は関数に与えるとき、&a[3][3]でいいですか。今まで1次元配列しかつかってこなかったので、で関数で使うときは a[2][2]とかでいいんでしょうか。

たまにのっているa[0]とはなんでしょうか。よく分からないので教えてください。

(使ったことがないので、被害はありません)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

Cでは、二次元の配列は 一次元の配列 の配列です。
例えば、b[3][2]という配列をA番地から割り付けたとするなら(intが4byteを占める処理系としたとき)

  • b[3][2]の配列

(A+0x00)番地~ ただし、sizeof(b)は24

  • b[0], b[1], b[2]という3つの[int型要素2個の配列)]が含まれている、

(A+0x00)番地~b[0]
(A+0x08)番地~b[1]
(A+0x10)番地~b[2] ただし、sizeof(b[0])は8

  • b[0][0], b[0][1], b[1][0], b[1][1], b[2][0], b[2][1] のint型が含まれている

(A+0x00)番地~b[0][0] (A+0x04)番地~b[0][1]
(A+0x08)番地~b[1][0] (A+0x0c)番地~b[1][1]
(A+0x10)番地~b[2][0] (A+0x14)番地~b[2][1]

という格納がされているわけです。

以下、Cでは配列が単独で記述されたときには配列の先頭要素へのポインタと解釈される(sizeofあるいは&演算子のオペランドになったときは例外)、というのは前提知識として...

配列を関数の引数とするときは、とりあえず仮引数の型にはその配列をそのまま記述すれば成立はします(ただし配列の要素数は記述不要、記述しても無視される)。
あるいは、配列の先頭要素へのポインタ型を記述します。

  • 2次元配列int [3][2]を受け取りたいのなら

仮引数(関数の宣言)はfunc(int arg[][2]) あるいは func(int (arg)[2]) //後者はint2要素の配列へのポインタ型arg
これに対し、実引数(関数の呼び出し時)はそのまま配列を渡せばOK
func(b)
で呼び出します。つまり、bはその先頭要素b[0]へのポインタとして解釈され、int(
)[2]型の値です。
(余計なことを言えば、func(&b[0])でもOK。先述の例外のひとつ、&演算子で&b[0]はb[0]自身のアドレスを求める)

  • int[2]を受け取りたいのなら、

仮引数はfunc(int arg[]) あるいは func(int arg)
これに対し、実引数はint 2要素の配列を渡すので、
func(b[0])あるいはfunc(b[1]), func(b[2])
で呼び出します。つまり、b[0]とかb[1],b[2]はその先頭要素b[n][0]へのポインタとして解釈され、int
型の値です。

  • intへのポインタを受け取りたいのなら

仮引数はfunc(int *arg)
これに対し、実引数はintへのポインタを渡すので
func(&b[0][0])あるいはfunc(&b[0][1]), ... func(&b[2][0])
で呼び出します。

等と記述することになります。

ここで、前述のように、bの格納されている番地は、b[0]の格納されている番地でもあり、b[0][0]の格納されている番地(いずれもA+0x00)でもあります。Cは(暗黙で変換出来てしまうなら)型の一致を厳密にはチェックせず、受け取った仮引数の型として解釈しますから、
func(int arg[][2])と宣言した関数に対して
func(&b[0][0])と呼び出しを行っても(あるいはfunc(b[0])でも)
アドレスは同じなので動作してしまう、ということになります。

投稿2020/09/27 06:43

thkana

総合スコア7639

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

txty

2020/09/27 07:07

なんか大事なことを書いてあることは理解できるのですが、頭が理解することをを拒むので、面白そうだから暇なときに読みます。
guest

0

ベストアンサー

a でいいです
まあ、先頭アドレスを渡せばいいってことで、a[0]でも同じ値を渡せれるんですが、型が違ってきますね


C

1void kansu(int arg[3][3]) 2{ 3 // なんやかや 4} 5 6int a[3][3]={{1,2,3},{4,5,6},{7,8,9}}; 7 8int main(void) 9{ 10 kansu(a); // OK 11 12 kansu(a[0]); // int** を渡さなければいけないところに、int* を渡してます 13 kansu(&a[0][0]); // これも同上 14} 15

C言語では、コンパイルエラーとはなりませんが、ワーニングが出ますね

投稿2020/09/27 04:00

編集2020/09/27 04:43
y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

txty

2020/09/27 04:05

>aでいいですとはどこでしょうか 細分化しますが int a[3][3] のポインタの引数は関数に与えるとき、&a[3][3] まではあってますか。
y_waiwai

2020/09/27 04:09

ちがいます a[3][3] ってなに表してるのかよく考えましょう そのテでするなら、&a[0][0]で与えれば同じ値になります 配列は、配列名でポインタと互換できます
txty

2020/09/27 04:40 編集

一次元もa か&a[0]で渡すから、使うとき,a[~]ですが、間違ってても責任もてないが、2次元は(いろいろあるようですが) aでいいことも確認しました。&a[0][0]で渡したいです。使うときはa[~][~]のようですが、後、引数の受け取り側はどうなりますか。
txty

2020/09/27 05:16 編集

warningでるってことはやっちゃうといけないんですか。2重ポインタは回避したく、使いたくないです。(c++では、どうなるんでしょう。reinterpret_cast使わないとワーニングなのですか。)コードの張り付けみて、だいたい理解できました。ありがとうございます。
thkana

2020/09/27 05:35

> // int** を渡さなければいけないところ int (*)[3] を渡さなければいけないところ、ですよね。int**では、Cでは警告で許してくれるかも知れないけどC++ならエラー。
txty

2020/09/27 06:06 編集

/home/hoge/nijigen/src/main.cc:22:17: エラー: cannot convert ‘int*’ to ‘int (*)[3]’ for argument ‘1’ to ‘void kansu(int (*)[3])’ コメントありがとうございます。エラーでました。引数は、c++では、aじゃないと駄目なんですね。知りませんでした。(他の部分も知りませんでしたが)おふたがたありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問