C言語で文字列を扱う際に覚えておくと便利なのが文字列操作関数です。
このページでは、よく利用する文字列操作関数と、その使用方法について解説していきます。

私も毎回ググってるよ…
まあ、なので、覚えなくても良いようにこんなまとめページを作ったんだ!

私も文字列操作関数は毎回調べながら使用しています。
おそらくそういう方も多いと思うので、よく使う文字列操作関数をこのページにまとめました!
是非文字列操作関数やその使い方に迷ったらこのページを参考にしてください。
Contents
文字列の長さを取得する
文字列の長さ(文字数)を取得する時に使用する関数は「strlen 関数」です。
strlen 関数
strlen 関数は文字列の長さを取得する関数になります。
strlen 関数を実行することで、例えば文字列 "aiueo" の文字列の長さ 5 を取得することができます。
strlen 関数の定義ファイル、関数定義は下記の通りです。
#include <string.h>
size_t strlen(const char* str);
strlen 関数の引数
strlen 関数の引数には str、文字列へのアドレスを指定します。より具体的には、文字列が格納された配列やメモリのアドレスを指定します。
strlen 関数の返却値
strlen 関数の返却値は引数 str の文字列の長さになります。
この文字列の長さにはヌル文字(\0)の分はカウントされません。
strlen 関数の詳細
では、この strlen 関数が返却する「文字列の長さ」とは具体的にはどのような値になるでしょうか?
これは、引数で指定するアドレス str からアドレスを1バイトずつ増やしていき、次にヌル文字(\0)が見つかるまでのバイト数になります。

バイト数ですので、日本語などマルチバイト文字を格納した文字列に対して strlen 関数を実行すると文字数と一致しないので注意しましょう。
ただ、特にC言語習いたての方は1バイト文字(英数字)を利用することが多いので、まずは「strlen 関数は文字数を取得する関数」と覚えておいて差し支えないと思います。
また、ヌル文字(\0)が存在することを期待して動作しますので、ヌル文字(\0)が含まれないデータへのアドレスを strlen 関数に渡してしまうと動作がおかしくなります。

\0)が含まれないとどうなるの?おそらくだけど、配列のサイズに関係なく、次にヌル文字(\0)があるアドレスまでヌル文字の探索が行われるよ
この場合、配列のサイズを超えてデータの参照が行われるのでバッファオーバーフローになる可能性もある

スポンサーリンク
strlen 関数の使用例
strlen 関数を使用して文字列の長さを取得するプログラムの例は下記になります。
#include <stdio.h>
#include <string.h>
int main(void){
char *str1 = "hitotsume";
size_t len1;
/* 文字列の長さ取得 */
len1 = strlen(str1);
/* 表示 */
printf("str1 = %s, len1 = %lu\n", str1, len1);
return 0;
}
実行結果は下のようになります。
str1 = hitotsume, len1 = 9
文字列をコピーする
文字列をコピーする時に利用する関数は「strcpy 関数」です。
strcpy 関数
strcpy 関数は文字列をコピーする関数です。
strcpy 関数の定義ファイル、関数定義は下記の通りです。
#include <string.h>
char* strcpy(char* str1, const char* str2);
strcpy 関数の引数
第1引数の str1 には文字列をコピーする “先” の配列やメモリのアドレスを指定し、第2引数の str2 には文字列をコピーする “元” の配列やメモリのアドレスを指定します。
strcpy 関数の返却値
返却値は文字列をコピーした “先” の先頭アドレスになります。つまり、str1 と一致します。
strcpy 関数の詳細
strcpy を実行することで、str2 のアドレスからヌル文字(\0)までの文字列が str1 のアドレスの配列やメモリにコピーされます。


\0)もコピーされるの?ヌル文字(\0)も含めてコピーされると考えて良いです。
ただし、コピー先のアドレスである str1 の指す配列やメモリは、ヌル文字(\0)を含めたサイズにしておく必要があります。
スポンサーリンク
strcpy 関数の使用例
strcpy 関数を使用して文字列をコピーするプログラムの例は下記になります。
#include <stdio.h>
#include <string.h>
#define MAX_CHAR_NUM 10
int main(void){
char str1[MAX_CHAR_NUM];
char str2[MAX_CHAR_NUM];
/* 文字列コピー */
strcpy(str1, "hitotsume");
printf("str1 = %s\n", str1);
printf("\n");
strcpy(str2, str1);
printf("str1 = %s\n", str1);
printf("str2 = %s\n", str2);
printf("\n");
strcpy(str2, "futatsume");
printf("str1 = %s\n", str1);
printf("str2 = %s\n", str2);
printf("\n");
return 0;
}
実行結果は下のようになります。ポイントは "hitotsume" などのような「文字列自体」を strcpy 関数の第2引数にも指定可能という点だと思います。
この場合もしっかりヌル文字(\0)が含まれる形で文字列のコピーが行われます。
str1 = hitotsume str1 = hitotsume str2 = hitotsume str1 = hitotsume str2 = futatsume
文字列を比較する
文字列の比較する時に利用する関数は「strcmp 関数」です。
strcmp 関数
strcmp 関数は2つの文字列を比較する関数です。
strcmp 関数の定義ファイル、関数定義は下記の通りです。
#include <string.h>
int strcmp(const char* str1, const char* str2);
strcmp 関数の引数
strcmp 関数の第1引数 str1・第2引数 str2 に比較したい2つの文字列が格納された配列やメモリの先頭アドレスを指定します。
単に同じかどうかを比較したい場合は、第1引数 str1 と第2引数 str2 の順序に特に意味はありません。
ただし、大小関係を調べたい場合は第1引数 str1 と第2引数 str2 の指定順で返却値が異なりますので注意してください。
strcmp 関数の返却値
引数 str1 と str2 で指定したアドレスの先の2つの文字列が同じである場合、strcmp 関数は 0 を返却します。
同じでない場合は 0 以外の値を返却します。
より具体的には、”文字コード的に” 第1引数の方が大きい場合は “正” の値、第2引数の方が大きい場合は “負” の値を返却します。

正確に言うと「文字に割り当てられた数字」に大きいや小さいがあるんだ
各文字には文字コードという数字が割り当てられてて、その数字の大小関係に応じて値が返却される感じだね

strcmp 関数の詳細
strcmp 関数は引数 str1 と str2 で指定された2つの文字列の比較を行います。
比較は先頭の文字から1文字ずつ行われます。

そして、両方の文字列の文字がヌル文字(\0)である場合もしくは文字が異なる場合に比較を終了します。
この時、両方文字列の文字がヌル文字(\0)である場合は、2つの文字列の先頭から文字列の最後(ヌル文字)まで同じであると判断できるので、文字列が同じであることを示す 0 が返却されます。
一方、文字が異なる場合は、2つの文字列が異なると判断できるので、文字列が異なることを示す 0 以外の値が返却されます。
ここからは環境によって異なるかもしれませんが、私の環境では異なった文字の文字コードの差が返却されました。
具体的には、引数 str1 と引数 str2 の第 n 文字目が異なる場合は、下記の値が返却されるようでした。
str1[n] - str2[n];
例えば str1 = "abc"、str2 = "abx" の場合、'c' - 'x' = -21 が返却されました。
この辺りの細かい返却値については環境依存で結果が異なる可能性がありますが、str1 の方が文字コード的に大きい場合は正の値、str2 の方が文字コード的に大きい場合は負の値が返却される点はどの環境でも同じではないかと思います。
こういった文字コードの大小関係を strcmp 関数の返却値で取得することもできますので、2分探索を行う場合にも便利な関数です。
スポンサーリンク
strcmp 関数の使用例
strcmp 関数を使用して文字列を比較するプログラムの例は下記になります。
#include <stdio.h>
#include <string.h>
int main(void){
char str[] = "abc";
char str1[] = "abc";
char str2[] = "abcd";
char str3[] = "abd";
char str4[] = "abb";
char str5[] = "Acd";
printf("strcmp(%s, %s) : %d\n", str, str1, strcmp(str, str1));
printf("strcmp(%s, %s) : %d\n", str, str2, strcmp(str, str2));
printf("strcmp(%s, %s) : %d\n", str, str3, strcmp(str, str3));
printf("strcmp(%s, %s) : %d\n", str, str4, strcmp(str, str4));
printf("strcmp(%s, %s) : %d\n", str, str5, strcmp(str, str5));
return 0;
}
実行結果は下のようになります。
strcmp(abc, abc) : 0 strcmp(abc, abcd) : -100 strcmp(abc, abd) : -1 strcmp(abc, abb) : 1 strcmp(abc, Acd) : 32
文字列を連結(結合)する
文字列を連結することができるのは strcat 関数です。
strcat 関数
strcat 関数は2つの文字列を連結する関数です。
例えば "ai" という文字列と "ueo" という文字列を連結して "aiueo" という文字列を生成すすることができます。
strcat 関数の定義ファイル、関数定義は下記の通りです。
#include <string.h>
char* strcat(char* str1, const char* str2);
strcat 関数の引数
strcat 関数の第1引数 str1 には連結 “元” になる文字列が格納された配列やメモリのアドレスを、第2引数 str2 には第1引数 str1 に連結したい文字列が格納された配列やメモリのアドレスを指定します。
strcat 関数の返却値
2つの文字列を連結した結果が格納される配列やメモリの先頭アドレスが返却されます。
といっても、strcat 関数では後述するように第1引数で指定した文字列の後ろ側に第2引数で指定した文字列が連結されるため、結局第1引数で指定したアドレスと同じものが返却されることになります。
strcat 関数の詳細
strcat 関数は引数で指定した文字列 str1 の後ろに文字列 str2 を連結します。
より具体的に言うと、str1 の終端を表すヌル文字(\0)部分から後ろ側に文字列 str2 が連結されます。

str1 の終端を表すヌル文字(\0)は str2 に上書きされて無くなりますが、連結後も str2 側のヌル文字(\0)は残ります。
strcat 関数の注意点
strcat 関数には注意点が2つあります。
1点目は、第1引数で指定した str1 の指す配列やメモリの内容が下記変わってしまうことです。具体的には、strcat 関数を実行することで、str1 の指す配列やメモリには str1 に str2 を連結した文字列が格納されることになります。
2点目は第1引数で指定した str1 の指す配列やメモリのサイズです。
strcat 関数を実行すると、str1 の後ろ側に str2 の文字列が連結されることになりますので、str1 の指す配列やメモリのサイズは str2 連結後の文字列が十分に格納できるだけのものでなければなりません。
連結後の文字列が配列やメモリに入りきらない場合、メモリの不正アクセスになってしまうので注意してください。
スポンサーリンク
strcat 関数の使用例
下記は strcat 関数を用いて文字列の連結を行うプログラムの例です。
#include <stdio.h>
#include <string.h>
int main(void) {
char str1[10] = "ai";
char str2[] = "ueo";
strcat(str1, str2);
printf("str1 = %s\n", str1);
}
実行すると下記のように表示され、str1 に str2 が連結されていることが確認できると思います。
aiueo
下記はダメな例です。
#include <stdio.h>
#include <string.h>
int main(void) {
char str1[] = "ai";
char str2[] = "ueo";
strcat(str1, str2);
printf("str1 = %s\n", str1);
}
str1 には str2 が連結されるので、str2 の文字列の長さも考慮して str1 の配列のサイズを設定する必要があります。
下記だと str1 の配列のサイズが "ai" の文字列分しか確保されていないため、strcat 関数で str1 に str2 に連結する時にバッファオーバーフローが発生します。
書式を指定して文字列を生成する
書式を指定して文字列を生成するのは sprintf 関数です。
printf 関数同様の感覚で文字列の生成や文字列の結合などを行うことができます。sprintf 関数に関しては下記ページで詳しく解説しておりますので、詳しく知りたい方は下記ページをご参照いただければと思います。
文字列を探索する
文字列を探索する時に使用するのは strstr 関数です。
スポンサーリンク
strstr 関数
strstr 関数は文字列の中から指定した文字列を探索する関数です。
strstr 関数の定義ファイル、書式は下記の通りです。
#include <string.h>
char* strstr(const char* str1, const char* str2);
strstr 関数の引数
strstr 関数の第1引数 str1 には探索 “先” になる文字列が格納された配列やメモリのアドレスを、第2引数 str2 には第1引数 str1 で指定した文字列から探索したい文字列が格納された配列やメモリのアドレスを指定します。
strstr 関数の返却値
文字列 str1 の中から文字列 str2 が見つかった位置(アドレス)を返却します。
見つからなかった場合は NULL を返却します。
strstr 関数の詳細
strstr 関数では str1 の文字列(str1 の指すアドレスから、str1 の終端を表すヌル文字('\0')までの間のデータ)の中から str2 の指す文字列の探索が行われます。
str1 の文字列の中から str2 が見つかった場合、str2 が見つかった位置のアドレスを返却します。

str1 の文字列に str2 の文字列が複数存在する場合は、先頭に近い方のアドレスが返却されます。
strstr 関数の使用例
下記は strstr 関数を用いて文字列の探索を行うプログラムの例です。
#include <string.h>
#include <stdio.h>
#define MAX_CHAR_NUM 10
#define MAX_LINE 5
int main(void) {
char str[MAX_LINE][MAX_CHAR_NUM] = {
"I am cat",
"scan",
"melon",
"cat can",
"cccaaaa"
};
char search[] = "ca";
int i;
char *ret;
for (i = 0; i < MAX_LINE; i++) {
ret = strstr(str[i], search);
if (ret != NULL) {
printf("%s:%s\n", str[i], ret);
} else {
printf("%s:Notfound\n", str[i]);
}
}
return 0;
}
実行結果は下記のようになります。strstr 関数の返却値は、str2 で指定した文字列が見つかった位置ですので、返却値を表示すると str1 の途中に str2 が存在する場合はその位置から文字列が表示されることになります。
I am cat:cat scan:can melon:Notfound cat can:cat can cccaaaa:caaaa
文字列を分離する(切り離す)
文字列を分離(切り離し)したい時に使用するのは strtok 関数です。
strtok 関数に関しては注意点が多いので下記ページにまとめています。strtok 関数について詳しく知りたい方は下記ページを参照していただければと思います。
スポンサーリンク
まとめ
このページでは下記の文字列を操作する関数について解説しました!
-
strlenstrcpystrcmpstrcatstrstr
C言語でも文字列の操作を行う関数が数多く用意されています。
とにかくこれらの関数では、文字列の最後にヌル文字('\0')が存在することを期待して動作します。なので、ヌル文字('\0')が含まれない文字列を引数に指定すると基本的にバッファオーバーフローが起こります。ここが文字列操作関数における1番の注意点だと思います。
また、便利なものが多いですが、strtok のようにクセの強い関数も結構多い印象です!
使い方に困った時などは是非コメントなどで質問いただければと思いますのでよろしくお願いいたします。
