文字列を整数に変換する | Programming Place Plus C言語編 逆引き

トップページC言語編逆引き

このページの概要

以下は目次です。

目的

“100” や “-50” のような文字列を、整数型の値に変換したいとします。前者なら 100、後者なら -50 にします。

“100abc” のように、整数と関係がない文字が登場した場合、その手前までで打ち切ります。 また、“abc100” の場合は、先頭部分が整数と関係がない文字なので、変換に失敗します。

方法①(ato~系の関数を使う)

C言語の標準ライブラリには、文字列から数値へ変換する各種関数があります。変換後の型が int型の atoi関数、long型の atol関数、long long型の atoll関数があります。

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    printf("%d\n", atoi("100"));
    printf("%d\n", atoi("-50"));
    printf("%d\n", atoi("+50"));
    printf("%d\n", atoi("0"));
    printf("%d\n", atoi("100abc"));
    printf("%d\n", atoi("abc100"));
}

実行結果:

100
-50
50
0
100
0

この方法は手軽ですが、変換の失敗を検出する方法がないという欠点があります。 変換できなかった場合の戻り値は 0 になりますから、“0” を変換した場合との区別が付きません。 変換の失敗を検出できる必要がある場合は、方法②を使います。

方法②(strto~系の関数を使う)

C言語の標準ライブラリには、ato~系の関数以外にも、文字列から数値へ変換する各種関数があります。

変換後の型が long型の strtol関数、long long型の strtoll関数、unsigned long型の strtoul関数、unsigned long long型の strtoull関数があります。

方法①で取り上げて ato~系の関数と比べて、お手軽さの面で大きく劣ります。そのため、プログラムが長くなってしまうので、いったん、“100” だけを変換するプログラムを載せます。

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char* str = "100";

    errno = 0;
    char* end;
    long int v = strtol(str, &end, 10);
    if (errno == ERANGE) {
        printf("error\n");
    }
    else if (str == end) {
        printf("can't convert\n");
    }
    else {
        printf("%ld\n", v);
    }
}

実行結果:

100

第1引数に変換したい文字列を指定します。

第2引数は、変換できなかった文字へのポインタを格納するポインタ変数を指定します。これは不要ならヌルポインタで構いませんが、変換の失敗を検出するためには指定が必要です。

第3引数には、何進数の数値なのか(基数)を指定します。

2つの理由で、変換が失敗することがある点に注意が必要です。

1つには、変換後の値が、変換後の型で表現できないほど大きかったり、小さかったりするケースです。このケースでは、errno に ERANGE がセットされるので、これを使って調べられます。

もう1つは、“abc” を変換しようとした場合のように、数値に変換できないケースです。こちらは、第2引数をチェックすることで調べます。変換できなかった文字へのポインタが、変換元の最初の文字を指していたら、1文字も変換できなかったことを示しています。

このように、エラーの扱いを考慮すると、かなり長くなってしまいます。また、基数の指定は 10進数で構わない場合が多いでしょうから、余計かもしれません。そこで、使いやすいようにラップしたものを用意しておくと便利かもしれません。一例として、次のようにできます。

#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

/*
    文字列を long int型へ変換する。

    str:    変換元の文字列。ヌルポインタは不可。
    result: 変換結果を受け取るメモリアドレス。ヌルポインタは不可。
            変換できなかった場合には、何も格納されない。
    戻り値: 変換できた場合は 0以外、変換できなかった場合は 0。
*/
int stol(const char* str, long int* result)
{
    assert(str != NULL);
    assert(result != NULL);

    errno = 0;
    char* end;
    long int num = strtol(str, &end, 10);
    if (errno == ERANGE) {
        return 0;
    }
    else if (str == end) {
        return 0;
    }

    *result = num;
    return 1;
}

int main(void)
{
    long int v;

    if (stol("100", &v)) {
        printf("%ld\n", v);
    }
    else {
        printf("failed\n");
    }
}

実行結果:

100

この場合、変換できたのかできなかったのかだけを判定できるようにしています。 成否は戻り値で判別するので、戻り値のパターンを増やせば、 変換できなかった理由を区別できるように対応することは可能です。


参考リンク


更新履歴

’2018/4/20 「NULL」よりも「ヌルポインタ」が適切な箇所について、「ヌルポインタ」に修正。

’2017/7/20 strto~系の関数のエラーチェックについての文面を改めた。

’2017/6/11 新規作成。



逆引きのトップページへ

C言語編のトップページへ

Programming Place Plus のトップページへ



はてなブックマーク に保存 Pocket に保存 Facebook でシェア
X で ポストフォロー LINE で送る noteで書く
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー
先頭へ戻る