このページでは、C言語において文字列の比較を行う方法について説明していきます。
プログラムを作っていると「特定の2つの文字列が一致するかどうかを判断したい」ようなケースに遭遇する機会も多いと思います。例えば、ユーザーの入力した文字列が事前に設定されたパスワードと一致するかどうかを判断するようなケースは分かりやすい例だと思います。
C言語においては文字列の比較は標準ライブラリ関数である strcmp
関数を利用することが多いです。もちろん文字列の比較を行う処理を自力で記述して文字列の比較を実現することも可能ですが、このページでは関数を利用した文字列の比較について解説していきたいと思います。
また、C言語においては 文字列1 == 文字列2
のように ==
演算子での文字列比較は行うことが出来ません。この理由についても、おまけとして解説していきたいと思います。
Contents
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の比較結果
|
C言語における文字列とは「ヌル文字('\0'
)で終端された char
型の配列(メモリ)」であり、strcmp
関数の第1引数と第2引数にはヌル文字('\0'
)で終端した char
型の配列の「配列名」や「配列の先頭を指すアドレス」を指定することが可能です。
また、strcmp
関数では、第1引数と第2引数で指定した2つの文字列が一致した場合に 0
を返却します。なので、2つの文字列が一致するかどうかは返却値が 0
であるかどうかを確認することで判断することが可能です。
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引数の文字列がアルファベット順的に後ろ側に存在すると判断して 正の値
を返却します。
また、第1引数に "God"
、第2引数に "Good"
を指定した場合は、1つ目の文字の比較で G == G
、2つ目の文字の比較で o == o
となってここまでは一致しますが、3つ目の文字の比較で d < o
となるため strcmp
関数は第1引数の文字列がアルファベット順的に前側に存在すると判断して負の値を返却します。
さらに、第1引数に "Good"
、第2引数に "Good"
を指定した場合は、4つの文字全てが一致するため、strcmp
関数は2つの文字列が一致していると判断して 0
の値を返却します。
こんな感じで、strcmp
関数では、2つの文字列の先頭の文字から順に1文字ずつ比較を行うことで、2つの文字列のアルファベット順的な前後関係に応じた返却値が返却されるようになっています。
上記のソースコードのプログラムで最初に “スペースを含む文字列” を入力すると、scanf
関数でスペースまでの文字列のみが str1
に格納されることになるため strcmp
関数で意図した比較結果が得られないことになります
例えば Good bye
を入力すると、"Good"
までが str1
に格納されるので、strcmp
関数からは 0
が返却されることになってしまいます
scanf
関数では、このような問題があるため、このページでの動作確認では scanf
での文字列入力時には “スペースを含まない文字列” を入力するようにしてください
スポンサーリンク
strcmp
関数を利用した文字列比較の例
続いて strcmp
関数を利用して文字列比較を行うプログラムのソースコードの実例を紹介していきます。
strcmp
関数で文字列が一致するかどうかを確認する
strcmp
関数で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 {
printf("str1 != str2\n");
}
}
上記では、まず scanf
関数で文字列の入力を受け付け、入力された文字列が str1
に格納されるようになっています。その後、str1
と str2
の文字列比較を 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つの文字列のアルファベット順的な前後関係を判断するプログラムのソースコードを紹介します。その例が下記となります。
#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
関数と名前が似ていることから想像できるように、strncmp
は strcmp
関数に似た関数となります。strcmp
関数では文字列全体の比較が行われることになりますが、strncmp
関数では「比較を行う文字数」を指定することが出来ます。この点を除けば strncmp
関数と strcmp
関数はほぼ同じ関数と考えて良いです。
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の比較結果
|
strncmp
関数を実行することで第1引数と第2引数で指定する文字列の先頭から n
文字分だけ比較が行われます。
そして、strncmp
では、先頭から n
文字の比較結果に応じた値が返却されることになります。比較する文字数が n
文字に限定されますが、比較結果に応じた返却値は strcmp
と同様であり、返却値が 0
であれば2つの文字列の先頭から n
文字が一致すると判断することが可能です。また、返却値が 正の値
or 負の値
によって2つの文字列における先頭から n
文字のアルファベット順的な前後関係も判断することが出来ます。
ここまでの説明からも理解していただけるように、先頭から特定の文字数分だけの比較を行いたい場合は strcmp
ではなく strncmp
を使う方が良いです。
strncmp
関数を利用した文字列比較の例
続いて strncmp
関数を利用して2つの文字列の比較を行うプログラムのソースコードの実例を紹介していきます。
strcmp
関数で文字列が一致するかどうかを確認する
strcmp
関数で2つの文字列の先頭から4文字が一致するかどうかを確認するプログラムのソースコードの例は下記となります。
#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
が出力されるのは strncmp
が 0
を返却したからで、この出力結果より、strncmp
が「先頭の n
文字が一致さえしていれば 0
を返却する」ということが確認できると思います。すでに理解していただいていると思いますが、strcmp
の場合は GoodMorning
が入力されない限りは 0
が返却されません。
また、例えば Goose
や God
のように、最初の 4
文字が一致しない文字列を入力した場合は strncmp
が 0 以外
を返却して 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
関数での str1
と str2
の比較では str1
と str2
とが一致すると判断されています。ですが、str1 == str2
での比較では str1
と str2
が一致しないと判断されています。
strcmp : str1 == str2 == : str1 != str2
ソースコードでは str1
と str2
が両方とも "Good"
という文字列となります。したがって、strcmp
での比較結果が正解で、==
での比較結果は誤りということになりますね!このように、基本的に文字列の ==
での比較では意図した結果が得られません。
では、文字列の ==
での比較で意図した結果が得られないのはなぜでしょうか?
結論を先に言うと、==
では文字列ではなくアドレスの比較が行われるからになります。
上記のソースコードで考えれば、str1
と str2
の実体は配列であり、これらは別々の配列になります。これらは PC のメモリ内に自動的に配置されますが、異なる配列なので異なるアドレスに配置されることになります。
そして、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
) を使うようにしてください。
ちなみに、==
の両辺に文字列を指定した場合でも、両辺が同じアドレスであれば比較結果は “真” となります。例えば、下記のように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");
}
}
上手く比較が行われているように思えますが、これは str1
と str2
が同じアドレスを指している、つまり str1
と str2
に同じアドレスが格納されているからであり、アドレスの比較結果が “真” であっても文字列の比較自体は行われていません。
このような比較を行ってたまたま意図した結果が得られることもありますが、前述のとおり文字列の比較を行いたいのであれば strcmp
(or strncmp
) を使うべきです。逆にアドレスの比較を行うのであれば strcmp
ではなく ==
での比較を行う必要があります。
ここまでの説明のように、strcmp
関数と ==
での比較の違いは全く異なるものであり、自身が実現したいことに応じてしっかり使い分ける必要があります。
スポンサーリンク
まとめ
このページでは、C言語における文字列の比較方法について解説しました!
C言語での文字列の比較は strcmp
関数 or strncmp
関数を利用することで実現できます。文字列全体を比較したい場合は strcmp
を、先頭から特定の文字数のみの比較を行いたい場合は strncmp
関数を利用すれば良いです。
特に、C言語では ==
での文字列の比較は行えない点に注意してください。
また、今回は文字列の比較について説明しましたが、文字列の検索に関しては strstr
関数を利用することになります。この strstr
関数を利用することで、文章中に特定の文字列が存在するかどうかや、その文字列の文章中の位置を求めたりすることが出来るようになります。strstr
関数に関しては下記ページで解説していますので、是非こちらの関数についても理解しておきましょう!