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

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

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

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

Q&A

解決済

4回答

5672閲覧

「&配列名」の意味について

cihnatr8

総合スコア14

C

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

2グッド

5クリップ

投稿2018/03/17 05:13

初質問です。
確認のための質問なのですが...
現在読んでいる本でchar array[];と宣言した1次元配列について、「&arrayはchar*型のarrayにアドレス演算子を付けたものだから, charへのポインタへのポインタと解釈される」と書かれているのですが、&arrayはchar型配列へのポインタですよね?

eien_beginner, yohhoy👍を押しています

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

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

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

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

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

guest

回答4

0

ベストアンサー

いくつかの意見が出ていますが、仕様に照らすとどれも正しいとは言えないのでより厳密な解釈を書きます。 結論から言うと、 char array[] と宣言された array があるとき、 &array はポインタのポインタではありません。 「&arraychar 型配列へのポインタ」という解釈が正しいです。

C/C++ で配列とポインタの関係を複雑にしているのは、配列はその先頭要素へのポインタへ暗黙の型変換をされるという規則です。 今回の質問について言えば、 arraychar の配列であり、それを型で言うなら char[] です。 これは暗黙の型変換によって char* になります。

ただし、この暗黙の型変換には例外があり、 & を適用するときは起こらないことになっています。 & はアドレスを得る演算子ですから配列 array のアドレスを得るという効果として現れることになります。 &arrayarray という配列を指すポインタです。

  • array は配列 (型で言えば char[]) であるが配列の先頭要素を指すポインタ (型で言えば char*) として使える
  • &array は配列を指すポインタ (型で言えば char(*)[]) である

値として見れば「配列の先頭要素を指すポインタの値」は「配列を指すポインタの値」と普通は同じでしょう。 array&array は型違いで同じ場所を指しているポインタと考えられます。

ただし、 char array[] が仮引数として宣言されていた場合は別の規則によって char* array と読み替えられるので、 &array はポインタのポインタです。

投稿2018/03/17 15:41

編集2018/03/17 23:42
SaitoAtsushi

総合スコア5437

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

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

a_saitoh

2018/03/18 06:51

もともと配列名を書いただけで先頭要素のポインタ値と解釈されるので、配列名に&をつける必要はありません。なので当初のCでは &配列名 は無かったのです。ANSI規格化するときに、 「一般には&左辺値式 は左辺値式のポインタだが、 &配列名 の時だけ例外で配列先頭要素へのポインタ」 とかいう規定が出来たのだったとおもいます。記憶で書いてますのでちょっとあやふや。
SaitoAtsushi

2018/03/18 09:54

C89 を持っていないので K&R 第2版 (の日本語版) の付録で確認したのですが、この時点でも & を配列に適用したときには型変換の例外になっていました。 なので &配列名 はあくまでも「配列を指すポインタ」であって「配列の先頭要素を指すポインタ」ではないようです。
a_saitoh

2018/03/22 03:31

むむむ。僕の持ってるK&R(ANSIじゃないやつ)ではななめ読みでは見当たりませんが、何ページでしょう?「配列は左辺値ではない」とあります。K&R第2版はANSI対応後の本ですよね?
SaitoAtsushi

2018/03/22 10:52

245ページの「A.7.1 ポインタの生成」に書かれています。 配列は配列の最初の要素へのポインタへ変換される旨がかかれていますが、単項&のオペランドであるときは対象外であると明示されています。 K&R 第2版は ANSI 規格準拠を標榜しています。 その付録は規格そのものではありませんが、 ANSI に沿って書かれたリファレンスであると書かれています。 この付録を読む限りでは配列が左辺値であるかどうか直接的な言及は見当たりませんでした。 C99 の仕様書だと左辺値 (lvalue) の概念が整理されて「変更可変な左辺値」という区分を設けていて、配列は左辺値だが変更可能な左辺値ではないことになっているので、 C89 の時点でも似たような概念があった可能性はあると思います。 K&R 第2版の付録で代入の項目を見ると、左辺オペランドとして置ける要件に左辺値であることに加えて変更可能であることが要求されているからです。 const (修飾されていない) のことを言っているかもしれないのでちょっと微妙なんですが……。 ちゃんとした資料を手に入れないとこれ以上のことはわからないですね。 試しに gcc で C89 モード (オプション -std=c89 を付ける) で int data[]={1,2,3}; int *p=&data; をコンパイルしてみると型が合ってないという警告は出るので &data の型は int* ではないと思うのですが、なぜか警告メッセージに型が表示されないのでどういう解釈をしてこうなっているのかはわからないですね……。 C99 モードだと期待する型と与えられた型を教えてくれるのですが。
a_saitoh

2018/03/22 15:56

ぼくが言ってる「当初のC」はANSIになる前のCです。K&R 初版の記述~4.[23]BSDに載ったバークレーpccあたりCの話。
SaitoAtsushi

2018/03/22 16:23 編集

ありゃ、どこがかみ合ってないのでしょう? 私の理解だと「ANSI 規格化するときに出来た規定では (中略) だったと思う」という話だったので、 ANSI 規格 (C89) の挙動ではそうなっていない (っぽい) ですと返したつもりなのですが、古い C がどう関わってくるのでしょうか。
a_saitoh

2018/03/23 08:36

じゃ、C89ではなくてもっと後に追加された規定ですかね。
SaitoAtsushi

2018/03/23 09:59

あっ、私の方が誤解してたかもしれません。 そちらの主張の中心は「(C89 で) &配列名 と書けるようになった」ということなんですかね? それに対して私は「(C89 で) &配列名 が返すのは『配列の先頭要素へのポインタ』ではない (けど &配列名 という書き方は出来て、それは配列を指すポインタであるっぽい)」という型の話をしているので食い違ったのでは……
guest

0

[ご参考] コンパイラ(Visual C++ 64bit)に訊いてみた。

C++

1#include <iostream> 2#include <typeinfo> 3 4int main() { 5 char array[5]; 6 std::cout << " array : " << typeid(array).name() << std::endl; 7 std::cout << "&array : " << typeid(&array).name() << std::endl; 8}

実行結果:

array : char [5] &array : char (* __ptr64)[5]

投稿2018/03/22 04:32

episteme

総合スコア16614

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

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

0

配列名をポインタとして評価する場合、先頭の要素のアドレスを返します。
ポインタが配列を示しているか、ただ一つの数を示しているか識別する方法はありません。

ですので『arrayはcharポインタとして評価される』と言うのも概ね正しいです。


ただし残念ながら、以下の記述は全体的には誤りです。

&arrayはchar*型のarrayにアドレス演算子を付けたものだから, charへのポインタへのポインタと解釈される

arrayの先頭アドレス(char*)を取る原則的な方法は&arrayです。
ただし、いくつかの文脈を除き、単にarrayと書いていいだけなのです。

&arrayはcharへのポインタのポインタではなく、charへのポインタです。


例えば以下のプログラムでそれを知ることが出来ます。Wandbox

C

1char hoge[] = "hoge"; 2 3printf("%p\n", hoge); 4printf("%p\n", &hoge); 5printf("%p\n", &hoge[0]);

アドレスは全て同じです。

投稿2018/03/17 06:10

LouiS0616

総合スコア35658

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

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

0

C言語の特例のため、char型配列名はchar型のアドレスと同一視できるため、
どちらも正しいです

投稿2018/03/17 05:17

編集2018/03/17 05:23
y_waiwai

総合スコア87719

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

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

SaitoAtsushi

2018/03/17 08:00 編集

配列に対する & 演算子の適用は暗黙の型変換の例外 (特例が適用されない) にあたるので、自動的に変換されたりはしません。 数値が等しいという意味では同一ですが、式 &array の型は char(*)[] となり、これが意味するところは「char の配列を指すポインタ」です。 字面通りに読んで良いのですが、配列がポインタに変換されるルールに慣れているとかえって混乱するかもしれないですね。
y_waiwai

2018/03/17 11:57

まあ、そう判断してもいいし、そうでない判断してもいい、ということで、そこらへんは受け取る人間の判断でいいんでないでしょうか。 こうでないといけない、という根拠もないというのが実際のところではあります
y_waiwai

2018/03/17 11:58

アドレスの値が同一だ、ということから、こうでないといけないという証拠にもなりませんしね。
SaitoAtsushi

2018/03/17 14:51

いえ、元質問は「&array はポインタのポインタと解釈していいのか」という話なので、値が array = &array であるからにはポインタのポインタと解釈するのはおかしいという意味です。 値が等しいというのは、ポインタのポインタとして解釈できないことの根拠として出しました。
y_waiwai

2018/03/17 14:55

値が等しいのはポインタのポインタではないという根拠にはなりませんが。 なぜ根拠になるとお思いですか?
SaitoAtsushi

2018/03/17 15:31

まず前提としてポインタはあるオブジェクトを指し示す仕組みです。 値が等しいことは &array がポインタの場所を指し示していないことの傍証になります。
y_waiwai

2018/03/17 22:34 編集

たぶんみんな言ってることは同じなんだとおもいます 私は、アドレスの値が同一だ、ということだけで、これはchar*だ、と断じているところがちと乱暴ではないの?とおもいます あくまで配列(char[])のアドレスであって、それがchar* として使えるってのはたまたまアドレスが同じ値を指しているだけであって、まあ、これがCという言語的にえ~加減なところでもあるんだけど、一緒くたにしてしまうのは(間違いとまでは言えないけど)まずいんじゃ?ということなんですね まあ、この考え方も、多分正解とか間違いということじゃなく、こういう考え方もあるという程度のもんなんですけどね。 さて、この配列のアドレスが char** になるのか?と言うことも同様で、ここらへんがCのえーかげんなところで(そこらへんは歴史的な経緯もあるんでしょうけど)、これも間違い、と断じてしまうのはこれもまた乱暴ではないの?とおもいます。 まあ、これも考え方の一つ、でしかないんだけどね #さきのコメントはサケ飲んで書いてしまったんでちと乱暴に書いてしまいました。こめんなさい
SaitoAtsushi

2018/03/18 09:23

そこまでいいかげんに拡大解釈したら「型が int* でも long long int*** でもメモリ上のどこかを指す『値』だから同じだ」と言えちゃいますよ。 私がここで型を強調して書いているのは、値とその値が表そうとしているものを混同して欲しくないという意図もあってのことなので同じだと断じたいわけじゃないではないですが、実際にポインタ (の場所) を指さずに配列を指しているものをポインタのポインタと呼ぶのは C の型システム的にも実態にも合ってないでしょう。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問