メイン画像

C言語 - 文字と文字列と文字列の配列

C言語 - 文字と文字列と文字列の配列


C言語での文字の扱いを整理する。

文字

C言語で文字を扱うときは文字型(char 型)のデータを使う。

1つの半角文字はシングルクォート(')で囲む。

char ch = 'A';

NOTE: 半角文字=ASCIIコード表に定義された文字

文字列

複数の半角文字、あるいは全角文字はダブルクォート(")で囲む。

変数に入れるときは、文字型の配列とし、配列の最後にヌル文字('\0')を置く。

C言語のデータ型には文字列を表す型がないため、このようにして表現する必要がある。

 

変数の宣言と同時に値を設定する場合、ヌル文字('\0')は自動で追加される。

次の場合、変数 chs は “ABC” とヌル文字が格納された、要素数4の文字型の配列となる。

char chs[] = "ABC";

全角文字も同様に文字型の配列で表現する。

char str[] = "あ";

 

半角文字の文字列だったら、1文字ずつ取り出すのも簡単にできる。

1つずつ要素にアクセスしていけばいい。

char chs[] = "ABC";

printf("%c\n", chs[0]);
// → A

printf("%c\n", chs[1]);
// → B

printf("%c\n", chs[2]);
// → C

 

しかし、全角文字も含まれていると一気に面倒になる。

UTF-8 で gcc でコンパイルした場合、全角文字は1文字あたり3バイトになる。

1文字取り出すのに配列の要素3つにアクセスしないといけない。

char mchs[] = "あいう";

printf("%c%c%c\n", mchs[0], mchs[1], mchs[2]);
// → あ

printf("%c%c%c\n", mchs[3], mchs[4], mchs[5]);
// → い

printf("%c%c%c\n", mchs[6], mchs[7], mchs[8]);
// → う

 

半角と全角文字の混在なんて考えただけで面倒くさい。

文字列の配列

複数の文字列を表すには、文字型の二次元配列を使えば良い。

char strlist[][128] = { "ABC", "あいうえお", '\0' };

int i;
int len = sizeof(strlist) / sizeof(strlist[0]);
for (i = 0; i < len; i++) {
    printf("%d: %s\n", i + 1, strlist[i]);
}

二次元配列を宣言と同時に初期化する場合、一次元目の要素数は省略できる。

char strlist[][128] = { "ABC", "あいうえお", '\0' };

一次元目の要素数は、配列全体のサイズ ÷ 二次元目の配列サイズ で求められる。
(この場合 384 ÷ 128 = 3 となる)

int len = sizeof(strlist) / sizeof(strlist[0]);

動的にメモリを確保する方法もある

ちなみに配列ではなく動的にメモリを確保する方法もある。

(今回の例だと動的に確保するメリットはないんだけど、一応こんなやり方もあるよ、という意味で載せておく)

文字列

次のプログラムは “あいう” をメモリに格納し、標準出力に出力する。

int bytelen = sizeof(char) * (strlen("あいう") + 1);
char *mchs = (char *)malloc(bytelen);
if ( mchs == NULL ) {
    perror("malloc err");
    return 1;
}

if ( strcpy_s(mchs, bytelen, "あいう") != 0 ) {
    perror("strcpy_s err");
} else {
    printf("%s\n", mchs);
}

free(mchs);

まず malloc 関数でメモリを動的に確保する。

int bytelen = sizeof(char) * (strlen("あいう") + 1);
char *mchs = (char *)malloc(bytelen);

次に strcpy_s 関数で文字列をメモリに入れる。

strcpy_s(mchs, bytelen, "あいう")

最後に free 関数で確保したメモリを解放する。

free(mchs);

文字列の配列

次のプログラムは “ABC” 、 “あいうえお” 、空文字の3つをそれぞれメモリに格納し、標準出力に出力する。

char **strlist = (char **)malloc(sizeof(char *) * 3);
if ( strlist == NULL ) {
    perror("malloc err");
    return 1;
}

int i;
for (i = 0; i < 3; i++) {
    int bytelen = sizeof(char) * 128;
    strlist[i] = (char *)malloc(bytelen);
    if ( strlist[i] == NULL ) {
        perror("malloc err");
        continue;
    }

    switch (i) {
        case 0:
            strcpy_s(strlist[i], bytelen, "ABC");
            break;
        case 1:
            strcpy_s(strlist[i], bytelen, "あいうえお");
            break;
        case 2:
            strcpy_s(strlist[i], bytelen, '\0');
            break;
    }
}

for (i = 0; i < 3; i++) {
    if ( strlist[i] != NULL ) {
        printf("%d: %s\n", i + 1, strlist[i]);
        free(strlist[i]);
    }
}

free(strlist);

まずは3つの文字列を入れるためのメモリを確保する。

char **strlist = (char **)malloc(sizeof(char *) * 3);

次にループでそれぞれの文字列を入れるためのメモリを確保する。

確保できたらメモリに文字列を入れる。
(strcpy_s 関数のエラー処理は面倒なので省略)

for (i = 0; i < 3; i++) {
    int bytelen = sizeof(char) * 128;
    strlist[i] = (char *)malloc(bytelen);

    switch (i) {
        case 0:
            strcpy_s(strlist[i], bytelen, "ABC");
            break;

そして新しいループでメモリに入れた文字列を順番に出力する。

その後、それぞれで確保したメモリを解放する。

for (i = 0; i < 3; i++) {
    if ( strlist[i] != NULL ) {
        printf("%d: %s\n", i + 1, strlist[i]);
        free(strlist[i]);
    }
}

最後に全体のメモリを解放する。

free(strlist);

 

何度も書くがあまり良い例ではなかった。

これなら静的メモリ確保(配列使用)で十分だろう。

動的メモリ確保のちゃんとしたやつは、何かのタイミングで書き残しておきたい。


アカウントを作成 して、もっと沢山の記事を読みませんか?


この記事が気に入ったら ことりと さんを応援しませんか?
メッセージを添えてチップを送ることができます。


この記事にコメントをしてみませんか?


酒とアクアリウムが最近の楽しみ。

おすすめの記事