C言語で文字列を扱うとき、配列やポインタの仕組みが関わるため、数値の比較と比べて少し分かりにくく感じる人が多いです。
その中でも文字列を比較する関数strcmpは、標準ライブラリの中でも使用頻度が高いにもかかわらず、誤った使い方をされやすい関数の1つです。
本記事では、C言語初心者の方に向けて、strcmpの基本から、エラーになりやすいポイント、strncmpとの違いまで、実例を交えながらやさしく解説していきます。
strcmpとは何かを理解しよう
strcmpとは
strcmpは、2つの文字列を辞書順で比較する標準ライブラリ関数です。
C言語では、文字列はchar型の配列として表現され、終端を示す'\0'までが文字列の中身になります。
strcmpはこの配列を1文字ずつ見比べ、どちらが先か、あるいは同じかを判定します。
プログラム中では、例えばログインIDやコマンド名、メニュー選択の入力などを判定するときに頻繁に使われます。
数値同士の比較であれば==や<などの演算子を使いますが、文字列同士の場合は演算子ではなくstrcmpのような関数で比較する必要があることが重要なポイントです。
strcmpの基本的な書式とヘッダファイル
strcmpを使うには、標準ライブラリヘッダであるstring.hをインクルードします。
関数の宣言は次のようになっています。
int strcmp(const char *s1, const char *s2);
ここで、引数s1とs2は、比較したい2つの文字列へのポインタです。
どちらも'\0'で終端された文字列でなければなりません。
戻り値はint型で、0、正の値、負の値のいずれかになります。
実際に使うときは、次のようにヘッダをインクルードして使用します。
#include <stdio.h>
#include <string.h> // strcmpを使うために必要
int main(void) {
const char *a = "apple";
const char *b = "banana";
int result = strcmp(a, b); // aとbを比較
printf("result = %d\n", result);
return 0;
}
出力結果の例(実行環境により具体的な数値は変わることがあります)は次のようになります。
result = -1 // などの負の値
このように、strcmpは必ずstring.hをインクルードしてから使うという点を覚えておくことが大切です。
strcmpの戻り値(0, 正の値, 負の値)の意味
strcmpの戻り値は「どちらの文字列が辞書順で先か」を表します。
ここが初心者の方が最初につまずきやすいポイントです。
戻り値の意味は次の通りです。
| 戻り値 | 意味 |
|---|---|
| 0 | 2つの文字列の内容が完全に同じ(同じ長さ、同じ文字列) |
| 負の値(<0) | s1がs2より辞書順で前にある |
| 正の値(>0) | s1がs2より辞書順で後ろにある |
多くの教科書では「負の値」「正の値」と説明されますが、具体的な数値(例えば-1や2など)が何になるかは処理系依存であり、決まっていません。
そのため、プログラムでは戻り値を「== 1」や「== -1」のように比較してはいけません。
あくまで== 0、< 0、> 0という3パターンだけを使います。
簡単なイメージとしては、次のように考えると分かりやすいです。
- s1とs2を左から1文字ずつ比べる
- 最初に違う文字が出てきたところで、s1の文字とs2の文字の差(例:c – a)を返す
- 最後まで同じで、かつ長さも同じなら0を返す
この挙動により、辞書順の判定が実現されています。
なぜ文字列リテラル同士を==で比較してはいけないのか
C言語の初心者が必ずといってよいほどやってしまうミスが、次のようなコードです。
#include <stdio.h>
int main(void) {
const char *a = "apple";
const char *b = "apple";
if (a == b) {
printf("同じです\n");
} else {
printf("違います\n");
}
return 0;
}
一見すると、同じ文字列を代入しているのでa == bは真になりそうに思えます。
しかし、C言語における==は「ポインタが同じアドレスを指しているかどうか」を比べているだけで、文字列の内容を比較しているわけではありません。
コンパイラやリンクの最適化によっては、たまたま同じアドレスを指す場合もありますが、それは処理系依存の挙動です。
「文字列の中身が同じかどうか」を==で判定することはできないと考えてください。
文字列の内容を比較したい場合は、必ずstrcmpを使います。
#include <stdio.h>
#include <string.h>
int main(void) {
const char *a = "apple";
const char *b = "apple";
if (strcmp(a, b) == 0) { // 内容を比較
printf("内容は同じです\n");
} else {
printf("内容は違います\n");
}
return 0;
}
出力結果は次のようになります。
内容は同じです
「ポインタのアドレスを比較しているのか」「文字列の中身を比較しているのか」を常に意識することが、文字列処理を正しく書くための第一歩です。
strcmpの基本的な使い方
簡単なstrcmpの使用例
ここでは、もっとも基本的なstrcmpの例を示します。
2つの文字列を入力し、その大小(辞書順)を判定してみます。
#include <stdio.h>
#include <string.h>
int main(void) {
char s1[100];
char s2[100];
// ユーザから2つの文字列を入力してもらう
printf("1つ目の文字列を入力してください: ");
scanf("%99s", s1); // 最大99文字まで。最後の1文字は'#include <stdio.h>
#include <string.h>
int main(void) {
char s1[100];
char s2[100];
// ユーザから2つの文字列を入力してもらう
printf("1つ目の文字列を入力してください: ");
scanf("%99s", s1); // 最大99文字まで。最後の1文字は'\0'用
printf("2つ目の文字列を入力してください: ");
scanf("%99s", s2);
// strcmpで比較
int result = strcmp(s1, s2);
if (result == 0) {
printf("2つの文字列は<span style="--marker-custom-color: #ffcccc;" class="marker-custom">同じ</span>です。\n");
} else if (result < 0) {
printf("1つ目の文字列は2つ目の文字列より<span style="--marker-custom-color: #ffcccc;" class="marker-custom">辞書順で前</span>です。\n");
} else {
printf("1つ目の文字列は2つ目の文字列より<span style="--marker-custom-color: #ffcccc;" class="marker-custom">辞書順で後ろ</span>です。\n");
}
return 0;
}
'用
printf("2つ目の文字列を入力してください: ");
scanf("%99s", s2);
// strcmpで比較
int result = strcmp(s1, s2);
if (result == 0) {
printf("2つの文字列は<span style="--marker-custom-color: #ffcccc;" class="marker-custom">同じ</span>です。\n");
} else if (result < 0) {
printf("1つ目の文字列は2つ目の文字列より<span style="--marker-custom-color: #ffcccc;" class="marker-custom">辞書順で前</span>です。\n");
} else {
printf("1つ目の文字列は2つ目の文字列より<span style="--marker-custom-color: #ffcccc;" class="marker-custom">辞書順で後ろ</span>です。\n");
}
return 0;
}
1つ目の文字列を入力してください: apple
2つ目の文字列を入力してください: banana
1つ目の文字列は2つ目の文字列より辞書順で前です。
この例では、strcmpの戻り値を3種類の条件分岐で処理する典型的な書き方を確認できます。
if文とstrcmpを組み合わせた条件分岐
実際のプログラムでは、2つの文字列が「同じかどうか」だけを判定したいケースが多く、その場合は戻り値が0かどうかをチェックします。
ここでは、ユーザに「yes」か「no」を入力してもらう簡単な例を見てみます。
#include <stdio.h>
#include <string.h>
int main(void) {
char answer[10];
printf("処理を続行しますか?(yes/no): ");
scanf("%9s", answer);
// strcmpで「yes」かどうかを判定
if (strcmp(answer, "yes") == 0) {
printf("続行します。\n");
} else if (strcmp(answer, "no") == 0) {
printf("中止します。\n");
} else {
printf("不明な入力です。\n");
}
return 0;
}
実行例は次の通りです。
処理を続行しますか?(yes/no): yes
続行します。
ここでのポイントは、「等しい場合だけを判定したいならif (strcmp(a, b) == 0)と書く」というパターンをしっかり覚えておくことです。
メニュー選択やコマンド判定にstrcmpを使う例
少し実用的な例として、文字列でメニューやコマンドを選ぶ簡単なインターフェースを考えてみます。
メニュー番号を整数ではなく文字列で受け取って判定するパターンです。
#include <stdio.h>
#include <string.h>
int main(void) {
char command[20];
printf("コマンドを入力してください(help/list/exit): ");
scanf("%19s", command);
if (strcmp(command, "help") == 0) {
printf("ヘルプを表示します。\n");
} else if (strcmp(command, "list") == 0) {
printf("項目を一覧表示します。\n");
} else if (strcmp(command, "exit") == 0) {
printf("プログラムを終了します。\n");
} else {
printf("不明なコマンドです。\n");
}
return 0;
}
出力例は次のようになります。
コマンドを入力してください(help/list/exit): list
項目を一覧表示します。
このように、文字列を使ったメニューやコマンド判定ではstrcmpが中心的な役割を果たします。
実際のアプリケーションでも同様のパターンが多く使われています。
大文字小文字を区別する比較と区別しない比較
標準のstrcmpは大文字と小文字を区別します。
つまり、"YES"と"yes"は別の文字列として扱われます。
#include <stdio.h>
#include <string.h>
int main(void) {
char s1[] = "YES";
char s2[] = "yes";
int result = strcmp(s1, s2);
printf("strcmp(\"%s\", \"%s\") = %d\n", s1, s2, result);
if (result == 0) {
printf("同じと判定されました。\n");
} else {
printf("違うと判定されました。\n");
}
return 0;
}
出力結果の一例です。
strcmp("YES", "yes") = -32 // などの負の値
違うと判定されました。
ユーザ入力では、大文字小文字を区別しないで判定したいことが多いため、その場合は次のような方法があります。
1つ目は、入力文字列をすべて小文字(または大文字)に変換してからstrcmpする方法です。
#include <stdio.h>
#include <string.h>
#include <ctype.h> // tolowerを使うために必要
// 文字列をすべて小文字に変換する関数
void to_lower_str(char *s) {
for (int i = 0; s[i] != '#include <stdio.h>
#include <string.h>
#include <ctype.h> // tolowerを使うために必要
// 文字列をすべて小文字に変換する関数
void to_lower_str(char *s) {
for (int i = 0; s[i] != '\0'; i++) {
s[i] = (char)tolower((unsigned char)s[i]);
}
}
int main(void) {
char answer[10];
printf("処理を続行しますか?(yes/no): ");
scanf("%9s", answer);
// 入力をすべて小文字に変換してから比較
to_lower_str(answer);
if (strcmp(answer, "yes") == 0) {
printf("続行します。\n");
} else if (strcmp(answer, "no") == 0) {
printf("中止します。\n");
} else {
printf("不明な入力です。\n");
}
return 0;
}
'; i++) {
s[i] = (char)tolower((unsigned char)s[i]);
}
}
int main(void) {
char answer[10];
printf("処理を続行しますか?(yes/no): ");
scanf("%9s", answer);
// 入力をすべて小文字に変換してから比較
to_lower_str(answer);
if (strcmp(answer, "yes") == 0) {
printf("続行します。\n");
} else if (strcmp(answer, "no") == 0) {
printf("中止します。\n");
} else {
printf("不明な入力です。\n");
}
return 0;
}
実行例の一つは次の通りです。
処理を続行しますか?(yes/no): YeS
続行します。
環境によってはstrcasecmpやstricmpといった大文字小文字を無視して比較する関数が用意されている場合もありますが、これらは標準Cではないため、移植性を意識するなら自前で大文字小文字をそろえる方法を覚えておくとよいです。
strncmpとの違いと安全な文字列比較
strncmpとは
strncmpは、指定した文字数までを比較する文字列比較関数です。
宣言は次の通りです。
int strncmp(const char *s1, const char *s2, size_t n);
strcmpとの違いは、nという引数がある点です。
最大でn文字までしか比較しないため、長い文字列同士の比較や、バッファサイズを意識した安全な比較に役立ちます。
strcmpとstrncmpの違い
両者の違いを整理すると次のようになります。
| 関数名 | 比較範囲 | 用途のイメージ |
|---|---|---|
| strcmp | 文字列終端の'\0'まで全て | 文字列全体が同じか、辞書順を正確に調べたいとき |
| strncmp | 最大n文字まで | 先頭の一部だけ比較したいとき、長さ制限したいとき |
例えば、コマンドの先頭だけを判定するケースを考えてみます。
#include <stdio.h>
#include <string.h>
int main(void) {
char cmd[100];
printf("コマンドを入力してください(例: show, showall): ");
scanf("%99s", cmd);
// 先頭4文字が"show"かどうかを判定
if (strncmp(cmd, "show", 4) == 0) {
printf("show系コマンドが入力されました。\n");
} else {
printf("show系ではないコマンドです。\n");
}
return 0;
}
出力例の1つは次のようになります。
コマンドを入力してください(例: show, showall): showall
show系コマンドが入力されました。
このように、先頭だけを比較したいときや、比較する文字数を制限したいときにはstrncmpが適しています。
バッファオーバーランを防ぐためのstrncmpの使いどころ
C言語では、文字列バッファ(配列)のサイズを超えてアクセスしてしまうバッファオーバーランが重大なバグや脆弱性の原因になります。
strcmpは終端の'\0'まで読み続けるため、もし文字列が正しく終端されていない場合、意図しないメモリ領域まで読んでしまう危険があります。
一方、strncmpを使えば、最大でn文字までしかアクセスしないため、ある程度安全性を高めることができます。
例えば、外部から受け取ったデータを比較する場合に、想定より長いデータが来る可能性を考慮して、バッファサイズまでしか比較しないようにする、といった使い方が考えられます。
次の例では、バッファサイズを意識しながら比較する様子を示します。
#include <stdio.h>
#include <string.h>
int main(void) {
char buf[8];
printf("文字列を入力してください(最大7文字): ");
scanf("%7s", buf);
// bufは最大7文字 + '#include <stdio.h>
#include <string.h>
int main(void) {
char buf[8];
printf("文字列を入力してください(最大7文字): ");
scanf("%7s", buf);
// bufは最大7文字 + '\0'の8バイト
// 比較時も最大7文字までに制限しておくと安全側になる
if (strncmp(buf, "secret", sizeof(buf) - 1) == 0) {
printf("シークレットワードが入力されました。\n");
} else {
printf("別の文字列が入力されました。\n");
}
return 0;
}
'の8バイト
// 比較時も最大7文字までに制限しておくと安全側になる
if (strncmp(buf, "secret", sizeof(buf) - 1) == 0) {
printf("シークレットワードが入力されました。\n");
} else {
printf("別の文字列が入力されました。\n");
}
return 0;
}
このように、入力の長さが想定より長くなるかもしれない場合は、strncmpで比較範囲を制限することが安全性向上につながります。
比較する文字数(n)をどう決めるかの考え方
strncmpで指定するnの値は、適当に決めるのではなく、次のような観点から決めるとよいです。
- バッファサイズを超えないこと
比較する文字列が格納されている配列のサイズを超えないようにnを設定します。一般的にはn <= sizeof(配列) - 1とします。 - 識別に十分な文字数かどうか
例えばコマンド名が"show"と"showall"だけなら4文字で十分に区別できますが、他に"sh"や"short"が存在する設計なら、比較文字数を増やす必要があります。 - パフォーマンスも意識する
非常に長い文字列同士を比較する場合、必要な範囲だけを比較することで、無駄な処理を減らせる場合があります。
例として、コマンドが「先頭3文字で識別できる」という仕様にしておき、その前提で比較する書き方を示します。
#include <stdio.h>
#include <string.h>
int main(void) {
char cmd[20];
printf("コマンドを入力してください(add/del/listなど): ");
scanf("%19s", cmd);
// 先頭3文字だけで判定する(仕様として3文字で一意に決まると仮定)
if (strncmp(cmd, "add", 3) == 0) {
printf("追加コマンドが選択されました。\n");
} else if (strncmp(cmd, "del", 3) == 0) {
printf("削除コマンドが選択されました。\n");
} else if (strncmp(cmd, "lis", 3) == 0) {
printf("一覧コマンドが選択されました。\n");
} else {
printf("不明なコマンドです。\n");
}
return 0;
}
このように、nは「安全な範囲」と「仕様上識別に必要な長さ」の両方を満たすように決めるとよいです。
strcmpでよくあるエラーと注意点
strcmpの戻り値を==1などと比較してしまう間違い
初心者が特につまずきやすいのが、strcmpの戻り値を具体的な数値(1や-1など)と比較してしまう間違いです。
次のようなコードは誤りです。
#include <stdio.h>
#include <string.h>
int main(void) {
char a[] = "apple";
char b[] = "banana";
// 間違った書き方の例
if (strcmp(a, b) == -1) {
printf("aの方が小さいと判定されました。\n");
}
return 0;
}
strcmpの戻り値は「負の値」「0」「正の値」の3パターンだけが保証されており、具体的に-1や1になるとは限りません。
そのため、比較するときは次のように書く必要があります。
#include <stdio.h>
#include <string.h>
int main(void) {
char a[] = "apple";
char b[] = "banana";
int result = strcmp(a, b);
if (result < 0) {
printf("aの方が小さいと判定されました。\n");
} else if (result == 0) {
printf("同じと判定されました。\n");
} else {
printf("aの方が大きいと判定されました。\n");
}
return 0;
}
strcmpの戻り値は「3つの範囲」だけを見ると覚えておくと、この種のバグを防げます。
NULLポインタや未初期化ポインタをstrcmpに渡す危険性
strcmpの引数は有効な文字列へのポインタでなければなりません。
つまり、NULLを指していたり、どこを指しているか分からない未初期化ポインタを渡してはいけません。
次のようなコードは非常に危険です。
#include <stdio.h>
#include <string.h>
int main(void) {
char *p; // 初期化されていないポインタ
char s[] = "test";
// 未初期化ポインタをstrcmpに渡している(未定義動作)
if (strcmp(p, s) == 0) {
printf("同じです。\n");
}
return 0;
}
このコードはコンパイル自体は通るかもしれませんが、実行時にクラッシュしたり、予測不能な挙動を示す未定義動作になります。
安全に使うためには、次のような点を守る必要があります。
- ポインタは必ずどこかの有効な領域を指すように初期化してから使う
- 場合によっては、呼び出し前に
if (p != NULL)のようなチェックを入れる
次の例は、安全な使い方の一例です。
#include <stdio.h>
#include <string.h>
int main(void) {
char s1[] = "hello";
char s2[] = "world";
char *p1 = s1; // s1を指すように初期化
char *p2 = s2; // s2を指すように初期化
if (p1 != NULL && p2 != NULL) {
if (strcmp(p1, p2) == 0) {
printf("同じ文字列です。\n");
} else {
printf("異なる文字列です。\n");
}
} else {
printf("ポインタがNULLです。\n");
}
return 0;
}
「strcmpはポインタそのものの妥当性まではチェックしてくれない」ことを理解し、呼び出し側で責任を持って管理する必要があります。
文字列終端(‘\0’)が抜けていて比較結果がおかしくなるケース
C言語の文字列は、必ず最後に'\0'が付いている必要があります。
もし終端文字が抜けていると、strcmpは'\0'に出会うまで延々とメモリを読み続けてしまいます。
その結果、比較結果がおかしくなったり、最悪の場合クラッシュすることもあります。
終端が抜けてしまう典型的な例として、文字配列を自前で操作するときが挙げられます。
#include <stdio.h>
#include <string.h>
int main(void) {
char s1[5];
char s2[5];
// 終端'#include <stdio.h>
#include <string.h>
int main(void) {
char s1[5];
char s2[5];
// 終端'\0'を入れ忘れている例(危険なコード)
s1[0] = 't';
s1[1] = 'e';
s1[2] = 's';
s1[3] = 't';
// s1[4]に'\0'を設定していない
strcpy(s2, "test"); // s2は正しく終端されている
// s1は文字列として正しく終端されていないため、strcmpは危険
int result = strcmp(s1, s2);
printf("result = %d\n", result);
return 0;
}
'を入れ忘れている例(危険なコード)
s1[0] = 't';
s1[1] = 'e';
s1[2] = 's';
s1[3] = 't';
// s1[4]に'#include <stdio.h>
#include <string.h>
int main(void) {
char s1[5];
char s2[5];
// 終端'\0'を入れ忘れている例(危険なコード)
s1[0] = 't';
s1[1] = 'e';
s1[2] = 's';
s1[3] = 't';
// s1[4]に'\0'を設定していない
strcpy(s2, "test"); // s2は正しく終端されている
// s1は文字列として正しく終端されていないため、strcmpは危険
int result = strcmp(s1, s2);
printf("result = %d\n", result);
return 0;
}
'を設定していない
strcpy(s2, "test"); // s2は正しく終端されている
// s1は文字列として正しく終端されていないため、strcmpは危険
int result = strcmp(s1, s2);
printf("result = %d\n", result);
return 0;
}
このようなコードは、動くかもしれないが、偶然動いているだけであり、完全な未定義動作です。
必ず次のように'\0'をセットして、文字列終端を保証しなければなりません。
s1[0] = 't';
s1[1] = 'e';
s1[2] = 's';
s1[3] = 't';
s1[4] = 's1[0] = 't';
s1[1] = 'e';
s1[2] = 's';
s1[3] = 't';
s1[4] = '\0'; // 文字列終端を明示的にセット
'; // 文字列終端を明示的にセット
「自前で配列に文字を設定したときは、最後に必ず'\0'を入れる」という習慣を身につけることで、この種のバグを避けられます。
全角文字やマルチバイト文字をstrcmpで扱うときの注意点
日本語の全角文字など、多くの環境ではマルチバイト文字として扱われます。
マルチバイト文字は、1文字を表現するのに2バイト以上を使うことがあり、strcmpはそれを単なるバイト列として扱います。
つまり、strcmpは「文字」単位ではなく「バイト」単位で比較していると理解する必要があります。
そのため、文字コードやロケール設定によっては、「日本語として正しい順番」になっていないように見える結果になることがあります。
簡単な例として、マルチバイト文字を使った比較を考えます。
#include <stdio.h>
#include <string.h>
int main(void) {
// 環境によっては、文字コードやロケールの設定が必要
char s1[] = "あい";
char s2[] = "あお";
int result = strcmp(s1, s2);
printf("strcmp(\"%s\", \"%s\") = %d\n", s1, s2, result);
if (result == 0) {
printf("同じ文字列です。\n");
} else if (result < 0) {
printf("\"%s\"の方が前と判定されました。\n", s1);
} else {
printf("\"%s\"の方が前と判定されました。\n", s2);
}
return 0;
}
出力結果や比較順序は、使用している文字コード(UTF-8、Shift_JISなど)やロケール設定によって変わる可能性があります。
「日本語としての辞書順」を正しく扱いたい場合は、strcmpだけでは不十分であり、ロケールを意識した関数やワイド文字(wchar_t)向けの関数、さらには専用ライブラリが必要になる場合があります。
初心者のうちは、strcmpはあくまでバイト列の比較であり、マルチバイト文字の日本語順序とは一致しないことがあると理解しておくとよいです。
デバッグのポイント
strcmpまわりでバグが出たときには、次のポイントを順番に確認していくと原因を特定しやすくなります。
1つ目は、「本当に文字列の内容を比較しているかどうか」です。
誤って==演算子でポインタ同士を比較していないかを確認します。
特に、if (s == "yes")のようなコードになっていないかチェックします。
2つ目は、ポインタや配列の有効性です。
ポインタがNULLになっていないか、未初期化のまま使っていないか、配列の寿命(スコープ外になっていないか)を確認します。
デバッガでポインタのアドレスを表示してみるのも有効です。
3つ目は、文字列終端'\0'の有無です。
自前で文字を代入した配列に、きちんと終端文字が入っているかを確認します。
デバッガで配列の中身を表示し、想定通りの位置に0('\0')があるかを見るとよいです。
4つ目は、戻り値の判定です。
== 1や== -1のような比較をしていないか、== 0、< 0、> 0の3種類だけに整理されているかを確認します。
デバッグの際には、次のようにprintfで文字列と戻り値を表示しながら原因を探ると、問題の箇所を特定しやすくなります。
#include <stdio.h>
#include <string.h>
void debug_compare(const char *s1, const char *s2) {
if (s1 == NULL) {
printf("s1はNULLです\n");
return;
}
if (s2 == NULL) {
printf("s2はNULLです\n");
return;
}
int result = strcmp(s1, s2);
printf("s1 = \"%s\"\n", s1);
printf("s2 = \"%s\"\n", s2);
printf("strcmp(s1, s2) = %d\n", result);
if (result == 0) {
printf("→ 同じ文字列です。\n");
} else if (result < 0) {
printf("→ s1の方が辞書順で前です。\n");
} else {
printf("→ s1の方が辞書順で後ろです。\n");
}
}
int main(void) {
debug_compare("apple", "banana");
debug_compare("test", "test");
debug_compare("zoo", "ant");
return 0;
}
出力例は次のようになります。
s1 = "apple"
s2 = "banana"
strcmp(s1, s2) = -1
→ s1の方が辞書順で前です。
s1 = "test"
s2 = "test"
strcmp(s1, s2) = 0
→ 同じ文字列です。
s1 = "zoo"
s2 = "ant"
strcmp(s1, s2) = 25
→ s1の方が辞書順で後ろです。
このように、比較対象の文字列とstrcmpの戻り値を一緒に出力することで、どのように比較されているかが視覚的に分かり、バグの原因を発見しやすくなります。
まとめ
strcmpは、C言語で文字列を扱う上で欠かせない基本かつ重要な関数です。
ポインタ同士を==で比較してしまう誤りや、戻り値を== 1のように扱う間違い、終端'\0'の付け忘れなど、初心者が陥りやすいポイントも多くあります。
本記事で説明したように、strcmpの戻り値の意味、文字列終端の重要性、NULLポインタの危険性、strncmpとの違いと使い分けをしっかり理解しておくことで、安全で読みやすい文字列比較が行えるようになります。
実際に手を動かしてサンプルコードを書き、動作を確認しながら、少しずつ慣れていってください。
