「C言語」の「文字列操作関数」が難解だった・・・

「文字列の操作」について学び忘れていたので、今回からは、「C言語」の「文字列操作」を学んでいきたいと思います。

もうほとんど学んだと思っていたのですが、学び忘れていたことが後からどんどん出くるので、きちんと学んでいきたい。

あと、「データ型の変換」も勉強していかないと・・・

「文字列操作」の関数

文字列を操作するための「専用の関数」が用意されているのですが、少しずつ関数の使い方について学んでいきたいと思います。

「strlen」関数

「strlen」関数は、「文字サイズ(バイト数)」を調べることができる関数です。

ただ、「バイト数」なので、「文字列の長さ」ではありません。

例えば、

#include <stdio.h>

int main(void) {

    char data[2048] = "abcde";

    int size = strlen(data);

    printf("string size=%d\n", size);

    return 0;
}

と書いて実行すると、

string size=5

のようになります。

半角文字だけだと「バイト数=文字数」となっているのですが、全角文字が含まれていると、「文字数」ではなくなってしまいます。

例えば、

#include <stdio.h>

int main(void) {

    char data[2048] = "おはよう";

    int size = strlen(data);

    printf("string size=%d\n", size);

    return 0;
}

のように、「日本語文字」を入れて、バイト数を見てみると、

string size=8

のようになるので、「日本語の全角文字」は、2バイトとして計算されているのがわかりますね。

ただ、「半角文字」と「全角文字」が混ざったらどうすればいいんでしょうか。

と思っていろいろと調べてみました。

すると、「_ismbblead」という関数で「マルチバイト文字」の1文字目かを判定でき、「_ismbbtrail」関数で「マルチバイト文字」の2文字めかを判定できるそうです。

なるほど。これを使って判定すると、文字数を数えることができそうですね。

と言いつつ、プログラムを書いてみても全くうまくいきませんでした。

プログラミング初心者にはちょっと難しい内容(^^;)

と思いながら2時間ほど悩んで、なんとか文字数を数えられるプログラムを作ってみました。

#include <stdio.h>

int main(void) {
	
    int size = 0;

    // 全角と半角文字の混合
    char data2[2048] = "おaは漢字一よqです。うq2";

    size = strlen(data2);

    printf("size=%d\n", size);

    int i = 0;
    int count = 0;

    while(1){

        printf("i=%d\n",i);

        if(data2[i] == '\0'){
            break;
        } else {
            // 全角(漢字)文字の1文字目かどうかを確認
            if( _ismbblead(data2[i]) != 0 ){
                printf("先頭\n");
                if(data2[i+1] == "\0"){
                    break;
                }
                i++;
                count++;
                // 全角(漢字)文字の2文字目かどうかを確認
            } else if ( _ismbbtrail(data2[i]) != 0 ){
                printf("後尾(%c)\n", data2[i]);
                count++;
            } else {
                printf("半角文字\n");
                count++;
            }
            i++;
        }
    }

    printf("文字数=%d\n", count);

    return 0;
}

何を判定しているのか見てみたかったので、判定結果も出力をしてみました。

すると、

size=24
i=0
先頭
i=2
後尾(a)
i=3
先頭
i=5
先頭
i=7
先頭
i=9
先頭
i=11
先頭
i=13
後尾(q)
i=14
先頭
i=16
先頭
i=18
先頭
i=20
先頭
i=22
後尾(q)
i=23
半角文字
i=24
文字数=14

のようになり、全角と半角文字が混在している場合でも、「文字数」が無事に数えられています。

文字数を数えるだけなのに、「C言語」だとこんなに複雑なプログラムになるんですね。

「C言語」の難しさをこんなところでも実感したり・・・

「strcat」関数

ある文字列の後ろにさらに文字列を追加できるのが「strcat」関数です。

この関数は、

strcat(ベースの文字列, 追加する文字列);

のように指定していきます。

例えば、

#include <stdio.h>

int main(void) {

    // 全角と半角文字の混合
    char data[2048] = "あいうえお";

    printf("文字列追加前=%s\n", data);

    strcat(data, "かきくけこ");

    printf("文字列追加後=%s", data);

    return 0;
}

のようにプログラムを作成し、実行してみると、

文字列追加前=あいうえお
文字列追加後=あいうえおかきくけこ

のようになります。

この関数を利用する場合は、「配列のサイズ」に気を付けて利用する必要があり、「文字列を追加後の文字サイズ」が、あらかじめ作成した「配列のサイズ」に収まっているかを確認しながら利用していく必要があります。

もし、サイズをオーバーしてしまったら・・・「バッファオーバーフロー(バッファオーバーラン)」と呼ばれる、「メモリ内容の上書きによるデータ破壊」が起こってしまいます。

「C言語」の関数を調べていると、こういう注意書きをしているドキュメントが結構多いので、初心者の自分は「ドキッ」としてしまいますね(^^;)

「strcpy」関数

「文字列データのコピー」が行えるのが「strcpy」関数です。

「文字列のデータを格納した配列」と「コピー先の配列」を用意しておき、「strcpy」関数で値をコピーするのですが、プログラムを書いてみると、

#include <stdio.h>

int main(void) {

    // 全角と半角文字の混合
    char data1[2048] = "あいうえお";
    char data2[2048] = "";

    printf("before data1=「%s」\n", data1);
    printf("before data2=「%s」\n", data2);

    strcat(data2, data1);

    printf("after data1=「%s」\n", data1);
    printf("after data2=「%s」\n", data2);

    return 0;
}

のようになり、これを実行してみると、

before data1=「あいうえお」
before data2=「」
after data1=「あいうえお」
after data2=「あいうえお」

のように表示されて、「data2」の配列に「data1」の文字列がコピーされているのがわかりますね。

この関数も、「コピー先の配列のサイズ」が、「コピー元のサイズ」より小さいと、メモリの内容を上書きしてしまうそうなので、使う時には気を付けないといけませんね。

初めは「代入演算子」でコピーができるんでは?と思っていたのですが、配列の変数には「配列の先頭要素のメモリアドレス」が入っているので、代入演算子が使えないことに気が付きました。

「strcmp」関数

「strcmp」関数は、「文字列の格納された配列変数」の文字列が等しいかを調べることができる関数です。

この関数は、

strcmp(文字列配列1, 文字列配列2);

のように利用していきます。

文字列の配列の値が等しいと、戻り値には「0」が返ってきます。

例えば、さっきのプログラムに追加をして、

#include <stdio.h>

int main(void) {

    // 全角と半角文字の混合
    char data1[2048] = "あいうえお";
    char data2[2048] = "";

    printf("before data1=「%s」\n", data1);
    printf("before data2=「%s」\n", data2);

    int i = strcmp(data1, data2);

    if( i == 0 ){
        printf("data1とdata2の文字列は等しい\n");
    } else {
        printf("data1とdata2の文字列は等しくない\n");
    }

    strcat(data2, data1);

    printf("after data1=「%s」\n", data1);
    printf("after data2=「%s」\n", data2);

    i = strcmp(data1, data2);

    if( i == 0 ){
        printf("data1とdata2の文字列は等しい\n");
    } else {
        printf("data1とdata2の文字列は等しくない\n");
    }

    return 0;
}

のように書くと、

before data1=「あいうえお」
before data2=「」
data1とdata2の文字列は等しくない
after data1=「あいうえお」
after data2=「あいうえお」
data1とdata2の文字列は等しい

のように表示されます。

「文字列操作」の関数について学んできましたが、「C言語」の文字列操作は、他のプログラム言語と比べると、難しいという印象でした。

特に「バッファサイズ」の管理が大変ですね(^^;)

初心者には「学ぶハードルが高い言語」というのが正直な感想ですが、もっと勉強していきたいと思います。

→(前へ)「C言語」の「ファイル操作の仕組み」とプログラムの書き方を学ぼう!

→(次へ)「C言語」の「数学関連関数」の使い方を学ぶ(苦手・・・)

→「Twitter:@satoru78888」

HOMEへ