Cで配列を関数の引数として渡すことができないのはなぜですか?


12

このコメントに続い、私はグーグルでグーグルを試みましたが、グーグルフーは失敗しました。

リンクからのコメント:

[...]しかし、重要なことは、Cでは配列とポインターが異なることです。

コンパイラの拡張機能を使用していないと仮定すると、通常、配列自体を関数に渡すことはできませんが、ポインタを渡し、ポインタを配列であるかのようにインデックス付けすることはできます。

ポインターには長さが付加されていないという事実に不満があります。配列を関数の引数として渡すことができないこと、または配列が暗黙的にポインターに低下することを不平を言うべきです。


それが答えかどうかはわかりませんが、配列のタイプの一部はそのサイズです。したがって、受け入れたいサイズごとに関数を定義する必要があると思います。
clcto 14年

関数ポインタとしての意味ですか? 質問を明確にしてください。
user949300 14年

2
@ user949300いいえ、コメントのコンテキストからはかなり明確です。配列がポインターになるため、関数に配列を渡すことはできません。また、なぜそうなのかを知りたがっています。
ドーバル14年

@DocBrown rlemonはこのための編集を提案しました。
フロリアンマーゲイン14年

回答:


18

私が最初に推測した理由は、単にパフォーマンスとメモリ節約の理由と、コンパイラの実装の容易さ(特にCが発明された当時のコンピューターの種類)でした。巨大な配列を「値で」渡すことはスタックに大きな影響を与えるように思われ、関数呼び出しごとに完全な配列コピー操作が必要であり、コンパイラは正しいアセンブリコードを出力するためにより賢くなければなりません(ただし、最後の点は議論の余地があります) 。また、動的に割り当てられた配列を静的に割り当てられた配列と同じ方法で扱うことは、言語の構文の観点からはより困難です。

編集:このリンクからいくつかの部分読んだ後、本当の理由(および構造体の配列が値型として扱われるのに対し、唯一の配列はそうではない理由)は、Cの先行Bとの後方互換性だと思います。以下はデニスリッチーの引用です。

[...}このソリューションは、型のないBCPLと型付きCの間の進化の連鎖における重要なジャンプを構成しました。ストレージ内のポインターの実体化を排除し、代わりに配列名が式で言及されるとポインターが作成されました。今日のCで生き残っているルールは、配列型の値が式に現れると、配列を構成する最初のオブジェクトへのポインターに変換されるということです。

この発明により、言語のセマンティクスの根本的な変化にもかかわらず、ほとんどの既存のBコードが機能し続けることができました。[..]


5
A struct Foo { int array[N]; } 値で渡すことできます。そして、(厳密な意味での配列は常にサイズを含む、配列インデックスのようなもののための統一概念がある同じが怪しいと思われる動的および静的割り当ての治療についての最後のビットは、ポインタの配列ツーポインタ崩壊と相まって)、あなたは手の込んだだろうか?

@delnan:ここで述べた一般原則は健全だと思います。明らかに、配列を構造体でラップすると、意図を指定していることになります。一般的な場合、ほとんどの場合、参照渡しになります。
ロバートハーヴェイ14年

また、OPで参照されているコメントは不必要に教訓的です。明らかに、値による配列ではなくポインタを渡している。しかし、同様に真実なのは、参照によって配列を効果的に渡しているということです長さが付けられていないという異議がある場合は、それも簡単に渡すことができます。
ロバートハーヴェイ14年

すべてが(構造体タイプの一部であるアレイがあっても、アレイタイプを除いて、値によって渡される:静止型システムにおける非対称だ@RobertHarvey れる呼び出しサイトでの値によって渡される)、それがあっても正確に同じ表記法を使用して(両方および関数シグネチャ内)。

@delnan:覚えておく必要がある以外に、なぜ関連するのですか?
ロバートハーヴェイ14年

9

メモリが8 kBしかないPDPミニコンピューターでは、非常に大きなスタックを割り当てることはできません。そのため、このようなマシンでは、予想される一般的なサブルーチン呼び出しの使用のためにスタックに何が必要かを最小限に抑えるために、言語設計(または進化)に注意する必要があります。Cは今日でも非常にメモリに制約のある(数kB)組み込みシステムをプログラムするために使用されているため、通常はトレードオフが適切です。

レジスタの数が非常に少ないプロセッサアーキテクチャでは、値ではなくポインタで配列を渡すと、レジスタをサブルーチン呼び出しの最適化として使用することができます。


2
データ用に256バイトのRAM、コード用に2K EEPROMを搭載したボードがいくつかあります。そこで配列のコピーを作成したくありません。
ジェリージェレミア
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.