C言語の文字列のポインタを比較する

525, 2022-07-29

目次

C言語の文字列のポインタを比較する

C言語の文字列のポインタを比較するときはstrcmp()関数を使うのが一般的です。
strcmp()string.hをインクルードすると使うことができます。

strcmp()は第1引数と第2引数の文字列が等しければ0を返します。
等しくなければ0以外を返します。

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

int main(void) {
    if (strcmp("abc", "abc") == 0) {
        printf("等しい\n");
    }

    if (strcmp("abc", "def") != 0) {
        printf("等しくない\n");
    }

    return 0;
}

↑のコードを実行すると↓の結果になります。

等しい
等しくない

関連記事

文字列とポインタの違い

C言語では文字列と言うとダブルクオーテーションで囲まれたものを指して言うことが多いです。

"abcdef123"

これは正式には文字列リテラルと呼ばれます。
この文字列はプログラムに静的に埋め込まれる文字列です。
そのためプログラムを解析すればこの文字列は見ることができます。

この文字列リテラルを変数に入れる場合、2つの方法があります。
1つは配列に文字列リテラルを保存する方法。

char str[] = "abcdef123";

もう1つはポインタに文字列リテラルを格納する方法です。

const char *str = "abcdef123";


前者の配列に文字列リテラルを保存する方法では文字列リテラルは配列にコピーされます。
つまり配列の値を変更しても元の文字列リテラルは影響がありません。

char str[] = "abcdef123";
str[0] = 'A';
str[1] = 'B';

いっぽうポインタに文字列リテラルを格納した場合は、そのポインタは文字列リテラルのアドレスを持っているだけです。
文字列リテラルというのは一度定義したらその後の変更は禁止されています。
そのため無理に文字列リテラルの値を変えようとするとエラーやバグになります。

char *str = "abcdef123";
str[0] = 'A';  // error! or bug!

そのためポインタに文字列リテラルを保存するときはconst修飾子を付けるのが普通です。

const char *str = "abcdef123";

「文字列のポインタ」と言った場合、そのポインタの持つアドレスは2種類あります。
1つが文字列リテラルのアドレスでもう1つが文字配列のアドレスです。

// 文字配列のポインタp1
char s1[] = "good";
const char *p1 = s1;

// 文字列リテラルのポインタp2
const char *p2 = "day";

この2種類のアドレスを持つポインタは同じように扱うことができます。
ただし文字列リテラルの場合は変更ができない点を除いて。

文字列のポインタの比較ではstrcmp()は書き換え等はしませんのでこの2種類のポインタは特に意識せずに混ぜて使うことができます。

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

int main(void) {
    // 文字配列のポインタp1
    char s1[] = "good";
    const char *p1 = s1;

    // 文字列リテラルのポインタp2
    const char *p2 = "day";

    if (strcmp(p1, p2) == 0) {
        printf("等しい\n");
    } else {
        printf("等しくない\n");
    }

    return 0;
}

結果↓。

等しくない

strcmp関数を使ってstreq関数を作る

strcmp()で文字列は比較できますがこの関数はあまり直感的ではありません。
なんで結果を整数で返すの? と思った人も多いかと思います。

C言語は歴史のある言語なのでこういった現代的な視点から見ると不可解な関数も多くあります。
その実装にはちゃんと理由があるのですがその理由もドキュメントとして残ってないものが大半です。
そういう時はC言語では自分で満足のいくものを作る、というのが普通です。

たとえばstreq()関数というものを作ります。
これは例えば↓のように定義します。

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

bool streq(const char *lhs, const char *rhs) {
    return strcmp(lhs, rhs) == 0;
}

int main(void) {
    if (streq("abc", "abc")) {
        printf("等しい\n");
    }

    if (!streq("abc", "def")) {
        printf("等しくない\n");
    }

    return 0;
}


このようにstreq()を定義しておけば直感的に文字列を比較することもできます。
関数のラップによる速度コストを気にする場合はinline関数にしても良いと思います。



この記事のアンケートを送信する