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

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

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

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

Q&A

解決済

2回答

1428閲覧

C言語の配列変数とポインタについて

yudai524

総合スコア37

C

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

1グッド

1クリップ

投稿2016/07/06 18:51

編集2016/07/06 21:42

###前提・実現したいこと
普段、仕事でWeb系のプログラムを書いていますが
最近、Head First C という本でC言語を勉強し始めました。

そこでどうしても理解できない部分があります。

###該当のソースコード

c

1#include <stdio.h> 2 3int main() 4{ 5 int doses[] = {1, 2, 3, 1000}; 6 printf("用量%iを与える\n", 3[doses]); 7 8 return 0; 9}

###試したこと
上記のコードで、
標準出力に「用量1000を与える」が出力されるところまで確認しています。
また、本の解説では

c

1doses[3] == *(doses + 3) == *(3 + doses) == 3[doses]

と書いてあり、補足的な情報として、

dosesなどの配列変数はポインタとして使える

とありました。

c

1doses[3] == *(doses + 3) == *(3 + doses)

までは理解出来るのですが、なぜ

c

13[doses]

になるのかがどうしても理解できません。

そういう書き方も出来るんだ。と考えるべきなのでしょうか。

以上です。是非お知恵を拝借させて下さい。
すみませんが、よろしくお願い致します。


以下追記です。

###出典について

Head First C――頭とからだで覚えるCの基本
David Griffiths、Dawn Griffiths 著、中田 秀基 監訳、木下 哲也 訳
2013年04月 発行
ISBN978-4-87311-609-9
出版社: オライリージャパン
原書: Head First C
出版社サイトのこの本についてのページ

Chironian👍を押しています

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

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

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

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

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

cateye

2016/07/06 21:24

これは^^; 私は下記のような書き方をたまにしますが、上記のような方法は初めてですね。 "abcdef"[2] → 'c' 出典を教えていただければ幸いです。
yudai524

2016/07/06 21:43

出典を追加しました!
guest

回答2

0

ベストアンサー

C言語ではa[b](*((a)+(b)))と同一であると言語仕様で定められているからです。

C11仕様書最終ドラフトn1570 6.5.2.1 Array subscripting > Semantics 2 (p.80) より引用

A postfix expression followed by an expression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th element of E1 (counting from zero).

角括弧[]で囲む表現の後置式は、配列オブジェクトの要素の添字表現です。添字演算子[]の定義は、E1[E2](*((E1)+(E2)))と同一であるとしています。二項演算子+を評価するときの変換規則によって、もし、E1が配列オブジェクト(つまり、配列オブジェクトの最初の要素へのポインタ)であり、かつ、E2が整数値であるなら、E1[E2]E1(0から始める)のE2番目の要素を表します。

つまり、C言語では、a[b]の定義は直接「ab番目の要素」を表すということではありませんa[b]自体には(*((a)+(b)))であるということまでしか定義されておらず、実際の計算や評価の規則は+演算子や*演算子に委ねられています。しかし、ポインタに対する+の評価での変換規則等により、aが配列で、bが整数なら、結果的に「ab番目の要素」を表すことができるようになっているので、添字演算子として使えるということ過ぎません。

3[doses](*((3)+(doses)))と見なされます。整数とポインタの組み合わせにおける+演算子は、左右を逆にしても結果が同一である(n1570 6.5.6.8[p.93])ため、同じになると言うことです。

投稿2016/07/06 22:20

raccy

総合スコア21735

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

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

yudai524

2016/07/06 22:42

大変わかりやすい回答を頂きありがとうございます! 文句なしのベストアンサーでした。 今後、行き詰まったら仕様書を確認する習慣をつけようと思います。
guest

0

理解できなくても問題ありません。このようなトリッキーな書き方はバグのもとにもなり、読みにくくもなりますので、使うべきではありません。

と言うのが前提です。

ただ、あくまで実践で使わないお遊びとして考えるなら、C の配列は実際のところ基準となるポインタに(添字×型のサイズ)を足したポインタです。

JAVA などの処理系では当然エラーになる構文ですが、C では配列のアドレスは単純に計算によって求められ、範囲外かどうかのチェックはありません。
従って、計算として正しいならば通ってしまいます。

しかし、dose の指し示すポインタが仮に1024 で int のサイズが 4 であるとすると、&dose[3]=1024+34、&3[dose]=3+10244 となり、等しくありません。従って、解説は間違っています。

###追記
と書いた後で確かめて、実際に int であろうが long であろうが成り立つことがわかりました。この本のアドレス計算の部分はやはり誤りでしたが、配列に関しては逆にしても成り立ちます。

###訂正
よく調べもせずにいい加減なことを書きました。
私の書いた内容が誤りです。
訂正してお詫びします。

投稿2016/07/06 21:38

編集2016/07/06 22:24
Zuishin

総合スコア28660

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

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

Zuishin

2016/07/06 21:40

Hello first C という題名から察するに、これは入門書なのでしょうが、これは入門書に書くべき内容ではありません。 その本はしまっておいて、別の本をお読みになることをお勧めします。
yudai524

2016/07/06 22:42

いえいえ、Zuishinさんの回答(C では配列のアドレスは単純に計算によって求められ、範囲外かどうかのチェックはありません。 )を元に色々自分でコードを書いて(&3[doses]や&*(3+doses)のアドレスを確かめてみたり)試すことができ、 配列やポインタに対する理解がとても深まりました。 ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問