【C言語】strcmpで文字列の比較を行う

このページにはプロモーションが含まれています

このページでは、C言語において文字列の比較を行う方法について説明していきます。

プログラムを作っていると「特定の2つの文字列が一致するかどうかを判断したい」ようなケースに遭遇する機会も多いと思います。例えば、ユーザーの入力した文字列が事前に設定されたパスワードと一致するかどうかを判断するようなケースは分かりやすい例だと思います。

2つの文字列を比較する様子

C言語においては文字列の比較は標準ライブラリ関数である strcmp 関数を利用することが多いです。もちろん文字列の比較を行う処理を自力で記述して文字列の比較を実現することも可能ですが、このページでは関数を利用した文字列の比較について解説していきたいと思います。

また、C言語においては 文字列1 == 文字列2 のように == 演算子での文字列比較は行うことが出来ません。この理由についても、おまけとして解説していきたいと思います。

strcmp 関数を利用した文字列比較

このページの冒頭でも触れたように、C言語における文字列の比較は strcmp 関数を実行することで実現できます。

strcmp 関数

この strcmp 関数は文字列の比較を行い、その比較結果を返却する関数になります。大文字と小文字を区別して比較が行われます。string.h で宣言されており、strcmp 関数を利用する際には string.h をインクルードしておく必要があります。

strcmp 関数の引数・返却値

strcmp 関数の引数 / 返却値は下記のようになります。ちなみに、2つの文字列の文字列長が異なる場合は strcmp 関数は必ず 0 以外の値を返却することになります。

第1引数 const char *str1 文字列1
第2引数 const char *str2 文字列2
返却値 int

文字列1と文字列2の比較結果

  • 文字列1と文字列2が一致:0
  • それ以外:0 以外

C言語における文字列とは「ヌル文字('\0')で終端された char 型の配列(メモリ)」であり、strcmp 関数の第1引数と第2引数にはヌル文字('\0')で終端した char 型の配列の「配列名」や「配列の先頭を指すアドレス」を指定することが可能です。

strcmpの引数はヌル文字で終端されている秘帖があることを示す図

また、strcmp 関数では、第1引数と第2引数で指定した2つの文字列が一致した場合に 0 を返却します。なので、2つの文字列が一致するかどうかは返却値が 0 であるかどうかを確認することで判断することが可能です。

strcmpで文字列が一致するかを判断
if (strcmp(文字列1, 文字列2) == 0) {
    // 2つの文字列が一致していたときの処理
} else {
    // 2つの文字列が一致していないときの処理
}

また、2つの文字列が一致しない場合の返却値は 0 以外 の値となり、より具体的には、第2引数に対する第1引数の文字列の “アルファベット順的な前後関係” に応じて下記の値を返却するようになっています。そのため、この返却値から2つの文字列のどちらがアルファベット順的に前側にあるのか(あるいは後ろ側にあるのか)を判断することも可能です。

  • 正の値:文字列1が文字列2よりもアルファベット順的に後ろ
  • 負の値:文字列1が文字列2よりもアルファベット順的に前

このアルファベット順的な前後関係は、2つの文字列の先頭の文字から順に1文字ずつ比較を行うことで判断されるようになっています。これは実装依存かもしれませんが、おそらく各文字の文字コードの値で比較が行われます。

例えば、第1引数に "Hello"、第2引数に "Good" を指定した場合は、最初の文字の比較で H > G となるため(文字コードが)、strcmp は第1引数の文字列がアルファベット順的に後ろ側に存在すると判断して 正の値 を返却します。

strcmp関数が正の値を返却するケースの説明図

また、第1引数に "God"、第2引数に "Good" を指定した場合は、1つ目の文字の比較で G == G、2つ目の文字の比較で o == o となってここまでは一致しますが、3つ目の文字の比較で d < o となるため strcmp 関数は第1引数の文字列がアルファベット順的に前側に存在すると判断して負の値を返却します。

strcmp関数が負の値を変客するケースの説明図

さらに、第1引数に "Good"、第2引数に "Good" を指定した場合は、4つの文字全てが一致するため、strcmp 関数は2つの文字列が一致していると判断して 0 の値を返却します。

strcmp関数が0を返却するケースの説明図

こんな感じで、strcmp 関数では、2つの文字列の先頭の文字から順に1文字ずつ比較を行うことで、2つの文字列のアルファベット順的な前後関係に応じた返却値が返却されるようになっています。

MEMO

上記のソースコードのプログラムで最初に “スペースを含む文字列” を入力すると、scanf 関数でスペースまでの文字列のみが str1 に格納されることになるため strcmp 関数で意図した比較結果が得られないことになります

例えば Good bye を入力すると、"Good" までが str1 に格納されるので、strcmp 関数からは 0 が返却されることになってしまいます

scanf 関数では、このような問題があるため、このページでの動作確認では scanfでの文字列入力時には “スペースを含まない文字列” を入力するようにしてください

スポンサーリンク

strcmp 関数を利用した文字列比較の例

続いて strcmp 関数を利用して文字列比較を行うプログラムのソースコードの実例を紹介していきます。

strcmp 関数で文字列が一致するかどうかを確認する

strcmp 関数で2つの文字列が一致するかどうかを確認するプログラムのソースコードの例は下記となります。

2つの文字列の比較1
#include <stdio.h> // printf,scanf
#include <string.h> // strcmp

int main(void) {
    char str1[256];
    char str2[] = "Good";
    int result;

    printf("Input string : ");
    scanf("%s", str1);

    result = strcmp(str1, str2);
    if (result == 0) {
        printf("str1 == str2\n");
    } else {
        printf("str1 != str2\n");
    }
}

上記では、まず scanf 関数で文字列の入力を受け付け、入力された文字列が str1 に格納されるようになっています。その後、str1str2 の文字列比較を strcmp 関数で実施しています。strcmp 関数は2つの文字列が一致する場合は 0、一致しない場合は 0 以外 を返却しますので、この2つの文字列が一致する場合は str1 == str2 が、一致しない場合は str1 != str2 が出力されることになります。

さらに、str2 の文字列は Good ですので、scanf によって入力された文字列が Good の場合のみ str1 == str2 が出力されることになります。

実際に、上記のソースコードをコンパイルして実行すれば、まず下記のように文字列の入力が促され、

Input string : 

ここで、Good の文字列を入力してエンターキーを押した場合は下記が、

str1 == str2

Good 以外の文字列を入力してエンターキーを押した場合は下記が表示されることが確認できます。

str1 != str2

この結果より、2つの文字列比較が strcmp 関数で実現できること、さらに strcmp 関数の返却値から2つの文字列が一致しているかどうかを判断できることが理解していただけると思います。

strcmp 関数でアルファベット順的な前後関係を判断する

次は、単に2つの文字列が一致するかどうかを判断するだけではなく、strcmp 関数で2つの文字列のアルファベット順的な前後関係を判断するプログラムのソースコードを紹介します。その例が下記となります。

2つの文字列の比較2
#include <stdio.h> // printf,scanf
#include <string.h> // strcmp

int main(void) {
    char str1[256];
    char str2[] = "Good";
    int result;

    printf("Input string : ");
    scanf("%s", str1);

    result = strcmp(str1, str2);
    if (result > 0) {
        printf("str1 > str2\n");
    } else if (result < 0) {
        printf("str1 < str2\n");
    } else {
        printf("str1 == str2\n");
    }
}

strcmp 関数の実行部分までのコードは strcmp 関数で文字列が一致するかどうかを確認する で紹介したものと全く同じで、strcmp 関数の返却値の扱いのみが異なります。

strcmp 関数 で説明したように、strcmp 関数では第1引数の文字列(文字列1)と第2引数の文字列(文字列2)が異なる場合に、第2引数に対する第1引数の文字列の “アルファベット順的な前後関係” に応じて下記の値を返却するようになっています。

  • 正の値:文字列1が文字列2よりもアルファベット順的に後ろ
  • 負の値:文字列1が文字列2よりもアルファベット順的に前

また、上記のソースコードにおいて、文字列2は "Good" となります。

そのため、上記のソースコードをコンパイルして実行し、Hello を入力してエンターキーを入力すれば strcmp 関数が 正の値 を返却して下記が出力されることになります。strcmp 関数が 正の値 を返却するのは、文字列2 "Good" と文字列1 "Hello" の2つの文字列において、1文字目が一致せず、さらに文字列1の1文字目('H')の方が文字列2の1文字目('G')よりもアルファベット順的に後ろ側にあるからになります。

str1 > str2

また、God を入力してエンターキーを入力した場合は strcmp 関数が 負の値 を返却して下記が出力されることになります。strcmp 関数が 負の値 を返却するのは、文字列2 "Good" と文字列1 "God" の2つの文字列において、1文字目と2文字目は一致しますが3文字目が一致せず、さらに文字列1の3文字目('d')の方が文字列2の3文字目('o')よりもアルファベット順的に前側にあるからになります。

str1 < str2

さらに、Good を入力してエンターキーを入力した場合は strcmp 関数が 0 を返却して下記が出力されることになります。strcmp 関数が 0 を返却するのは、文字列2 "Good" と文字列1 "Good" の2つの文字列において、全ての文字が一致するからになります。

str1 == str2

こんな感じで、strcmp 関数を利用することで、単に文字列が一致するかどうかを判断するだけでなく、2つの文字列のアルファベット順的な前後関係を調べることも出来るようになります。

strncmp 関数を利用した文字列比較

また、C言語の標準ライブラリ関数には strncmp 関数が存在し、この strncmp を利用することでも文字列の比較を実現することが出来ます。

スポンサーリンク

strncmp 関数

strcmp 関数 で紹介した strcmp 関数と名前が似ていることから想像できるように、strncmpstrcmp 関数に似た関数となります。strcmp 関数では文字列全体の比較が行われることになりますが、strncmp 関数では「比較を行う文字数」を指定することが出来ます。この点を除けば strncmp 関数と strcmp 関数はほぼ同じ関数と考えて良いです。

先頭からn文字のみが比較されることを示す図

strcmp 関数と同様に、strncmp 関数は string.h で宣言されており、strncmp 関数を利用する際には string.h をインクルードしておく必要があります。

strncmp 関数の引数・返却値

strncmp 関数の引数 / 返却値は下記のようになります。

第1引数 const char *str1 文字列1
第2引数 const char *str2 文字列2
第3引数 size_t n 比較する文字数
返却値 int

文字列1と文字列2の比較結果

  • 文字列1と文字列2とで先頭から n 文字が一致:0
  • それ以外:0 以外

strncmp 関数を実行することで第1引数と第2引数で指定する文字列の先頭から n 文字分だけ比較が行われます。

そして、strncmp では、先頭から n 文字の比較結果に応じた値が返却されることになります。比較する文字数が n 文字に限定されますが、比較結果に応じた返却値は strcmp と同様であり、返却値が 0 であれば2つの文字列の先頭から n 文字が一致すると判断することが可能です。また、返却値が 正の値 or 負の値 によって2つの文字列における先頭から n 文字のアルファベット順的な前後関係も判断することが出来ます。

ここまでの説明からも理解していただけるように、先頭から特定の文字数分だけの比較を行いたい場合は strcmp ではなく strncmp を使う方が良いです。

strncmp 関数を利用した文字列比較の例

続いて strncmp 関数を利用して2つの文字列の比較を行うプログラムのソースコードの実例を紹介していきます。

strcmp 関数で文字列が一致するかどうかを確認する

strcmp 関数で2つの文字列の先頭から4文字が一致するかどうかを確認するプログラムのソースコードの例は下記となります。

strncmpを利用した文字列の比較
#include <stdio.h> // printf,scanf
#include <string.h> // strcmp

int main(void) {
    char str1[256];
    char str2[] = "GoodMorning";
    size_t n = 4;
    int result;

    printf("Input string : ");
    scanf("%s", str1);

    result = strncmp(str1, str2, n);
    if (result == 0) {
        printf("str1 == str2\n");
    } else {
        printf("str1 =! str2\n");
    }
}

上記のソースコードでは strncmp の第2引数に指定する文字列は "GoodMorning" としています。また、第3引数には n (4) を指定しています。

実行して下記のような文字列を入力してエンターキーを押した場合、全ての場合で str1 == str2 が出力されることになります。

  • GoodMorning
  • Good
  • GoodBye

str1 == str2 が出力されるのは strncmp0 を返却したからで、この出力結果より、strncmp が「先頭の n 文字が一致さえしていれば 0 を返却する」ということが確認できると思います。すでに理解していただいていると思いますが、strcmp の場合は GoodMorning が入力されない限りは 0 が返却されません。

また、例えば GooseGod のように、最初の 4 文字が一致しない文字列を入力した場合は strncmp0 以外 を返却して str1 != str2 が出力されることも確認していただけると思います。

ここまで説明してきたように、strncmp 関数を利用することでも文字列の比較を行うことが可能です。特に strncmp 関数は先頭から特定の文字数分のみの比較を行いたい時に利用することになります。 

参考:== を使った文字列の比較がダメな理由

最後に、参考として == での文字列比較がダメな理由について説明します。

例えば Python など他のプログラミング言語では == を使うだけで文字列比較を行うことが可能です。ですが、C言語においては == での文字列比較は不可となります。

例えば下記のようなソースコードについて考えてみましょう!

==による比較
#include <stdio.h> // printf
#include <string.h> // strncmp

int main(void) {
    char str1[] = "Good";
    char str2[] = "Good";

    if (strcmp(str1, str2) == 0) {
        printf("strcmp : str1 == str2\n");
    } else {
        printf("strcmp : str1 =! str2\n");
    }

    if (str1 == str2) {
        printf("==     : str1 == str2\n");
    } else {
        printf("==     : str1 =! str2\n");
    }
}

このソースコードをコンパイルして実行すれば下記のような出力が得られます。つまり、strcmp 関数での str1str2 の比較では str1str2 とが一致すると判断されています。ですが、str1 == str2 での比較では str1str2 が一致しないと判断されています。

strcmp : str1 == str2
==     : str1 != str2

ソースコードでは str1str2 が両方とも "Good" という文字列となります。したがって、strcmp での比較結果が正解で、== での比較結果は誤りということになりますね!このように、基本的に文字列の == での比較では意図した結果が得られません。

では、文字列の == での比較で意図した結果が得られないのはなぜでしょうか?

結論を先に言うと、== では文字列ではなくアドレスの比較が行われるからになります。 

上記のソースコードで考えれば、str1str2 の実体は配列であり、これらは別々の配列になります。これらは PC のメモリ内に自動的に配置されますが、異なる配列なので異なるアドレスに配置されることになります。

2つの配列が異なるアドレスに配置される様子を説明する図

そして、C言語では、配列の「配列名」は “配列の先頭アドレス” として扱われることになります。

したがって、下記の処理は配列 str1 と配列 str2 の先頭アドレスの比較となり、これらは別々のアドレスに配置されているため当然比較結果は “偽” となることになります。

アドレスの比較
if (str1 == str2) {
    printf("==     : str1 == str2\n");
} else {
    printf("==     : str1 =! str2\n");
}

このように、== での比較は文字列の比較を行っているようで結局はアドレスの比較になります。そして、それらの文字列が別々の配列に格納されているのであれば比較結果は必ず “偽” になります。

strcmp 関数でも第1引数と第2引数に指定するのは結局はアドレスになるのですが(配列名はアドレスとして扱われる)、strcmp の場合はしっかり文字列の比較が行われることになります。

strcmp 関数では引数として渡された2つのアドレスから順に1文字ずつ取得してこれらの比較を行っていきます。そのため、単にアドレスの比較を行うのではなく、そのアドレスに格納されたデータ(文字)の比較が行われることになります。したがって、== での比較のように単なるアドレスの比較ではなく、文字列中の各文字の比較が行われることになり、結果として文字列全体の比較結果が得られることになります。

このように、== では文字列の比較ではなく単なるアドレスの比較が行われることになりますので、文字列の比較を行いたいのであれば strcmp (or strncmp) を使うようにしてください。

==とstrcmpでの比較の違いの説明図

ちなみに、== の両辺に文字列を指定した場合でも、両辺が同じアドレスであれば比較結果は “真” となります。例えば、下記のように2つのポインタ変数から同じ文字列リテラルを指している場合、== での比較結果は真となって str1 == str2 が出力されることになります。

==による比較が真となるケース
#include <stdio.h> // printf
#include <string.h> // strncmp

int main(void) {
    char *str1 = "Good";
    char *str2 = "Good";

    if (strcmp(str1, str2) == 0) {
        printf("strcmp : str1 == str2\n");
    } else {
        printf("strcmp : str1 =! str2\n");
    }

    if (str1 == str2) {
        printf("==     : str1 == str2\n");
    } else {
        printf("==     : str1 =! str2\n");
    }
}

上手く比較が行われているように思えますが、これは str1str2 が同じアドレスを指している、つまり str1str2 に同じアドレスが格納されているからであり、アドレスの比較結果が “真” であっても文字列の比較自体は行われていません。

2つのポインタ変数が同じ文字列リテラルを指す様子

このような比較を行ってたまたま意図した結果が得られることもありますが、前述のとおり文字列の比較を行いたいのであれば strcmp (or strncmp) を使うべきです。逆にアドレスの比較を行うのであれば strcmp ではなく == での比較を行う必要があります。

ここまでの説明のように、strcmp 関数と == での比較の違いは全く異なるものであり、自身が実現したいことに応じてしっかり使い分ける必要があります。

スポンサーリンク

まとめ

このページでは、C言語における文字列の比較方法について解説しました!

C言語での文字列の比較は strcmp 関数 or strncmp 関数を利用することで実現できます。文字列全体を比較したい場合は strcmp を、先頭から特定の文字数のみの比較を行いたい場合は strncmp 関数を利用すれば良いです。

特に、C言語では == での文字列の比較は行えない点に注意してください。

また、今回は文字列の比較について説明しましたが、文字列の検索に関しては strstr 関数を利用することになります。この strstr 関数を利用することで、文章中に特定の文字列が存在するかどうかや、その文字列の文章中の位置を求めたりすることが出来るようになります。strstr 関数に関しては下記ページで解説していますので、是非こちらの関数についても理解しておきましょう!

strstr関数の使い方の解説ページアイキャッチ 【C言語】strstr関数の使い方(文字列を検索する関数)

同じカテゴリのページ一覧を表示