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

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

このページの概要

以下は目次です。

目的

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

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

方法①(atof関数を使う)

C言語の標準ライブラリに含まれている atof関数を使うと、文字列を double型の値に変換できます。

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

int main(void)
{
    printf("%lf\n", atof("12.3"));
    printf("%lf\n", atof("-12.3"));
    printf("%lf\n", atof("+12.3"));
    printf("%lf\n", atof("0"));
    printf("%lf\n", atof("12.3abc"));
    printf("%lf\n", atof("abc12.3"));
}

実行結果:

12.300000
-12.300000
12.300000
0.000000
12.300000
0.000000

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

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

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

変換後の型が double型の strtod関数、float型の strtof関数、long double型の strtold関数があります。

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

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

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

    errno = 0;
    char* end;
    double v = strtod(str, &end);
    if (errno == ERANGE) {
        printf("error\n");
    }
    else if (str == end) {
        printf("can't convert\n");
    }
    else {
        printf("%lf\n", v);
    }
}

実行結果:

12.300000

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

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

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

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

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

このように、エラーの扱いを考慮すると、かなり長くなってしまいます。そこで、使いやすいようにラップしたものを用意しておくと便利かもしれません。一例として、次のようにできます。

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

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

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

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

    *result = num;
    return 1;
}

int main(void)
{
    double v;

    if (stod("12.3", &v)) {
        printf("%lf\n", v);
    }
    else {
        printf("failed\n");
    }
}

実行結果:

12.300000

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


参考リンク


更新履歴

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

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

’2017/6/19 新規作成。



逆引きのトップページへ

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

Programming Place Plus のトップページへ



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