ヌル終端文字
CoddyのCジャーニー「Logic & Flow」セクションの一部 — レッスン 13/63。
C言語の文字列は文字の配列であることを学びましたが、それらを正しく機能させるための重要な詳細があります。すべてのC言語の文字列は、\0と記述されるヌル終端文字(null terminator)と呼ばれる特殊な文字で終わらなければなりません。
ヌル終端文字は、文字列の終わりを示すASCII値が0の文字です。これがないと、printfのような関数は文字列がどこで終わるのかを判断できず、ランダムにゼロバイトに遭遇するまでメモリを読み取り続けるため、しばしば文字化けした出力が生成されることになります。
char word[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
// \0 はC言語に「文字列はここで終わり」と伝えます文字列を "Hello" のようなリテラルで初期化すると、C言語は自動的にヌル終端文字を追加します。しかし、手動で1文字ずつ文字列を構築する場合は、最後に \0 を追加することを忘れてはいけません。
このヌル終端文字があるため、"Hello"のような5文字の単語には6要素の文字配列が必要になります。つまり、\0のために1つ分の余分なスペースが必要なのです。この概念を理解することは、すべてのC言語の文字列関数が文字列の開始位置と終了位置をどのように判断するかという基礎となるため、不可欠です。
チャレンジ
簡単適切なヌル終端を用いた手動の文字単位の初期化を使用して、文字列の作成と操作を行うCプログラムを作成してください。プログラムの内容は以下の通りです:
- 要素数がちょうど5つの
nameという名前の文字配列を宣言します - 適切なヌル終端を用いて "John" と綴るように、
name配列を文字単位で手動で初期化します:- 1番目の要素: 'J'
- 2番目の要素: 'o'
- 3番目の要素: 'h'
- 4番目の要素: 'n'
- 5番目の要素:
'\0'(ヌル終端文字)
- 要素数がちょうど7つの
cityという名前の2つ目の文字配列を宣言します - 適切なヌル終端を用いて "Boston" と綴るように、
city配列を文字単位で手動で初期化します:- 'B', 'o', 's', 't', 'o', 'n', および
'\0'を個別に文字代入します
- 'B', 'o', 's', 't', 'o', 'n', および
printfと%sフォーマット指定子を使用して、両方の文字列を出力します- ヌル終端がない場合に何が起こるかを示すために、要素数が4つの
testという名前の3つ目の文字配列を作成します testを文字 'A', 'B', 'C', 'D' のみで初期化します(ヌル終端なし)- 予測不可能な出力を示すために、
%sを使用してtest配列を出力します
出力結果は以下の形式で表示される必要があります:
Name: John
City: Boston
Test without null terminator: ABCD[unpredictable characters]このチャレンジでは、手動での文字列構築の理解、C言語の文字列におけるヌル終端文字 '\0' の極めて重要な役割、および %s を使用した printf が文字列の終わりを判断するためにヌル終端文字の検出にどのように依存しているかをテストします。
チートシート
C文字列は、文字列の終わりを示すためにヌル終端文字 \0 で終わらなければならない文字配列です。
ヌル終端文字はASCII値が0であり、printfのような関数に文字列がどこで終わるかを伝えます:
char word[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
// \0はCに「文字列はここで終わる」と伝えます"Hello"のような文字列リテラルを使用する場合、Cは自動的にヌル終端文字を追加します。文字を1つずつ組み立てて文字列を作成する場合は、手動で \0 を追加する必要があります。
文字列にはヌル終端文字のために配列要素が1つ余分に必要です。「Hello」(5文字)には6要素の配列が必要です。
自分で試してみよう
#include <stdio.h>
int main() {
// TODO: ここにコードを記述してください
// 指定された通りに文字配列を宣言し、初期化します
// 結果を出力します
return 0;
}このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。