閉じる

C言語のatofで文字列を浮動小数点に変換する使い方

文字列として受け取った数値を実際に計算で使える浮動小数点数に変換する場面は、ユーザー入力や設定ファイルの読み込みなどで頻繁に登場します。

C言語ではatof関数が手軽に使えますが、使いどころと注意点を理解していないと意図しない結果を招きます。

ここでは初心者でも迷わないように、基本から実践、そして落とし穴まで丁寧に解説します。

C言語のatofの基本

何をする関数か

atof(ASCII to floating)は、数値を表す文字列をdouble型に変換する関数です。

先頭の空白や符号を処理し、可能な範囲で数値を読み取ります。

読み取りは「数字として解釈できない文字に出会ったところで停止」します。

シグネチャ

関数の宣言は次の通りです。

  • 戻り値: double
  • 引数: 変換するヌル終端文字列の先頭ポインタconst char *nptr

動作の概要

  • 先頭の空白(スペース、タブなど)は読み飛ばします。
  • 符号+-を受け付けます。
  • 整数部、.(小数点)、小数部、指数部e/Eなどを解釈します。
  • 解釈できない文字に到達したらそこまでを数値として扱います。

必要なヘッダ

atof<stdlib.h>で宣言されています。

使用するソースファイルの先頭でインクルードします。

C言語
#include <stdlib.h>  // atof
#include <stdio.h>

int main(void) {
    const char *s = "3.14";
    double x = atof(s);  // 文字列をdoubleへ変換
    printf("x = %f\n", x);
    return 0;
}

対応する書式

典型的に解釈される書式を例で示します。

小数点は標準のCロケールでは.(ピリオド)です。

例の文字列主な解釈備考
12.3412.34通常の小数
.50.5先頭の0は省略可
5.5.0末尾の0は省略可
1e31000指数表記(e/E)
-2.5e-2-0.025符号と指数の組み合わせ
” +42″42先頭空白と+
3.14abc3.14数字以外の文字で読み取り停止
0x1.8p+13.016進浮動小数(C99以降)。初心者は無理に使わないでOK

実装によってはinf/infinitynanも受け付けますが、移植性と可読性の観点で初心者は避けるのが無難です。

戻り値

  • 変換に成功した場合は、読み取れた範囲の数値をdoubleで返します
  • 変換可能な部分がまったく無い場合は0.0を返します。
  • 注意: 0.0は「本当に0だった」場合と「失敗した」場合の両方で返るため、エラー判定には使えません

atofの使い方

文字列を浮動小数点数(double)に変換

最も基本的な使い方です。

配列の複数の文字列をatofで変換して表示します。

C言語
#include <stdio.h>
#include <stdlib.h>

// 基本的なatofの使い方デモ
int main(void) {
    const char *inputs[] = {
        "12.34", "0.001", "1e3", ".5", "5.", "  42.0", "-3.14", "+6.022e23"
    };

    for (size_t i = 0; i < sizeof(inputs)/sizeof(inputs[0]); ++i) {
        const char *s = inputs[i];
        double val = atof(s);  // 文字列からdoubleへ変換
        // %.17g は double を簡潔かつ誤解の少ない形で表示しやすい
        printf("\"%s\" -> %.17g\n", s, val);
    }
    return 0;
}
実行結果
"12.34" -> 12.34
"0.001" -> 0.001
"1e3" -> 1000
".5" -> 0.5
"5." -> 5
"  42.0" -> 42
"-3.14" -> -3.14
"+6.022e23" -> 6.022e+23

表示フォーマットの補足

printfで浮動小数を見やすく表示するには%f%gを使います。

%gは不要な0や指数表記を自動選択するため、サンプルのようなデモに向いています。

空白や符号(+/-)の扱い

atof先頭の空白を無視し、符号も処理します。

C言語
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    const char *a = "   -12.34";
    const char *b = "+5.0e2";
    const char *c = " \t +0.75";

    printf("\"%s\" -> %f\n", a, atof(a)); // -12.340000
    printf("\"%s\" -> %f\n", b, atof(b)); // 500.000000
    printf("\"%s\" -> %f\n", c, atof(c)); // 0.750000
    return 0;
}
実行結果
"   -12.34" -> -12.340000
"+5.0e2" -> 500.000000
" 	 +0.75" -> 0.750000

数字以外の文字が混ざる場合

数字以外の文字が出た地点で読み取りを停止します。

残りの文字は無視されます。

C言語
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    const char *s1 = "3.14abc";
    const char *s2 = "123xyz456";
    const char *s3 = "abc";
    const char *s4 = "1.2.3";

    printf("\"%s\" -> %.6f\n", s1, atof(s1)); // 3.140000
    printf("\"%s\" -> %.6f\n", s2, atof(s2)); // 123.000000
    printf("\"%s\" -> %.6f\n", s3, atof(s3)); // 0.000000 (変換失敗でも0)
    printf("\"%s\" -> %.6f\n", s4, atof(s4)); // 1.200000 (2つ目の'.'で停止)
    return 0;
}
実行結果
"3.14abc" -> 3.140000
"123xyz456" -> 123.000000
"abc" -> 0.000000
"1.2.3" -> 1.200000

「無視される残りの文字」が存在してもエラーにはなりません

この仕様が便利な一方で、厳密な入力検証には向かないことを覚えておくと安心です。

atofの注意点

エラー判定はできない

atof単体では「変換に失敗したのか、0なのか」を区別できません

また、オーバーフローやアンダーフローが発生しても、errnoや未消費文字位置を直接知る手段がありません。

入力検証やエラーハンドリングが必要な場面ではより厳密なstrtodを使ってください(後述)。

0と失敗の区別に注意

次の例では、"0""abc"0.0になります。

出力だけではどちらが来たのか判断できません

C言語
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    const char *inputs[] = { "0", "0.0", "0abc", "abc" };
    for (size_t i = 0; i < sizeof(inputs)/sizeof(inputs[0]); ++i) {
        printf("\"%s\" -> %f\n", inputs[i], atof(inputs[i]));
    }
    return 0;
}
実行結果
"0" -> 0.000000
"0.0" -> 0.000000
"0abc" -> 0.000000
"abc" -> 0.000000

この曖昧さがあるため、入力の妥当性確認を伴う場面でatofを使うのは避けるのが安全です。

入力はヌル終端の文字列にする

atofヌル終端(末尾が'\0')の文字列を前提に動作します。

ファイルや標準入力から読み込む場合はfgetsなど必ずヌル終端を保証する関数を使いましょう。

C言語
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    char buf[64];

    // fgetsは終端に'
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char buf[64];
// fgetsは終端に'\0'を付けるので安全(バッファサイズ-1文字まで)
if (fgets(buf, sizeof(buf), stdin) != NULL) {
// 入力末尾の改行が残る場合は取り除く
for (char *p = buf; *p != '\0'; ++p) {
if (*p == '\n') { *p = '\0'; break; }
}
double x = atof(buf);
printf("入力: \"%s\" -> %f\n", buf, x);
}
return 0;
}
'を付けるので安全(バッファサイズ-1文字まで) if (fgets(buf, sizeof(buf), stdin) != NULL) { // 入力末尾の改行が残る場合は取り除く for (char *p = buf; *p != '
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char buf[64];
// fgetsは終端に'\0'を付けるので安全(バッファサイズ-1文字まで)
if (fgets(buf, sizeof(buf), stdin) != NULL) {
// 入力末尾の改行が残る場合は取り除く
for (char *p = buf; *p != '\0'; ++p) {
if (*p == '\n') { *p = '\0'; break; }
}
double x = atof(buf);
printf("入力: \"%s\" -> %f\n", buf, x);
}
return 0;
}
'; ++p) { if (*p == '\n') { *p = '
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char buf[64];
// fgetsは終端に'\0'を付けるので安全(バッファサイズ-1文字まで)
if (fgets(buf, sizeof(buf), stdin) != NULL) {
// 入力末尾の改行が残る場合は取り除く
for (char *p = buf; *p != '\0'; ++p) {
if (*p == '\n') { *p = '\0'; break; }
}
double x = atof(buf);
printf("入力: \"%s\" -> %f\n", buf, x);
}
return 0;
}
'; break; } } double x = atof(buf); printf("入力: \"%s\" -> %f\n", buf, x); } return 0; }

途中でヌル終端しないバイト列を渡すと未定義動作になり、クラッシュや誤変換の原因になります。

厳密な変換はstrtod

厳密に検証したい場合はstrtodを使います。

strtod読み取り終了位置を返すため、未消費文字があるかを判定でき、errnoで範囲エラーも検出できます。

C言語
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>   // isspace
#include <errno.h>   // errno, ERANGE

// 文字列全体が正しい小数(先頭空白可、末尾空白可)か検証しつつ変換
int parse_double_strict(const char *s, double *out) {
    errno = 0;

    // 先頭空白をスキップ(任意)
    while (isspace((unsigned char)*s)) { ++s; }

    char *end = NULL;
    double val = strtod(s, &end);

    if (s == end) {
        // 一文字も読み取れなかった => 変換失敗
        return 0;
    }
    if (errno == ERANGE) {
        // 範囲外(オーバーフロー/アンダーフロー)
        return 0;
    }
    // 末尾空白をスキップして、完全に読み切ったか確認
    while (isspace((unsigned char)*end)) { ++end; }
    if (*end != '
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>   // isspace
#include <errno.h>   // errno, ERANGE
// 文字列全体が正しい小数(先頭空白可、末尾空白可)か検証しつつ変換
int parse_double_strict(const char *s, double *out) {
errno = 0;
// 先頭空白をスキップ(任意)
while (isspace((unsigned char)*s)) { ++s; }
char *end = NULL;
double val = strtod(s, &end);
if (s == end) {
// 一文字も読み取れなかった => 変換失敗
return 0;
}
if (errno == ERANGE) {
// 範囲外(オーバーフロー/アンダーフロー)
return 0;
}
// 末尾空白をスキップして、完全に読み切ったか確認
while (isspace((unsigned char)*end)) { ++end; }
if (*end != '\0') {
// 数字の後にゴミが残っている
return 0;
}
*out = val;
return 1;
}
int main(void) {
const char *tests[] = { "123.456", "3.14abc", "abc", "1e309", "  -0.25  " };
for (size_t i = 0; i < sizeof(tests)/sizeof(tests[0]); ++i) {
double v = 0.0;
int ok = parse_double_strict(tests[i], &v);
if (ok) {
printf("\"%s\" -> OK: %.17g\n", tests[i], v);
} else {
printf("\"%s\" -> NG\n", tests[i]);
}
}
return 0;
}
') { // 数字の後にゴミが残っている return 0; } *out = val; return 1; } int main(void) { const char *tests[] = { "123.456", "3.14abc", "abc", "1e309", " -0.25 " }; for (size_t i = 0; i < sizeof(tests)/sizeof(tests[0]); ++i) { double v = 0.0; int ok = parse_double_strict(tests[i], &v); if (ok) { printf("\"%s\" -> OK: %.17g\n", tests[i], v); } else { printf("\"%s\" -> NG\n", tests[i]); } } return 0; }
実行結果
"123.456" -> OK: 123.456
"3.14abc" -> NG
"abc" -> NG
"1e309" -> NG
"  -0.25  " -> OK: -0.25

実運用ではatofよりstrtodを優先し、必要に応じて「入力全体を消費したか」「範囲エラーはないか」をチェックするのが堅牢です。

まとめ

atofは「ざっくり変換する」ための簡便な関数で、先頭空白や符号、指数表記を扱えます。

一方でエラー判定ができず、0と失敗の区別がつかないという大きな制約があります。

ヌル終端の文字列を渡すこと、読み取りが途中で止まってもエラーにならないことを理解したうえで、入力検証が必要な場面ではstrtodを使うのが安全です。

用途に応じてatofstrtodを使い分け、予期せぬバグや誤動作を避けていきましょう。

この記事を書いた人
エーテリア編集部
エーテリア編集部

プログラミングの基礎をしっかり学びたい方向けに、C言語の基本文法から解説しています。ポインタやメモリ管理も少しずつ理解できるよう工夫しています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!