Thinkers'Studio
JavaとC言語の自習ツール
atof と strtod の違い
 atofstrtod も <stdlib.h> に定義されている関数です。 どちらも文字列を渡すと double型の浮動小数点数に変換して返します。 なぜ同じ機能の関数が2つあるのでしょう? 今回は、それらの違いについての話題です。

atof と strtod で異なる点

 正しく変換できるときは、動作に違いはありません。
 変換できない文字が含まれていたり、double 型に格納できる範囲を超えているとき、strtod はそのことが分かるようになっています。 エラー処理が必要なときは strtod 関数を使います。

atofstrtod の形式 】
 double atof( const char *s )
  • s を double に変換して返す
 double strtod( const char *s, char **endp )
  • s を double に変換して返す
  • s に変換不能な部分があれば、そこから後ろの文字列が endp にセットされる
  • 戻り値や errno により、オーバーフローやアンダーフローのエラーが検出できる(下記で説明)
atofstrtod の使い方例と比較のプログラム 】
#include <stdio.h>
#include <stdlib.h>
main()
{
    int i;
    double d;
    char *ep;
    char str[][24] = { "0.543f", "  3.", "ABCD", "123e3", "1.56xy3" };

    for( i = 0; i < 5; i++ ) {
        printf( "元の文字列:%s\n", str[i] );
        d = atof( str[i] );         printf( "  atof   結果:%f\n", d );
        d = strtod( str[i], &ep ); printf( "  strtod 結果:%f", d );
        if( *ep != '\0' ) printf( "(変換不能部:%s)\n", ep );
        else              putchar( '\n' );
    }
}
 実行結果
元の文字列:0.543f
  atof   結果:0.543000
  strtod 結果:0.543000(変換不能部:f)
元の文字列:  3.
  atof   結果:3.000000
  strtod 結果:3.000000
元の文字列:ABCD
  atof   結果:0.000000
  strtod 結果:0.000000(変換不能部:ABCD)
元の文字列:123e3
  atof   結果:123000.000000
  strtod 結果:123000.000000
元の文字列:1.56xy3
  atof   結果:1.560000
  strtod 結果:1.560000(変換不能部:xy3)
 変換不能部を調べる必要が無いときは、d = strtod( str[i], NULL ); としても構いません。 atof と同じことになります。

strtod のエラーを調べる方法

 変換の結果が大き過ぎたり(オーバーフロー)、小さ過ぎたり(アンダーフロー)して double型に格納できないとき、strtod は次のようにしてエラーを知らせます。
  ・ オーバーフローしたとき --- 戻り値に範囲エラーを示す HUGE_VAL という値が返される
  ・ アンダーフローしたとき --- 戻り値が 0 で、errno に ERANGE がセットされる
 プログラムコードでは、errno.h と math.h を include して、次のように調べます
#include <errno.h>
#include <math.h>
   :
errno = 0;

d = strtod( str[i], &ep );
if( d == HUGE_VAL ) {
    //オーバーフロー時の処理
} else if( d == 0 && errno == ERANGE ) {
    //アンダーフロー時の処理
}
  :

(今回のクイズです)
 身長を入力するプログラムがあります。指定は、cm単位と m単位のどちらでもよいものとします。
 cm単位のデータに統一して、double型の配列に入れるにはどうすればよいでしょうか?
  char hstr[][24] = { "172.3cm", "1.56m", "184.5cm", "1.675m" };  の指定を
  double cmh[4]; //cm単位の身長データ配列  に格納するには?
   (答えは、次回のC言語の Tips で ・・・)

[ 関連記事 ] atof関数の自前処理解説

前回のクイズの答え: (前回の問題を見る
追加が必要な部分は下記の青文字です。
fprintf( fp, "処理年月:%04d/%02d\n", year, month ); //追加
fprintf( fp, "エリア名,平均気温,最低気温,最高気温,最高-最低\n" ); //ヘッダに項目追加
for( i = 0; i < DTCNT; i++ ) {
    fprintf( fp, "\"%s\",%f,%f,%f,%lf\n"//データ出力 最高気温-最低気温を追加
    , res[i].area, res[i].avg, res[i].min, res[i].max, res[i].max-res[i].min ); 
}