【C言語】文字列操作関数(strlen・strcatなど)まとめ【目的から逆引き】

文字列操作関数まとめページのアイキャッチ

C言語で文字列を扱う際に覚えておくと便利なのが文字列操作関数です。

このページでは、よく利用する文字列操作関数と、その使用方法について解説していきます。

文字列関連の関数って結構使うんだけど使い方なんかは全然覚えてないや

私も毎回ググってるよ…

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

私も文字列操作関数は毎回調べながら使用しています。

おそらくそういう方も多いと思うので、よく使う文字列操作関数をこのページにまとめました!

是非文字列操作関数やその使い方に迷ったらこのページを参考にしてください。

文字列の長さを取得する

文字列の長さ(文字数)を取得する時に使用する関数は「strlen 関数」です。

strlen 関数

strlen 関数は文字列の長さを取得する関数になります。

strlen 関数を実行することで、例えば文字列 "aiueo" の文字列の長さ 5 を取得することができます。

strlen 関数の定義ファイル、関数定義は下記の通りです。

strlen関数
#include <string.h>
size_t strlen(const char* str);

strlen 関数の引数

strlen 関数の引数には str、文字列へのアドレスを指定します。より具体的には、文字列が格納された配列やメモリのアドレスを指定します。

strlen 関数の返却値

strlen 関数の返却値は引数 str の文字列の長さになります。 

この文字列の長さにはヌル文字(\0)の分はカウントされません。

strlen 関数の詳細

では、この strlen 関数が返却する「文字列の長さ」とは具体的にはどのような値になるでしょうか?

これは、引数で指定するアドレス str からアドレスを1バイトずつ増やしていき、次にヌル文字(\0)が見つかるまでのバイト数になります。

strlenの動作

バイト数ですので、日本語などマルチバイト文字を格納した文字列に対して strlen 関数を実行すると文字数と一致しないので注意しましょう。

ただ、特にC言語習いたての方は1バイト文字(英数字)を利用することが多いので、まずは「strlen 関数は文字数を取得する関数」と覚えておいて差し支えないと思います。

また、ヌル文字(\0)が存在することを期待して動作しますので、ヌル文字(\0)が含まれないデータへのアドレスを strlen 関数に渡してしまうと動作がおかしくなります。

ヌル文字(\0)が含まれないとどうなるの?

おそらくだけど、配列のサイズに関係なく、次にヌル文字(\0)があるアドレスまでヌル文字の探索が行われるよ

この場合、配列のサイズを超えてデータの参照が行われるのでバッファオーバーフローになる可能性もある

スポンサーリンク

strlen 関数の使用例

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 関数の定義ファイル、関数定義は下記の通りです。

strcpy関数
#include <string.h>
char* strcpy(char* str1, const char* str2);

strcpy 関数の引数

第1引数の str1 には文字列をコピーする “先” の配列やメモリのアドレスを指定し、第2引数の str2 には文字列をコピーする “元” の配列やメモリのアドレスを指定します。

strcpy 関数の返却値

返却値は文字列をコピーした “先” の先頭アドレスになります。つまり、str1 と一致します。

strcpy 関数の詳細

strcpy を実行することで、str2 のアドレスからヌル文字(\0)までの文字列が str1 のアドレスの配列やメモリにコピーされます。

strcpyの動作

ヌル文字(\0)もコピーされるの?

ヌル文字(\0)も含めてコピーされると考えて良いです。

ただし、コピー先のアドレスである str1 の指す配列やメモリは、ヌル文字(\0)を含めたサイズにしておく必要があります。

スポンサーリンク

strcpy 関数の使用例

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 関数の定義ファイル、関数定義は下記の通りです。

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 関数の返却値

引数 str1str2 で指定したアドレスの先の2つの文字列が同じである場合、strcmp 関数は 0 を返却します。

同じでない場合は 0 以外の値を返却します。

より具体的には、”文字コード的に” 第1引数の方が大きい場合は “正” の値、第2引数の方が大きい場合は “負” の値を返却します。

文字に大きいや小さいがあるの?

正確に言うと「文字に割り当てられた数字」に大きいや小さいがあるんだ

各文字には文字コードという数字が割り当てられてて、その数字の大小関係に応じて値が返却される感じだね

strcmp 関数の詳細

strcmp 関数は引数 str1str2 で指定された2つの文字列の比較を行います。

比較は先頭の文字から1文字ずつ行われます。

strcmpの動作

そして、両方の文字列の文字がヌル文字(\0)である場合もしくは文字が異なる場合に比較を終了します。

この時、両方文字列の文字がヌル文字(\0)である場合は、2つの文字列の先頭から文字列の最後(ヌル文字)まで同じであると判断できるので、文字列が同じであることを示す 0 が返却されます。

一方、文字が異なる場合は、2つの文字列が異なると判断できるので、文字列が異なることを示す 0 以外の値が返却されます。

ここからは環境によって異なるかもしれませんが、私の環境では異なった文字の文字コードの差が返却されました。

具体的には、引数 str1 と引数 str2 の第 n 文字目が異なる場合は、下記の値が返却されるようでした。

strcmpの返却値
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 関数の定義ファイル、関数定義は下記の通りです。

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 が連結されます。

strcatの動作

str1 の終端を表すヌル文字(\0)は str2 に上書きされて無くなりますが、連結後も str2 側のヌル文字(\0)は残ります。

strcat 関数の注意点

strcat 関数には注意点が2つあります。

1点目は、第1引数で指定した str1 の指す配列やメモリの内容が下記変わってしまうことです。具体的には、strcat 関数を実行することで、str1 の指す配列やメモリには str1str2 を連結した文字列が格納されることになります。

2点目は第1引数で指定した str1 の指す配列やメモリのサイズです。

strcat 関数を実行すると、str1 の後ろ側に str2 の文字列が連結されることになりますので、str1 の指す配列やメモリのサイズは str2 連結後の文字列が十分に格納できるだけのものでなければなりません。

連結後の文字列が配列やメモリに入りきらない場合、メモリの不正アクセスになってしまうので注意してください。

スポンサーリンク

strcat 関数の使用例

下記は 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

下記はダメな例です。

strcatの使用例(ダメな例)
#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 関数で str1str2 に連結する時にバッファオーバーフローが発生します。

書式を指定して文字列を生成する

書式を指定して文字列を生成するのは sprintf 関数です。

sprintf 関数

sprintf 関数を書式を指定して文字列を生成する関数です。

書式とは…?

うーん、まずはあまり深く考えなくて良いかな

要は printf 関数の文字列出力バージョンだよ

おそらく最初に使用した関数が printf という方も多いと思います。馴染み深い関数だと思います。

printf 関数は標準出力(例えばコンソール・ターミナルなど)に文字列を出力する関数ですよね!

変換指定子(%d%s など)を指定し、そこに変数の値を埋め込んで文字列を出力できるところがポイントです。

sprintf 関数は、標準出力ではなく、配列やメモリに文字列を出力することができる関数です。

sprintf 関数数の定義ファイル、関数定義は下記の通りです。

sprintf関数
#include <stdio.h>
int sprintf(char *str, const char *format, ...);

sprintf 関数の引数

sprintf 関数の第1引数 str は文字列の出力先のアドレスを指定します。

第2引数 format には書式を指定します。

第3引数以降は可変長引数になっており、format に含まれる変換指定子の数分の引数を指定します。

sprintf 関数の返却値

成功時は str に格納された文字列の長さ(ヌル文字は含まない)を返却します。

失敗時は負の値を返却します。

sprintf 関数の詳細

書式や変換指定子など難しい言葉が使われていたり、関数の引数が可変長引数になっていたりで難しそうに感じるかもしれませんが、基本的に printf 関数と同じ感じで使用すれば良いです。

例えば第2引数 format"I am %s\n" を指定し、第3引数に "cat" を指定して sprintf 関数を実行すれば、第1引数 str の指すアドレスに "I am cat\n" が格納されることになります。

前述で strcat 関数を紹介しましたが、sprintf 関数でも文字列の連結を簡単に行うことができます。下記は str1str2str3 を連結した文字列を str の指すアドレスに格納する sprintf 関数の使用例になります。

sprintfでの文字列の結合
sprintf(str, "%s%s%s", str1, str2, str3);

printf 同様に、変換指定子 に %d や %f を指定すれば、数値などを format に埋め込んだ結果を取得することもできます。

sprintf 関数の注意点

第1引数 str の指すアドレスの配列やメモリのサイズに注意が必要です。

第1引数 str には、第2引数 format に対して第3引数以降の引数を埋め込んだ結果が格納されます。

したがって、その埋め込み後の文字列の長さ以上のサイズの配列やメモリのアドレスを第1引数 str に指定する必要があります。

サイズが足りない場合はバッファオーバーフローが発生します。

スポンサーリンク

sprintf 関数の使用例

下記は sprintf 関数を使用して文字列を生成するプログラムの例です。

sprintf関数の使用例
#include <stdio.h>

int main(void) {

    char str[100];
    char name[] = "hanako";
    float height = 165.5;

    sprintf(str, "%s's height is %.1f\n", name, height);

    printf("%s", str);

    return 0;
}

文字列を探索する

文字列を探索する時に使用するのは strstr 関数です。

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 が見つかった位置のアドレスを返却します。

strstrの動作

str1 の文字列に str2 の文字列が複数存在する場合は、先頭に近い方のアドレスが返却されます。

スポンサーリンク

strstr 関数の使用例

下記は 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 関数について詳しく知りたい方は下記ページを参照していただければと思います。

strtok関数の使い方の解説ページアイキャッチ【C言語】strtok関数の使い方と注意点(文字列を区切り文字で分離する関数)

まとめ

このページでは下記の文字列を操作する関数について解説しました!

    • strlen
    • strcpy
    • strcmp
    • strcat
    • strstr

C言語でも文字列の操作を行う関数が数多く用意されています。

とにかくこれらの関数では、文字列の最後にヌル文字('\0')が存在することを期待して動作します。なので、ヌル文字('\0')が含まれない文字列を引数に指定すると基本的にバッファオーバーフローが起こります。ここが文字列操作関数における1番の注意点だと思います。

また、便利なものが多いですが、strtok のようにクセの強い関数も結構多い印象です!

使い方に困った時などは是非コメントなどで質問いただければと思いますのでよろしくお願いいたします。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です