第14回|C言語で文字列処理の基本を学ぶ:char配列として文字列を正しく扱う

当サイトでは、コンテンツの一部に広告を掲載しています。
第14回|C言語で文字列処理の基本を学ぶ:char配列として文字列を正しく扱う

はじめてのC言語 | 第14回

目次

はじめに

前回は、配列とポインタの関係を学びました。
今回は、その知識を使って「文字列処理の基本」を整理します。

C言語では、文字列は特別な型ではなく、char の配列として扱われます。
そのため、配列の考え方を理解していることが重要です。

この回の目的は次の5点です。

  • 文字列が char 配列であることを理解する
  • 文字列の終わりを表す '\0' の意味を確認する
  • strlen strcpy strcmp の基本を学ぶ
  • 文字列処理でサイズに注意する理由を理解する
  • 初学者が起こしやすいミスを先に押さえる

文字列は char 配列である

C言語では、文字列は文字の並びを char 配列で表します。
たとえば "cat" は、内部では次のような文字の並びとして扱われます。

{'c', 'a', 't', '\0'}

最後の '\0' は、文字列の終わりを表す特別な文字です。
これをヌル文字と呼びます。

printf("%s", name); のような文字列表示は、この '\0' が現れるまで文字を読み取っています。

まずは文字列を表示する

ソースコード

string_print.c という名前で保存します。

#include <stdio.h>

int main(void) {
    char name[] = "cat";

    printf("%s\n", name);

    return 0;
}

実行手順

1. 作業ディレクトリに移動する

cd ~/Desktop

2. コンパイルする

clang string_print.c -o string_print

3. 実行する

./string_print

実行結果:

cat

コードの読み方

char name[] = “cat”;

char name[] = "cat";

これは文字列 "cat"char 配列として保存しています。
内部では c a t に加えて、最後に '\0' も入ります。

そのため、この配列には4個分の領域が必要です。

%s

printf("%s\n", name);

%s は文字列を表示するための書式指定子です。
name の先頭から読み進めて、'\0' が出るまで表示します。

‘\0’ の意味を確認する

文字列では、見えている文字数と配列の必要サイズが一致しないことがあります。
これは終端の '\0' が必要だからです。

サンプルコード

#include <stdio.h>

int main(void) {
    char word[4] = {'c', 'a', 't', '\0'};

    printf("%s\n", word);

    return 0;
}

実行結果:

cat

このように、文字列として扱うには最後の '\0' が必要です。

文字列の長さを調べる strlen

文字列の長さを調べるには strlen を使います。
strlen'\0' より前の文字数を数えます。

#include <stdio.h>
#include <string.h>

int main(void) {
    char word[] = "apple";

    printf("%zu\n", strlen(word));

    return 0;
}

実行結果:

5

なぜ5になるのか

"apple" には a p p l e の5文字があります。
末尾には '\0' がありますが、strlen はそれを長さに含めません。

文字列をコピーする strcpy

文字列を別の配列にコピーするときは strcpy を使います。

#include <stdio.h>
#include <string.h>

int main(void) {
    char source[] = "cat";
    char dest[4];

    strcpy(dest, source);
    printf("%s\n", dest);

    return 0;
}

実行結果:

cat

dest[4] が必要な理由

"cat" は3文字ですが、最後に '\0' も必要です。
そのため、コピー先には最低でも4個分の領域が必要です。

文字列を比較する strcmp

文字列同士を比較するときは、== ではなく strcmp を使います。

#include <stdio.h>
#include <string.h>

int main(void) {
    char a[] = "cat";
    char b[] = "cat";

    if (strcmp(a, b) == 0) {
        printf("same\n");
    }

    return 0;
}

実行結果:

same

なぜ == ではないのか

配列同士の中身を == で比較することはできません。
文字列の内容が同じかどうかを調べたいときは、1文字ずつ比較する strcmp を使います。

strcmp の戻り値は次のように使います。

  • 0 : 同じ文字列
  • 0 より小さい値 : 左の文字列のほうが小さい
  • 0 より大きい値 : 左の文字列のほうが大きい

初学者の段階では、まず strcmp(a, b) == 0 が「同じ」という判定だと覚えれば十分です。

文字列処理でサイズに注意する

文字列処理では、配列の大きさが足りないと問題が起こります。

次のコードを見てください。

char dest[3];
strcpy(dest, "cat");

"cat" は3文字ですが、終端の '\0' も必要です。
そのため、実際には4個分の領域が必要です。

このような不足した領域への書き込みは未定義動作になります。
文字列を扱うときは、必ず '\0' の分も含めてサイズを考えます。

初心者がつまずきやすい点

文字数と配列サイズは同じではない

文字列 "cat" は3文字ですが、必要な領域は4です。

char word[4] = "cat";

このように、終端文字の分を忘れないようにします。

strlen は配列全体の大きさではない

strlen(word) は文字列の長さを返します。
配列全体に確保された要素数を返すわけではありません。

strcpy はコピー先のサイズ不足を自動では防がない

strcpy は便利ですが、コピー先が十分な大きさかどうかを自動では確認しません。
そのため、コピー前に必要サイズを意識する必要があります。

文字列比較に == を使わない

文字列の内容を比べるときは strcmp を使います。
== で比較するという考え方を持ち込まないようにします。

よくあるエラー

implicit declaration of function ‘strlen’

原因: strlen を使っているのに #include <string.h> を書いていません。
対処: 文字列関数を使うときは #include <string.h> を追加します。

implicit declaration of function ‘strcpy’

原因: strcpy を使っているのに #include <string.h> を書いていません。
対処: #include <string.h> を追加します。

実行結果がおかしい、または異常終了する

原因: 文字列の終端 '\0' がない、または配列サイズが不足している可能性があります。
対処: 配列サイズと終端文字の有無を確認します。

練習用コード

文字列の長さを表示する

#include <stdio.h>
#include <string.h>

int main(void) {
    char word[] = "banana";

    printf("%zu\n", strlen(word));

    return 0;
}

2つの文字列を比較する

#include <stdio.h>
#include <string.h>

int main(void) {
    char a[] = "dog";
    char b[] = "cat";

    if (strcmp(a, b) == 0) {
        printf("same\n");
    } else {
        printf("different\n");
    }

    return 0;
}

実行結果:

different

まとめ

今回のポイントは次のとおりです。

  • 文字列は char 配列として表される
  • 文字列の終わりには '\0' が必要である
  • strlen'\0' を含まない文字数を返す
  • strcpy ではコピー先に十分なサイズが必要である
  • 文字列比較では strcmp を使う
  • 文字列処理ではサイズ不足が重大な不具合につながる

この回では、C言語の文字列が char 配列として扱われることを確認しました。
文字列処理では、文字そのものだけでなく、終端文字 '\0' と配列サイズを常に意識する必要があります。

次回予告

次は、関数と配列の受け渡しを学びます。
配列や文字列を関数に渡す考え方を整理すると、より実用的なプログラムを書きやすくなります。

あわせて読みたい
第15回|C言語で関数と配列の受け渡しを学ぶ:配列を処理する関数を作る はじめてのC言語 | 第15回 はじめに 前回は、文字列処理の基本を学びました。今回は、配列を関数に渡して処理する方法を整理します。 配列を使うプログラムでは、合計...

さらに学びたいあなたへ

用途ごとに選ぶ Linux のおすすめ本

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

のいのアバター のい UNIX Cafe マスター

Macintosh Color Classicから始まった旅は、長いWindows時代を経て、Windows10のサポート終了をきっかけにUNIXの世界へ戻ってきました。UNIX Cafeでは、UNIX・Linux・そしてMacな世界を、むずかしい言葉を使わず、物語のように書いています。プログラミングは、アイデアをコンピューターに伝えるための言葉です。簡単な単語と文法を覚えれば、誰でもコマンドを使えます。ぜひ一度、やさしいプログラミングの世界をのぞいてみてください。

Created by UNIX Cafe

目次