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