
C言語基礎|atoi と atof の使い方
文字列の数字を“そのまま計算”に変える!atoi と atof を使って、入力処理を一気にラクにしよう。
C言語では、キーボード入力やファイルから読んだ値が、まず文字列として手に入ることがよくあります。
そこで活躍するのが atoi(整数へ) と atof(実数へ)。どちらも「数字っぽい文字列」を数値型に変換してくれる便利な関数です。
ただし、便利なぶん注意点もあります。とくに 変換できないときの判定が難しい、オーバーフロー時の動作が保証されない など、落とし穴も一緒に覚えておくのがコツです。

atoi / atof とは何をする関数?
まず全体像(表)
| 関数 | 変換先の型 | 役割 | ヘッダ |
|---|---|---|---|
| atoi | int | 文字列 → 整数 | stdlib.h |
| atof | double | 文字列 → 浮動小数点数 | stdlib.h |
| atol | long | 文字列 → long | stdlib.h |
| atoll | long long | 文字列 → long long | stdlib.h |
この表の見方(説明)
- 「どの関数がどの型に変換するのか」を一発で整理するための表です。
- atoi と atof を中心に、同じ仲間(atol / atoll)も並べて、使い分けが分かるようにしています。
書式(関数の形)と意味
atoi
- ヘッダ:#include <stdlib.h>
- 形式:int atoi(const char *nptr);
何をする関数か
- nptr が指す文字列を int に変換します。
重要な注意
- 変換結果が int の範囲に収まらないときの動作は定義されません(要するに安全ではない)。
atof
- ヘッダ:#include <stdlib.h>
- 形式:double atof(const char *nptr);
何をする関数か
- nptr が指す文字列を double に変換します。
重要な注意
- 変換結果が double で表現できないときの動作は定義されません(こちらも安全ではない)。
変換のルール(どう読んで、どこで止まる?)
atoi / atof は、文字列の先頭から「数値として読める部分」を読み取って変換します。イメージはこんな感じです。
変換の読み取りイメージ(図)
入力: " -12abc"
↑空白は飛ばす
↑符号OK
↑数字を読む
↑ここで止まる(aは数字じゃない)
結果: -12
この図の説明
- 先頭の空白をスキップ → 符号(+/-)を読む → 数字が続く限り読む → 途中で非数字が出たらそこで終了、という流れを示しています。
- “全部が数字である必要はない” という点が、初心者がつまずきやすいポイントです。
よくある入力と結果(表)
| 入力文字列 | atoi の結果 | atof の結果 | ひとこと |
|---|---|---|---|
| 123 | 123 | 123.0 | ふつうにOK |
| -45 | -45 | -45.0 | 符号OK |
| 12abc | 12 | 12.0 | 途中で止まる |
| abc12 | 0 | 0.0 | 先頭から数値にできず 0 |
| 0 | 0 | 0.0 | これも 0(判別しづらい) |
| 3.14 | 3 | 3.14 | atoi は小数点で止まる |
この表の説明
- 「途中に文字が混ざっていても、先頭部分が数字なら変換される」こと
- 「変換できないときも 0 になりがちで、0 と区別しにくい」こと
この2点をまとめて確認するための表です。
atoi / atof は手軽ですが、エラー判定が弱いのが最大の弱点です。
弱点(表)
| 困りごと | 何が起きる? | どう対策する? |
|---|---|---|
| 変換失敗の判定 | 失敗でも 0 を返しやすい(0と区別できない) | strtol / strtod を使う(変換終了位置を確認できる) |
| オーバーフロー | 範囲外のとき動作が保証されない | strtol / strtod と errno を使って判定 |
| 入力の安全性 | scanf で長い入力が来ると危険 | fgets で行を読み、必要なら解析 |
この表の説明
- ここでは「atoi / atof が簡単だけど危険になりやすい理由」を整理しています。
- すぐに置き換えられる代替として strtol / strtod を名前だけでも覚えておくと、実務で助かります。
※とはいえ学習段階では、まず atoi / atof で「文字列→数値」の感覚を掴むのが大事です。
サンプルプログラム
人数(整数) と 1人あたり料金(小数) を文字列で受け取り、合計を計算するプログラム例です。
プロジェクト名:chap11-12-1 ソースファイル名:chap11-12-1.c
Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char s_people[128];
char s_price[128];
puts("人数と1人あたり料金を入力して、合計金額を計算します。");
printf("人数(例 3):");
scanf("%127s", s_people);
printf("1人あたり料金(例 1250.5):");
scanf("%127s", s_price);
int people = atoi(s_people);
double price = atof(s_price);
double total = people * price;
printf("人数=%d、料金=%.2f なので、合計=%.2f です。\n", people, price, total);
return 0;
}このプログラムで出てくる命令(関数)も押さえよう
| 名前 | 何をする? | ここでの役割 |
|---|---|---|
| puts | 文字列+改行を表示 | 案内文を出す |
| printf | 書式付きで表示 | 入力促し、結果表示 |
| scanf | 標準入力から読み取る | 文字列として入力を受け取る |
| atoi | 文字列を int に変換 | 人数にする |
| atof | 文字列を double に変換 | 料金にする |
この表の説明
- 「変換だけでなく、周辺の入出力関数もセットで理解する」ための表です。
- とくに scanf は入力の受け取りで必ず登場するので、役割をはっきりさせています。
使い方のコツ(安全に寄せる書き方)
➀ 文字列入力は幅指定をつける
上の例の scanf は %127s を使っています。これは 128バイト配列に最大127文字+終端\0 を入れるためです。
幅指定を付けないと、長い入力で配列をはみ出して危険です。
➁ atoi / atof の結果が 0 のときは注意
0 には2種類あります。
- 入力が本当に 0
- 変換できなくて 0
ここを厳密に判定したいなら、学習が進んだら strtol / strtod に移行すると安心です。
演習問題
条件:添字演算子を使わずに実現(ポインタ走査で)
演習11-7:文字列を表示する関数
文字列 s を表示する関数 put_string を作成せよ。添字演算子を使わずに実現すること。
void put_string(const char *s);
解答例
プロジェクト名:chap11-12-2 ソースファイル名:chap11-12-2.c
#include <stdio.h>
void put_string(const char *s)
{
while (*s) {
putchar(*s);
s++;
}
}解説
*s で現在の文字を参照し、1文字出力したら s++ で次へ進みます。ナル文字で止まります。
演習11-8:文字の出現回数を数える
文字列 s の中に文字 c が含まれている個数を返す関数 str_chnum を作成せよ。
int str_chnum(const char *s, int c);
解答例
int str_chnum(const char *s, int c)
{
int n = 0;
while (*s) {
if ((unsigned char)*s == (unsigned char)c)
n++;
s++;
}
return n;
}解説
走査しながら一致したらカウントします。int c は putchar 系と相性が良い形です。
演習11-9:最初に見つかった文字へのポインタを返す
文字列 s の中に文字 c が含まれていれば、その最も先頭側の位置へのポインタを返せ。なければ NULL を返せ。
char *str_chr(const char *s, int c);
解答例
プロジェクト名:chap11-12-3 ソースファイル名:chap11-12-3.c
#include <stddef.h>
char *str_chr(const char *s, int c)
{
while (*s) {
if ((unsigned char)*s == (unsigned char)c)
return (char *)s;
s++;
}
return NULL;
}解説
見つけた瞬間に返すのがポイントです。返り値は「その文字の位置」です。
演習11-10:大文字化・小文字化(2関数)
次の2関数を添字演算子なしで実装せよ。
void str_toupper(char *s);
void str_tolower(char *s);
解答例
プロジェクト名:chap11-12-4 ソースファイル名:chap11-12-4.c
#include <ctype.h>
void str_toupper(char *s)
{
while (*s) {
*s = (char)toupper((unsigned char)*s);
s++;
}
}
void str_tolower(char *s)
{
while (*s) {
*s = (char)tolower((unsigned char)*s);
s++;
}
}解説
ctype.h の toupper / tolower は unsigned char にして渡すのが安全です。*s を直接書き換えます。
演習11-11:数字文字を削除する
文字列 str 内のすべての数字文字を除去する関数 del_digit を作成せよ。
例:AB1C9 → ABC
void del_digit(char *str);
解答例
プロジェクト名:chap11-12-5 ソースファイル名:chap11-12-5.c
#include <ctype.h>
void del_digit(char *str)
{
char *src = str;
char *dst = str;
while (*src) {
if (!isdigit((unsigned char)*src)) {
*dst = *src;
dst++;
}
src++;
}
*dst = '\0';
}解説
src で読み、dst に「残す文字だけ」詰め直します。最後に dst にナル文字を置いて完成です。
演習11-12:atoi / atol / atoll / atof 相当を作る
次の2関数を作成せよ。添字演算子なし。
- my_atoi:空白スキップ、符号、数字列まで対応
- my_atof:空白スキップ、符号、整数部と小数部(指数は不要)まで対応
解答例
プロジェクト名:chap11-12-6 ソースファイル名:chap11-12-6.c
#include <ctype.h>
int my_atoi(const char *s)
{
while (isspace((unsigned char)*s)) s++;
int sign = 1;
if (*s == '-') { sign = -1; s++; }
else if (*s == '+') { s++; }
int x = 0;
while (*s >= '0' && *s <= '9') {
x = x * 10 + (*s - '0');
s++;
}
return sign * x;
}
double my_atof(const char *s)
{
while (isspace((unsigned char)*s)) s++;
int sign = 1;
if (*s == '-') { sign = -1; s++; }
else if (*s == '+') { s++; }
double x = 0.0;
while (*s >= '0' && *s <= '9') {
x = x * 10.0 + (*s - '0');
s++;
}
if (*s == '.') {
s++;
double base = 0.1;
while (*s >= '0' && *s <= '9') {
x += (*s - '0') * base;
base *= 0.1;
s++;
}
}
return sign * x;
}解説
atoi / atof の「読めるところまで読む」挙動を、ポインタ走査で再現しています。途中に文字が混ざったらそこで止まります。
