【2026年7月最新】C言語の文字列比較を完全解説!strcmp・strncmp・strcasecmpの使い方とバグパターン・Claude Codeで即解決
この記事の内容
C言語の文字列比較は、「==演算子が使えない」「戻り値が0・正・負の3種類」「バッファオーバーフローのリスクがある」など、他の言語と異なる罠が多い領域です。本記事ではC言語のstrcmp・strncmp・strcasecmp等の文字列比較関数を完全解説し、よくあるバグパターンと修正方法を実際のコード例付きで解説します。
後半では、Claude Codeを使ってCプログラムのバグを自動診断・修正する方法も紹介します。「セグメンテーションフォルト(Segfault)の原因がわからない」「バッファオーバーフローが起きている場所を特定したい」という方はぜひ参考にしてください。
01 BASICS C言語の文字列と比較の基礎 char配列・ポインタ・ヌル文字終端の理解が全ての出発点
C言語では「String型」という型は存在しません。文字列はchar型の配列として扱われ、最後に必ずヌル文字('\0')が置かれます。このヌル文字が文字列の終端を示すシグナルです。
// C言語での文字列の基本
char str1[] = "hello"; // = {'h','e','l','l','o','\0'}
char str2[] = "hello";
// ==はポインタ比較(アドレスを比較)するため、文字列比較には使えない
if (str1 == str2) { // これは文字列が同じかどうかの比較ではない!
// 多くの場合falseになる(str1とstr2は別の配列のため)
}
// 正しい文字列比較はstrcmpを使う
#include <string.h>
if (strcmp(str1, str2) == 0) {
printf("文字列は同じです\n");
}
📚 用語解説
ヌル文字(Null Character / \0):C言語で文字列の終わりを示す特殊な文字。ASCII値は0(ゼロ)で、コードでは'\0'と書く。C言語の文字列処理関数(strlen・strcmp・strcat等)はすべてこのヌル文字で文字列の終わりを判断する。ヌル文字がない文字列を処理すると、関数がどこまでも読み続けてバッファオーバーフローやセグメンテーションフォルトの原因になる。
C言語で文字列比較に==が使えない理由は、==演算子が「文字列の内容」ではなく「ポインタのアドレス(配列が格納されているメモリ上の場所)」を比較するからです。異なる変数に同じ文字列「hello」を代入した場合、内容は同じでも別のメモリ領域に存在するため、==はfalseを返します。
📚 用語解説
ポインタ(Pointer):メモリ上のアドレス(番地)を値として持つ変数。C言語では配列変数は「配列の先頭要素のアドレス」として扱われる。「char *str = "hello"」と書くと、strは文字列"hello"が格納されたメモリアドレスを指す。==演算子でポインタ同士を比較すると、「同じメモリ上の同じ場所を指しているか」が比較される(内容の比較ではない)。
文字列を格納
が末尾に自動付加
内容を比較
一致と判定
02 STRCMP strcmpの使い方:戻り値と比較の仕組み 0・正・負の戻り値の意味を正確に理解する
strcmp()はstring.hヘッダで提供されるC標準ライブラリ関数で、2つの文字列を辞書順(文字コード順)で比較します。プロトタイプはint strcmp(const char *s1, const char *s2);です。
📚 用語解説
strcmp()の戻り値:strcmp(s1, s2)が返す整数値の意味:①0 = s1とs2の文字列が完全に一致している ②負の値 = s1がs2より辞書順で前(s1の文字コードがs2より小さい) ③正の値 = s1がs2より辞書順で後(s1の文字コードがs2より大きい)。重要:具体的な正負の値は処理系依存で、-1や1とは限らない。「== 0」「< 0」「> 0」という形で判定するのが正確。
#include <stdio.h>
#include <string.h>
int main() {
char s1[] = "apple";
char s2[] = "apple";
char s3[] = "banana";
char s4[] = "APPLE"; // 大文字
// 完全一致
printf("%d\n", strcmp(s1, s2)); // 0(一致)
// s1が辞書順で前
printf("%d\n", strcmp(s1, s3)); // 負の値(appleはbananaより前)
// s3が辞書順で前
printf("%d\n", strcmp(s3, s1)); // 正の値(bananaはappleより後)
// 大文字小文字を区別する
printf("%d\n", strcmp(s1, s4)); // 正の値(小文字aは大文字Aより文字コードが大きい)
return 0;
}
strcmpの正しい使い方パターン
// パターン1:一致確認(最も一般的)
if (strcmp(str1, str2) == 0) {
printf("一致\n");
}
// パターン2:辞書順の前後確認
if (strcmp(str1, str2) < 0) {
printf("str1がstr2より辞書順で前\n");
} else if (strcmp(str1, str2) > 0) {
printf("str1がstr2より辞書順で後\n");
} else {
printf("同じ\n");
}
// パターン3:コマンドライン引数の判定
int main(int argc, char *argv[]) {
if (argc > 1 && strcmp(argv[1], "--help") == 0) {
printf("ヘルプを表示します\n");
}
return 0;
}
C言語初心者が頻繁に犯す誤りが「strcmp()が0以外(trueと評価される値)を返したら一致」という勘違いです。実際は逆で、「0 = 一致、0以外 = 不一致」です。「if (strcmp(a, b))」はstrcmpが0以外を返したとき(つまり文字列が不一致のとき)にtrueになります。一致を確認したいなら「if (strcmp(a, b) == 0)」と明示的に書いてください。
03 STRNCMP strncmpの使い方:文字数を指定して比較 先頭N文字だけを比較してバッファオーバーフローを防ぐ
strncmp()はstrcmp()の安全版です。プロトタイプはint strncmp(const char *s1, const char *s2, size_t n);で、第3引数nで比較する最大文字数を指定します。
#include <stdio.h>
#include <string.h>
int main() {
char s1[] = "apple_pie";
char s2[] = "apple_cake";
// 先頭5文字だけを比較("apple"の部分)
int result = strncmp(s1, s2, 5);
printf("%d\n", result); // 0(先頭5文字は同じ)
// 全体を比較
result = strncmp(s1, s2, 10);
printf("%d\n", result); // 0以外(_pieと_cakeで違う)
// 1文字だけ比較
result = strncmp(s1, s2, 1);
printf("%d\n", result); // 0(先頭の'a'は同じ)
return 0;
}
strncmpを使うべき場面
strncmpが特に有効なのは以下のような場面です:①プロトコル・コマンドのプレフィックス確認(「GETで始まるHTTPリクエストか」など)②バッファオーバーフローを防ぎたい場合③固定長フィールドを比較する場合。
// HTTPメソッドの判定
char request[] = "GET /index.html HTTP/1.1";
if (strncmp(request, "GET", 3) == 0) {
printf("GETリクエストです\n");
} else if (strncmp(request, "POST", 4) == 0) {
printf("POSTリクエストです\n");
}
// コマンドのプレフィックス確認
char cmd[] = "quit_now";
if (strncmp(cmd, "quit", 4) == 0) {
printf("終了コマンドが入力されました\n");
}
📚 用語解説
バッファオーバーフロー(Buffer Overflow):配列(バッファ)の境界を超えてメモリに書き込む・読み込む脆弱性。C言語では文字列の長さチェックをプログラマが明示的に行わないと発生しやすい。例えばstrcpy(dest, src)でsrcがdestより長い場合、destのバッファを超えた部分のメモリが上書きされ、プログラムのクラッシュやセキュリティ侵害(任意コードの実行)につながる。strncpyやstrncat等のn系関数でサイズ制限をかけることが基本的な対策。
strncmpの安全な使い方として「比較する2つの文字列のうち、バッファが小さい方のサイズ」を第3引数に使うパターンが推奨されます。sizeof()やstrlen()で算出した値を使うことで、意図せず配列範囲外をアクセスするリスクを下げられます。
04 FUNCTIONS その他の文字列比較関数:strcasecmp・memcmp等 POSIX関数・メモリ比較・大文字小文字無視の使い分け
| 関数名 | ヘッダ | 用途 | 注意点 |
|---|---|---|---|
| strcmp(s1, s2) | string.h | 大文字小文字区別の完全比較 | n系の使用を推奨 |
| strncmp(s1, s2, n) | string.h | n文字までの比較 | C標準・安全 |
| strcasecmp(s1, s2) | strings.h | 大文字小文字無視の比較 | POSIX(Windows非対応) |
| strncasecmp(s1, s2, n) | strings.h | 大文字小文字無視・n文字まで | POSIX(Windows非対応) |
| _stricmp(s1, s2) | string.h | Windows版strcasecmp | MSVC専用(非移植) |
| memcmp(p1, p2, n) | string.h | バイナリデータのn byte比較 | ヌル文字で止まらない |
| wcscmp(s1, s2) | wchar.h | ワイド文字(Unicode)の比較 | マルチバイト文字に使用 |
strcasecmp():大文字小文字を無視して比較
strcasecmp()はPOSIX規格の関数で、大文字小文字を区別せずに文字列を比較します。Linuxとmacで使えますが、Windowsではデフォルトでは使えない点に注意が必要です。
#include <strings.h> // POSIX(Linux/Mac)
char input[] = "YES";
char expected[] = "yes";
if (strcasecmp(input, expected) == 0) {
printf("一致(大文字小文字無視)\n"); // 出力される
}
// Windows (MSVC) では _stricmp を使う
#ifdef _WIN32
#define strcasecmp _stricmp
#endif
memcmp():バイナリデータの比較
memcmp()は文字列ではなく任意のメモリ領域をバイト単位で比較します。ヌル文字(\0)で停止せず、指定したバイト数だけ比較する点がstrcmpと大きく異なります。画像・音声・バイナリプロトコルなど、テキスト以外のデータ比較に使います。
#include <stdio.h>
#include <string.h>
int main() {
// 通常のテキスト比較
char s1[] = "hello\0world"; // ヌル文字を含む
char s2[] = "hello\0earth";
// strcmpはヌル文字で止まるので"hello"までしか比較しない
printf("strcmp: %d\n", strcmp(s1, s2)); // 0(helloまで一致)
// memcmpは12バイト全部を比較する
printf("memcmp: %d\n", memcmp(s1, s2, 12)); // 0以外(worldとearthで違う)
// バイナリデータの比較
unsigned char hash1[] = {0x1a, 0x2b, 0x3c, 0x4d};
unsigned char hash2[] = {0x1a, 0x2b, 0x3c, 0x4d};
if (memcmp(hash1, hash2, 4) == 0) {
printf("ハッシュ値が一致\n");
}
return 0;
}
→ strcmp
→ strcasecmp
→ strncmp
→ memcmp
05 BUG PATTERNS よくあるバグパターン10選と修正方法 C言語のString比較で現場が頻繁にハマる落とし穴
C言語の文字列比較では定番のバグパターンがあります。以下の10パターンを理解しておけば、デバッグ時間を大幅に短縮できます。
パターン1:==で文字列を比較する
// NG
char s1[] = "hello";
char s2[] = "hello";
if (s1 == s2) { ... } // ポインタ比較になる
// OK
if (strcmp(s1, s2) == 0) { ... }
パターン2:strcmpの戻り値の意味を逆に解釈する
// NG(一致を確認したいのに不一致時に実行される)
if (strcmp(s1, s2)) {
printf("一致しました\n"); // 実際は不一致のときに実行される
}
// OK
if (strcmp(s1, s2) == 0) {
printf("一致しました\n");
}
パターン3:ヌル文字が付いていない文字列を比較する
// NG(ヌル文字がないとstrcmpがどこまでも読み続ける)
char s[5] = {'h', 'e', 'l', 'l', 'o'}; // ヌル文字がない!
strcmp(s, "hello"); // 未定義動作(バッファ外を読む)
// OK
char s[6] = {'h', 'e', 'l', 'l', 'o', '\0'}; // ヌル文字を明示
// または
char s[] = "hello"; // リテラルは自動的にヌル文字が付く
パターン4:NULLポインタをstrcmpに渡す
// NG(NULLをstrcmpに渡すとセグメンテーションフォルト)
char *s = NULL;
if (strcmp(s, "hello") == 0) { ... } // SEGFAULT
// OK(NULLチェックを先に行う)
if (s != NULL && strcmp(s, "hello") == 0) { ... }
パターン5:strncmpのn=0を使う
// 注意:n=0のstrncmpは常に0を返す
if (strncmp(s1, s2, 0) == 0) {
// 常にtrueになる。意図していた比較は行われない
}
パターン6:バッファサイズを超えたstrncmpのn指定
// NG(bufferのサイズを超えたn指定)
char buffer[10];
strncmp(buffer, "very long string here", 50); // bufferは10バイトしかない
// OK(小さい方のサイズを使う)
strncmp(buffer, "target", sizeof(buffer) - 1);
パターン7:strcasecmpをWindowsで使おうとする
// NG(WindowsのMSVCではコンパイルエラー)
#include <strings.h>
strcasecmp(s1, s2);
// OK(プラットフォーム対応マクロを使う)
#ifdef _WIN32
#define strcasecmp _stricmp
#else
#include <strings.h>
#endif
strcasecmp(s1, s2); // これなら両方で動く
パターン8:strlenの戻り値をsize_t型で扱わない
// NG(size_tはunsignedなので、0から引くと大きな正の数になる)
int n = strlen(s1) - strlen(s2); // s2が長ければ巨大な数になる
if (n < 0) { ... } // 意図通りに動かない
// OK(型を意識する)
size_t len1 = strlen(s1);
size_t len2 = strlen(s2);
if (len1 < len2) { printf("s1の方が短い\n"); }
else if (len1 > len2) { printf("s1の方が長い\n"); }
else { /* 長さが同じ */ }
パターン9:初期化されていない配列を比較する
// NG(未初期化の配列はランダムなデータが入っている)
char buffer[100]; // 初期化なし
if (strcmp(buffer, "hello") == 0) { ... } // 未定義動作
// OK(memsetで初期化)
char buffer[100];
memset(buffer, 0, sizeof(buffer)); // 全バイトを0で初期化
パターン10:Unicode・マルチバイト文字をchar*で比較する
// NG(日本語等のマルチバイト文字をstrcmpで比較すると文字化けや誤判定)
char japanese[] = "こんにちは";
if (strcmp(japanese, "こんにちは") == 0) { ... } // 動くが移植性に問題
// OK(ワイド文字列を使う)
#include <wchar.h>
wchar_t ws1[] = L"こんにちは";
wchar_t ws2[] = L"こんにちは";
if (wcscmp(ws1, ws2) == 0) { ... }
06 CLAUDE CODE Claude CodeでCのバグを即診断・修正する方法 手動デバッグの10分の1の時間で根本原因を特定
C言語のバグ(特にセグメンテーションフォルト・バッファオーバーフロー)は原因特定が難しく、熟練エンジニアでも調査に時間がかかります。Claude Codeを活用することで、この診断プロセスを大幅に高速化できます。
セグメンテーションフォルトの原因をClaude Codeで特定
「Segmentation fault (core dumped)」が出たとき、Claude Codeにコードを渡して「このCコードのセグメンテーションフォルトの原因を特定して修正して」と指示するだけで、原因分析が完了します。
# Claude Codeへの指示例
「以下のCコードでSegfaultが発生しています。
原因を特定し、修正後の安全なコードを提示してください。
特にNULLポインタ・バッファオーバーフロー・
未初期化変数・ヌル文字欠落の観点で確認してください。
[ここにCコードを貼り付ける]」
文字列比較バグのパターンをプロジェクト全体でスキャン
プロジェクト全体のCコードを対象に「==を使った文字列比較を全て見つけてstrcmpに修正して」という指示をClaude Codeに与えることで、手動grepとは比べ物にならない精度でバグパターンを検出できます。
# Claude Codeへの指示例
「このCプロジェクトの全ソースファイルを読んで、
以下のバグパターンを全て検出して修正案を提示してください:
1. ==演算子でcharポインタを比較している箇所
2. NULLチェックなしでstrlen/strcmpを呼んでいる箇所
3. strncmpを使わずstrcmpで外部入力を比較している箇所
4. バッファサイズを超える可能性があるstrncmpのn指定」
Claude Codeによる静的解析とvalgrindの連携
valgrindは実行時のメモリエラーを検出するツールです。Claude Codeはvalgrindの出力を読み込んで「このvalgrindの出力が示すメモリリーク・バッファ読み越しのコード上の原因を特定して修正して」という形で活用できます。開発環境にvalgrindがある場合、Claude Codeと組み合わせることでCのメモリ関連バグのデバッグ効率が劇的に向上します。特に大規模なCプロジェクトで「どのファイルの何行目のstrcmpがNULLチェックを欠落させているか」を人手で調べるのは膨大な時間がかかりますが、Claude Codeに「全ソースを読んでNULLポインタのリスクがある文字列比較を全て列挙して」と指示することで数分で完了します。
📚 用語解説
valgrind:LinuxでCプログラムのメモリ関連エラーを検出する動的解析ツール。プログラムを実行しながら「メモリリーク(確保したメモリを解放しない)」「無効なメモリアクセス(バッファオーバーフロー・NULLポインタ参照)」「未初期化メモリの使用」などを自動検出する。「valgrind ./myprogram」というコマンドで実行するだけで使えるため、C言語開発の必須ツールとして知られている。
C言語のレガシーシステムの品質改善・Claude Codeを使ったコード自動レビュー導入について、弊社AI鬼管理では個別相談を承っています。C言語の組み込みシステム・基幹システムのAI活用についてもご相談ください。
NEXT STEP
この記事の内容を、あなたのビジネスで
実践してみませんか?
AI活用を自社で回せるようになりたい方へ
AI鬼管理
Claude Code・Cowork導入支援から業務設計・社内浸透まで実践ベースで伴走。「自社で回せる組織」を90日で作る経営者向けトレーニング。
よくある質問
Q. C言語でstrcmpとstrncmpどちらを使うべきですか?
A. 外部からの入力(ユーザー入力・ネットワークデータ・ファイルからの読み込み)を比較する場合は必ずstrncmpを使い、比較する最大文字数を明示してください。コード内の定数リテラルとの比較など、長さが保証できる場合はstrcmpで問題ありません。迷ったらstrncmpという方針が最も安全です。
Q. C言語で大文字小文字を無視して文字列比較するには?
A. Linux・macOSではstrcasecmp()(strings.hをインクルード)が使えます。Windowsでは_stricmp()(string.h)を使います。クロスプラットフォームなコードを書く場合は、#ifdefマクロでプラットフォームを判定してどちらかに切り替えるか、tolower()を使って比較前に文字列を小文字に変換するアプローチが使われます。
Q. C言語でstrcmpがあるのにmemcmpが必要な理由は何ですか?
A. strcmpはヌル文字(\0)で比較を停止しますが、memcmpは指定したバイト数をそのまま比較します。バイナリデータ・ヌル文字を含むデータ・固定長フィールドなど「テキスト文字列でないデータ」を比較するにはmemcmpが必要です。例えばハッシュ値(sha256は32バイトのバイナリ)の比較にstrcmpを使うと、最初の\0バイトで比較が止まり正しく動きません。
Q. C言語のstrcmpで日本語(マルチバイト文字)を比較できますか?
A. 技術的にはstrcmpで日本語文字列を比較できますが、移植性の問題があります。UTF-8エンコードの日本語はstrcmpで動くことが多いですが、Shift-JISやEUC等のロケール依存エンコードでは誤動作するケースがあります。ワイド文字(wchar_t)を使ってwcscmp()で比較するか、ロケール対応のstrcoll()を使う方が安全です。
Q. Claude CodeはC言語のデバッグに本当に使えますか?
A. はい、特に「バグパターンの検出と修正提案」「スタックトレース・valgrind出力の解析」「レガシーCコードのコードレビュー」に非常に有効です。コードをClaude Codeに渡して「セグメンテーションフォルトの原因を探して」「==でcharを比較している箇所を全て検出して」といった指示を与えることで、手動調査では時間がかかる作業を短時間で完了できます。
Q. セグメンテーションフォルト(Segfault)とバッファオーバーフローの違いは何ですか?
A. セグメンテーションフォルト(SIGSEGV)はプログラムが「アクセスしてはいけないメモリ領域」にアクセスしたときに発生するOSからのエラーシグナルです。バッファオーバーフローはその原因の一つで「配列の境界を超えてメモリに書き込む」ことでセグフォルトや他の未定義動作が起きます。NULLポインタ参照もセグフォルトの典型的な原因です。valgrindやClaude Codeを使った解析で根本原因を特定できます。
Q. C言語の文字列比較と現代のAIツールは関係がありますか?
A. C言語で書かれた組み込みシステム・OSカーネル・基幹システムは現在も多く稼働しています。Claude Codeはこれらのレガシーシステムのコードレビュー・バグ修正・リファクタリングに活用できます。また、AIや機械学習のライブラリ(TensorFlow等のコアC++部分)のデバッグにも同様の手法が使えます。「C言語の専門知識がなくてもClaude Codeがサポートする」という形で、AIがCシステムの保守コストを大幅に下げています。
Claude Codeで業務自動化を90日で叩き込む
経営者向けの伴走型パーソナルトレーニング
Claude Code を業務に落とし込む
専門研修コース一覧
受講者本人の業務を題材に、「使いこなせる」状態になるまで伴走する研修プログラム。1対1特化型・ハンズオン・法人講座の3コースを展開中。業務特化・実装まで踏み込むタイプのClaude Code研修です。
研修コース一覧を見る →AI鬼管理へのお問い合わせ
この記事を読んで気になった方へ。
AI鬼管理の専門スタッフが、御社に最適な
業務自動化プランを無料でご提案します。




