数値配列がヌル文字で終わらないのはなぜですか?
例えば、
char name[] = {'V', 'I', 'J', 'A', 'Y', '\0'};
しかし、数値配列の場合、最後にヌル文字の兆候はありません...
例えば、
int marks[] = {20, 22, 23};
その背後にある理由は何ですか?
文字列は 0 ターミネータで終わりますが、文字列は配列と同じではありません。文字列を格納するために配列を使用しますが、文字列以外のものを格納するためにも配列を使用します。そのため、一般に、配列には自動的に 0 が追加されません。
さらに、 のジェネリック配列ではint
、0 が有効な (非センチネル) 値である可能性があります。
必要に応じて、int
配列を次のように終了させることもできます。0
int iarray[] = {1, 2, 3, 0};
'\0'
とはまったく同じなので、上記を に0
置き換えることもできます。0
'\0'
'\0'
あなたの混乱は、次のような宣言への自動挿入が原因である可能性があります。
char s[] = "hello";
上記では、 の定義はs
と同等char s[] = {'h', 'e', 'l', 'l', 'o', '\0'};
です。これは、C 標準によって提供される便利なショートカットと考えてください。必要に応じて、サイズを明示することで、ゼロ以外で終了する char 配列を強制できます。
char s[5] = "hello";
上記の例では、終了しs
ません。NUL
また、C の文字リテラルは 型int
であるため、'\0'
実際にはint
. (さらに、char
一体型です。)
配列の長さを追跡するには 3 つ、おそらく 4 つの適切な方法がありますが、C で一般的なのはそのうちの 2 つだけです。
自分で長さを追跡し、ポインターと一緒に渡します。
これは、配列が通常どのように機能するかです。特別なフォーマットを必要とせず、部分配列ビューを簡単に表現できます。(ポインターに加算し、長さを減算します。)
文字列以外の配列を扱う標準ライブラリの関数はすべて、これを想定しています。また、文字列をいじる一部の関数 (strncat
または などfgets
) でさえ、安全のためにそれを行います。
何らかの「センチネル」値で配列を終了します。
これが C 文字列の仕組みです。存在するほぼすべての文字セット/エンコーディングは、'\0'
印刷不可能な「何もしない」制御文字として定義されているため、テキストの典型的な部分ではないため、文字列を終了するために使用することは理にかなっています.
ただし、 a をバイト配列char[]
として使用している場合でも、長さを指定する必要があることに注意してください。これは、バイトが文字ではないためです。 文字ではなくバイトを扱うようになると、センチネル値としての意味が失われ、単純な古いデータに戻ります。0
大きな問題は、最も基本的な型では、考えられるすべてのsizeof(type)
バイト配列が有効で有用な値を表す可能性があることです。整数値の場合、ゼロは特に一般的です。これはおそらく、すべてのコンピューティングで最も使用され、最も有用な数値の 1 つです。0
データの半分を失うことなく、整数の配列にa を入れることができることを完全に期待しています。
それでは問題は、適切なセンチネル値とは何でしょうか? 配列で非合法化されるべきである、そうでなければ合法な数は何ですか? そして、その質問には、適切で普遍的な答えはありません。それはあなたのデータに完全に依存します。ですから、そのようなことをしたい場合は、自分で行ってください。
まともなセンチネル値がないことに加えて、このアプローチは別の理由で文字以外の型ではうまくいきません。配列のサブセットを表すのはより複雑です。再帰関数が配列の一部を自分自身に渡すには、センチネル値を挿入し、自分自身を呼び出してから、古い値を復元する必要があります。それか、範囲の開始点と範囲の長さへのポインターを渡すことができます。しかし、待ってください...それはあなたが避けようとしているものではありませんか? :P
完全を期すために、他の 2 つの方法は次のとおりです。
配列の長さとデータへのポインターを格納できる構造体を作成します。
これは、よりオブジェクト指向のアプローチであり、ほぼすべての最新言語で配列が機能する方法 (および C++ でベクトルが機能する方法) です。そのような構造体を管理する API があり、その API を宗教的に使用している場合、C で問題なく動作します。(オブジェクト指向言語は、API をオブジェクト自体にアタッチする方法を提供します。C にはそれがないため、API に固執するかどうかはあなた次第です。) しかし、構造体で動作するように設計されていない関数はすべて、上記の 2 つの方法のいずれかを使用して、ポインター (および場合によっては長さ) が渡されます。
2 つのポインターを渡します。
これは、C++ で「範囲」を渡す一般的な方法です。配列の先頭へのポインターと、配列の末尾のすぐ後ろにポインターを渡します。ただし、C ではあまり一般的ではありません。これは、生のポインターを使用して と が同じデータ(start,length)
を(start,end)
表すためです。C には、これをより便利にする反復子とテンプレートがありません。
'\0'
文字配列の最後に char を付ける必要はありません! これは間違った仮定です。あなたがするというルールはありません。文字 ( char
type) は、他の種類のデータとまったく同じです。
標準のprintf
-family 関数を使用して配列を出力する場合は、null で終了する char 配列が必要です。しかし、これらの関数が文字配列の末尾に依存しているという理由だけです - '\0'
char.
多くの場合、関数には、期待するデータの種類に関する規則があります。String ( char[]
) 関数も例外ではありません。しかし、これは言語要件ではありません。これらの要件を持つのは、使用している API です。
'\0'
これは、ライブラリが文字列の終了位置を認識する方法であるため、C 文字列を で終了する必要があります。
-termination は、NUL
char 配列と文字列( NUL
-terminated char-array)を区別するものです。ほとんどの文字列操作関数は、文字列が終了したとき (およびそのジョブが完了したとき) を知ることに依存しNUL
ており、単純な文字配列では機能しません (たとえば、配列の境界を超えて処理を続け、最後まで処理を続けます)。メモリのどこかを見つけNUL
ます-しばしばメモリが壊れます)。
char 配列は'\0'
、文字列として扱えるように特殊な char で終わります。また、文字列を操作しているときは、その文字列の長さ (境界) を伝える何らかの方法が必要です。
strcpyの関数プロトタイプを見てください
char * strcpy ( char * destination, const char * source );
ソースから宛先に何文字コピーするかをどのように知るのですか? 答えは''の位置を見ればわかり'\0
ます。
char は、'\0'
文字列を として扱う場合に顕著char *
です。終了マーカーがなければ、文字列として'\0'
扱うことはできませんでしたchar *
。