配列の場合、なぜa [5] == 5 [a]の場合ですか?

1651
Dinah 2008-12-20 07:01.

JoelがStackOverflowポッドキャスト#34で指摘しているように、Cプログラミング言語(別名:K&R)では、Cの配列のこのプロパティについて言及されています。a[5] == 5[a]

Joelは、それはポインタ演算のせいであると言いますが、私はまだ理解していません。なぜa[5] == 5[a]ですか?

17 answers

1952
Mehrdad Afshari 2008-12-20 07:04.

C標準では、[]演算子を次のように定義しています。

a[b] == *(a + b)

したがって、次のa[5]ように評価されます。

*(a + 5)

そして5[a]評価します:

*(5 + a)

a配列の最初の要素へのポインタです。a[5]は、から5要素離れた値aであり、と同じ*(a + 5)であり、小学校の数学から、それらが等しいことがわかります(加算は可換です)。

289
David Thornley 2008-12-20 07:05.

配列アクセスはポインタの観点から定義されているためです。a[i]*(a + i)、可換であるという意味で定義されます。

237
Keith Thompson 2013-08-23 15:37.

他の答えでは何かが見落とされていると思います。

はい、p[i]定義上、と同等です*(p+i)。これは(加算が可換であるため)、と同等です*(i+p)。これも([]演算子の定義により)と同等i[p]です。

array[i]では、配列名は暗黙的に配列の最初の要素へのポインターに変換されます。)

しかし、この場合、加算の可換性はそれほど明白ではありません。

両方のオペランドが同じ型である場合、または共通の型にプロモートされる異なる数値型である場合でも、可換性は完全に理にかなっていますx + y == y + x

ただし、この場合は、一方のオペランドがポインターで、もう一方のオペランドが整数であるポインター演算について具体的に説明しています。(整数+整数は別の演算であり、ポインター+ポインターは意味がありません。)

C標準の+演算子の説明(N1570 6.5.6)は次のように述べています。

さらに、両方のオペランドが算術型であるか、一方のオペランドが完全なオブジェクト型へのポインタであり、もう一方が整数型である必要があります。

それは同じように簡単に言ったかもしれません:

さらに、両方のオペランドが算術型であるか、左側のオペランドが完全なオブジェクト型へのポインタであり、右側のオペランドが整数型である必要があります。

その場合、i + pとの両方i[p]が違法になります。

C ++の用語では、実際には2セットのオーバーロードされた+演算子があり、大まかに次のように説明できます。

pointer operator+(pointer p, integer i);

そして

pointer operator+(integer i, pointer p);

そのうち最初のものだけが本当に必要です。

では、なぜこのようになっているのでしょうか。

C ++は、この定義をCから継承しました。CはBから取得しました(配列インデックスの可換性は、1972年のユーザーズリファレンスBに明示的に記載されています)、BCPL(1967年のマニュアル)から取得しました。以前の言語(CPL?Algol?)。

したがって、配列のインデックス付けは加算の観点から定義され、その加算は、ポインターと整数であっても可換であるという考えは、何十年も前にCの祖先言語にまでさかのぼります。

これらの言語は、現代のCよりも強く型付けされていませんでした。特に、ポインタと整数の区別はしばしば無視されていました。(初期のCプログラマーは、unsignedキーワードが言語に追加される前に、ポインターを符号なし整数として使用することがありました。)したがって、オペランドが異なるタイプであるために加算を非可換にするという考えは、これらの言語の設計者にはおそらく思い浮かばなかったでしょう。ユーザーが2つの「もの」を追加したい場合、それらの「もの」が整数、ポインター、またはその他のものであるかどうかにかかわらず、それを防ぐのは言語次第ではありませんでした。

そして何年にもわたって、そのルールへの変更は既存のコードを壊していたでしょう(1989年のANSI C標準は良い機会だったかもしれませんが)。

ポインタを左側に、整数を右側に配置する必要があるようにCやC ++を変更すると、既存のコードが破損する可能性がありますが、実際の表現力が失われることはありません。

つまり、後者の形式はIOCCCの外部に表示されるべきではありませんがarr[3]、今では3[arr]まったく同じ意味を持っています。

199
James Curran 2008-12-20 07:07.

そしてもちろん

 ("ABCD"[2] == 2["ABCD"]) && (2["ABCD"] == 'C') && ("ABCD"[2] == 'C')

これの主な理由は、Cが設計された70年代に、コンピューターに多くのメモリがなかったため(64KBが多かった)、Cコンパイラーが構文チェックをあまり行わなかったためです。したがって、「X[Y]」はやや盲目的に「*(X+Y)」に翻訳されました

これは、「+=」および「++」の構文についても説明しています。" A = B + C"の形式のすべてが同じコンパイル済み形式でした。ただし、BがAと同じオブジェクトである場合は、アセンブリレベルの最適化を利用できました。しかし、コンパイラーはそれを認識するのに十分な明るさ​​ではなかったので、開発者は(A += C)をしなければなりませんでした。同様に、もしCいた1、別のアセンブリレベルの最適化が利用可能であった、と再び開発者は、コンパイラがそれを認識していなかったので、それを明示しなければなりませんでした。(最近ではコンパイラーがそうしているので、これらの構文は最近ほとんど不要です)

56
user30364 2009-02-12 05:56.

誰もダイナの問題について言及していないようですsizeof

ポインターに追加できるのは整数のみで、2つのポインターを一緒に追加することはできません。そうすれば、整数へのポインター、またはポインターへの整数を追加するときに、コンパイラーは、考慮に入れる必要のあるサイズのビットを常に認識します。

50
Peter Lawrey 2011-08-12 03:50.

文字通り質問に答えること。それは必ずしも真実ではありませんx == x

double zero = 0.0;
double a[] = { 0,0,0,0,0, zero/zero}; // NaN
cout << (a[5] == 5[a] ? "true" : "false") << endl;

プリント

false
29
Frédéric Terrazzoni 2012-06-11 09:50.

この醜い構文は「便利」であるか、同じ配列内の位置を参照するインデックスの配列を処理するときに少なくとも非常に楽しいものになる可能性があることがわかりました。ネストされた角括弧を置き換えて、コードを読みやすくすることができます。

int a[] = { 2 , 3 , 3 , 2 , 4 };
int s = sizeof a / sizeof *a;  //  s == 5

for(int i = 0 ; i < s ; ++i) {  
           
    cout << a[a[a[i]]] << endl;
    // ... is equivalent to ...
    cout << i[a][a][a] << endl;  // but I prefer this one, it's easier to increase the level of indirection (without loop)
    
}

もちろん、実際のコードではそのユースケースはないと確信していますが、とにかく面白いと思いました:)

26
PolyThinker 2008-12-20 22:16.

素敵な質問/回答。

Cポインタと配列は同じではないことを指摘したいだけですが、この場合、違いは本質的ではありません。

次の宣言を検討してください。

int a[10];
int* p = a;

ではa.out、シンボルaは配列の先頭のpアドレスにあり、シンボルはポインタが格納されているアドレスにあり、そのメモリ位置のポインタの値は配列の先頭です。

20
Noname 2012-03-23 21:05.

Cのポインタについては、

a[5] == *(a + 5)

そしてまた

5[a] == *(5 + a)

したがって、それは本当です a[5] == 5[a].

16
Ajay 2011-06-19 22:37.

答えではありませんが、考えるべき食べ物です。クラスにオーバーロードされたインデックス/添え字演算子がある場合、式0[x]は機能しません。

class Sub
{
public:
    int operator [](size_t nIndex)
    {
        return 0;
    }   
};

int main()
{
    Sub s;
    s[0];
    0[s]; // ERROR 
}

intクラスにアクセスできないため、これを行うことはできません。

class int
{
   int operator[](const Sub&);
};
12
A.s. Bhullar 2013-09-27 20:46.

テッド・ジェンセンによる「Cのポインターと配列に関するチュートリアル」で非常に良い説明があります。

テッドジェンセンはそれを次のように説明しました:

実際、これは真実です。つまり、どこに書いa[i]*(a + i)も問題なく置き換えることができます。実際、コンパイラーはどちらの場合も同じコードを作成します。したがって、ポインタ演算は配列のインデックス付けと同じであることがわかります。どちらの構文でも同じ結果が得られます。

これは、ポインタと配列が同じものであると言っているのではなく、そうではありません。配列の特定の要素を識別するために、2つの構文を選択できると言っているだけです。1つは配列のインデックス付けを使用し、もう1つはポインター演算を使用して同じ結果を生成します。

さて、この最後の式、その一部を見ると(a + i)、+演算子を使用した単純な加算であり、Cの規則は、そのような式は可換であると述べています。つまり、(a + i)は(i + a)。と同じです。したがって、と*(i + a)同じくらい簡単に書くことができます*(a + i)。しかし*(i + a)、から来た可能性がありますi[a]!これらすべてから、次のような奇妙な真実が生まれます。

char a[20];

書き込み

a[3] = 'x';

書くのと同じです

3[a] = 'x';
8
Ajinkya Patil 2016-05-04 22:24.

私は質問が答えられることを知っています、しかし私はこの説明を共有することに抵抗できませんでした。

コンパイラ設計の原則を覚えています。aint配列で、サイズintが2バイトで、のベースアドレスaが1000であると仮定しましょう。

どのようa[5]に機能しますか->

Base Address of your Array a + (5*size of(data type for array a))
i.e. 1000 + (5*2) = 1010

そう、

同様に、cコードを3番地コードに分解5[a]すると、->になります。

Base Address of your Array a + (size of(data type for array a)*5)
i.e. 1000 + (2*5) = 1010 

したがって、基本的に両方のステートメントがメモリ内の同じ場所を指しているため、a[5] = 5[a]

この説明は、配列の負のインデックスがCで機能する理由でもあります。

つまり、私がアクセスa[-5]した場合、それは私に与えます

Base Address of your Array a + (-5 * size of(data type for array a))
i.e. 1000 + (-5*2) = 990

990の位置にあるオブジェクトが返されます。

7
Krishan 2013-12-18 01:22.

Cアレイ、arr[3]及び3[arr]同じであり、その等価ポインタ表記である*(arr + 3)*(3 + arr)。しかし、逆に[arr]3[3]arr正しくないと、構文エラーになります、など(arr + 3)*(3 + arr)*有効な式ではありません。その理由は、間接参照演算子は、アドレスの後ではなく、式によって生成されるアドレスの前に配置する必要があるためです。

6
AVIK DUTTA 2014-10-29 23:14.

cコンパイラで

a[i]
i[a]
*(a+i)

配列内の要素を参照するさまざまな方法です!(まったく奇妙ではありません)

5
dgnuff 2019-04-09 08:45.

今少し歴史。他の言語の中でも、BCPLはCの初期の開発にかなり大きな影響を及ぼしました。BCPLで次のような配列を宣言した場合:

let V = vec 10

これは実際には10ではなく11ワードのメモリを割り当てました。通常はVが最初で、直後のワードのアドレスが含まれていました。したがって、Cとは異なり、Vという名前はその場所に移動し、配列の0番目の要素のアドレスを取得します。したがって、BCPLでの配列の間接参照は、次のように表されます。

let J = V!5

J = !(V + 5)配列のベースアドレスを取得するためにVをフェッチする必要があったため、実際には(BCPL構文を使用して)実行する必要がありました。したがってV!5、と5!V同義でした。事例観察として、WAFL(Warwick Functional Language)はBCPLで記述されており、私の記憶の限りでは、データストレージとして使用されるノードにアクセスするために前者ではなく後者の構文を使用する傾向がありました。確かにこれは35年から40年前のことなので、私の記憶は少し錆びています。:)

ストレージの余分な単語を省き、名前が付けられたときにコンパイラに配列のベースアドレスを挿入させるという革新は後で起こりました。Cの歴史論文によると、これは構造がCに追加された頃に起こりました。

!BCPLでは、単項接頭演算子とバイナリ中置演算子の両方があり、どちらの場合も間接参照を行っていたことに注意してください。バイナリ形式には、間接参照を実行する前に2つのオペランドの追加が含まれているだけです。BCPL(およびB)の単語指向の性質を考えると、これは実際には非常に理にかなっています。Cではデータ型を取得する際に「ポインタと整数」の制限が必要にsizeofなり、モノになりました。

1
Harsha J K 2018-04-03 08:42.

さて、これは言語サポートのためにのみ可能である機能です。

コンパイラはa[i]として解釈し*(a+i)、式はに5[a]評価され*(5+a)ます。加算は可換であるため、両方が等しいことがわかります。したがって、式はに評価されtrueます。

0
Jayghosh Wankar 2017-02-13 03:54.

Cで

 int a[]={10,20,30,40,50};
 int *p=a;
 printf("%d\n",*p++);//output will be 10
 printf("%d\n",*a++);//will give an error

ポインタpは「変数」であり、配列名aは「ニーモニック」または「シノニム」であるためp++、有効ですがa++無効です。

a[2]対等である2[a]このの両方の内部動作が内部のように計算「ポインタ演算」であるため、*(a+2)イコール*(2+a)

Related questions

MORE COOL STUFF

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは、夫に会ったとき、典型的な交際のアドバイスに逆らいました。

マイケルシーンが非営利の俳優である理由

マイケルシーンが非営利の俳優である理由

マイケルシーンは非営利の俳優ですが、それは正確にはどういう意味ですか?

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。

「たどりつけば」をオンラインでストリーミングできない理由

「たどりつけば」をオンラインでストリーミングできない理由

ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

サロンからのヘアトリミングや個人的な寄付は、油流出を吸収して環境を保護するのに役立つマットとして再利用できます。

ホワイトハウスの最も記憶に残る結婚式を見てください

ホワイトハウスの最も記憶に残る結婚式を見てください

過去200年以上の間にホワイトハウスで結婚したのはほんの数人です。彼らは誰でしたか、そしてそこで結婚式を獲得するために何が必要ですか?

グッドジョブ、ESPN

グッドジョブ、ESPN

今日のホワイトハウスの記者会見で、報道官のサラ・ハッカビー・サンダースは、スポーツセンターのホストであるイェメル・ヒルのドナルド・トランプに関する最近のツイートについてコメントするよう求められ、大統領と彼の政策を白人至上主義者として説明した。ヒルは彼女のつぶやきのためにESPNによって公に叱責されました。

アマゾンからのこのレミントンツールセールで髪を整える、スタイルを整える、乾かす、または取り除く

アマゾンからのこのレミントンツールセールで髪を整える、スタイルを整える、乾かす、または取り除く

基本的に頭のあらゆる部分から髪の毛を整えたり、ブロードライしたり、まっすぐにしたり、脱毛したりする必要がある場合は、このレミントンゴールドボックスが最適です。今日だけ、Amazonは、すでに人気のあるShortcut Pro Self-HaircutKitやPearlPro Ceramic Flat Ironのように、グルーミングをはるかに簡単にするヘアツールをマークダウンしています。

カナダの元桂冠詩人が、史上最高の文化の盗用でトゥパックとマヤアンジェロウから盗んだ

カナダの元桂冠詩人が、史上最高の文化の盗用でトゥパックとマヤアンジェロウから盗んだ

トゥパックシャクール(ティムモーゼンフェルダー/ゲッティイメージズ); マヤアンジェロウ(マーティンゴッドウィン/ゲッティイメージズ)移動、テイラースウィフト。ケンドールとカイリーは、必要な数の座席を持っています。

テスラは、ハリケーンイルマによる避難を容易にするために、フロリダでの車両の範囲を拡大しています

テスラは、ハリケーンイルマによる避難を容易にするために、フロリダでの車両の範囲を拡大しています

写真:Tesla Motorsフロリダに住んでいて、Tesla Model S、Model X 60、またはModel 60Dを使用している場合、車の自律性は50 km(約30マイル)高くなります。これは失敗ではなく、ハリケーンイルマによる避難作業を容易にするために会社自身が命じた自治権の一時的な延長です。

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、生後4か月の娘、モナコに母乳育児をしていると語った。

投資ノート:Bioscout AU$300万シード

投資ノート:Bioscout AU$300万シード

Bioscoutは、農家を運転席に置くという使命を負っています。Artesian(GrainInnovate)やUniseedと並んで、最新のシードラウンドでチームを支援できることをうれしく思います。問題真菌症による重大な作物の損失は、農民にとって試練であることが証明されています。

リトルマーケットリサーチ1| 2022年のクイックグリンプス遠隔医療市場

リトルマーケットリサーチ1| 2022年のクイックグリンプス遠隔医療市場

遠隔医療は、パンデミック後の時代では新しいものではなく、時代遅れの分野でもありません。しかし、業界を詳しく見ると、需要と供給の強力な持続可能性と、米国で絶え間ない革命となる強力な潜在的成長曲線を示しています。

スタートアップ資金調達環境:タイのスタートアップエコシステムの次は何ですか?

スタートアップ資金調達環境:タイのスタートアップエコシステムの次は何ですか?

2021年は、世界的なベンチャーキャピタル(VC)の資金調達にとって記録的な年でした。DealStreetAsiaによると、東南アジアも例外ではなく、この地域では年間で記録的な25の新しいユニコーンが採掘されました。

ムーアの法則を超えて

ムーアの法則を超えて

計算に対する私たちの欲求とムーアの法則が提供できるものとの間には、指数関数的に増大するギャップがあります。私たちの文明は計算に基づいています—建築と想像力の現在の限界を超える技術を見つけなければなりません。

Language