私は C と C++ が大好きですが、null で終わる文字列の選択には頭を悩ませずにはいられません。
- C より前に存在していた長さの接頭辞付き (つまり Pascal) 文字列
- 長さのプレフィックス付き文字列は、一定時間の長さの検索を可能にすることで、いくつかのアルゴリズムを高速化します。
- 長さのプレフィックス付き文字列を使用すると、バッファ オーバーラン エラーが発生しにくくなります。
- 32 ビット マシンでも、文字列が使用可能なメモリのサイズになるようにすると、長さのプレフィックス付き文字列は、null で終了する文字列よりも 3 バイトだけ広くなります。16 ビット マシンでは、これは 1 バイトです。64 ビット マシンでは、文字列の長さの制限として 4GB が合理的ですが、それをマシン ワードのサイズまで拡張したい場合でも、64 ビット マシンには通常十分なメモリがあり、余分な 7 バイトが null 引数のようになります。元の C 標準が (メモリの点で) 非常に貧弱なマシン向けに作成されたことは知っていますが、効率の議論は私をここで売り込むものではありません。
- 他のほとんどすべての言語 (つまり、Perl、Pascal、Python、Java、C# など) は、長さのプレフィックス付き文字列を使用します。これらの言語は通常、文字列操作のベンチマークで C よりも優れています。
- C++ はテンプレートを使用してこれを少し修正しました
std::basic_string
が、null で終了する文字列を期待するプレーンな文字配列は依然として普及しています。ヒープ割り当てが必要なため、これも不完全です。 - ヌルで終了する文字列は、文字列に存在できない文字 (つまり、ヌル) を予約する必要がありますが、長さの接頭辞が付いた文字列には、埋め込まれたヌルを含めることができます。
これらのことのいくつかは C よりも最近明らかになったので、C がそれらを知らなかったのは理にかなっています。ただし、いくつかは C が登場する前に単純なものでした。明らかに優れた長さの接頭辞ではなく、ヌルで終了する文字列が選択されたのはなぜですか?
編集: 上記の効率化ポイントについて、いくつかの事実を尋ねた(そして、私が既に提供したものを好まなかった) ため、それらはいくつかのことに由来します:
- null で終了する文字列を使用した連結には、O(n + m) 時間の計算量が必要です。多くの場合、長さのプレフィックスには O(m) しか必要ありません。
- null で終了する文字列を使用した長さには、O(n) 時間の計算量が必要です。長さのプレフィックスは O(1) です。
- 長さと連結は、最も一般的な文字列操作です。null で終了する文字列の方が効率的である場合がいくつかありますが、その頻度ははるかに低くなります。
以下の回答から、null で終了する文字列の方が効率的である場合がいくつかあります。
- 文字列の先頭を切り取り、それを何らかのメソッドに渡す必要がある場合。長さの接頭辞はおそらく整列規則に従う必要があるため、元の文字列を破棄することが許可されていても、長さの接頭辞を使用して一定の時間でこれを行うことはできません。
- 文字列を 1 文字ずつループしているだけの場合、CPU レジスタを保存できる場合があります。これは、文字列を動的に割り当てていない場合にのみ機能することに注意してください (文字列を解放する必要があるため、保存した CPU レジスタを使用して、もともと malloc と友人から取得したポインターを保持する必要があります)。
上記のいずれも、長さと連結ほど一般的ではありません。
以下の回答には、もう1つ主張されています。
- 弦の端を切り落とす必要があります
しかし、これは正しくありません。null で終了し、プレフィックス付きの長さの文字列の時間は同じです。(null で終了する文字列は、新しい末尾にしたい場所に null を貼り付けるだけで、長さプレフィックスはプレフィックスから減算するだけです。)