【2026年9月最新】C言語 scanfで数値・文字列を入力する方法完全ガイド|sscanfの使い方とバッファオーバーランの注意点
「C言語のscanfで数値や文字列を入力する方法が知りたい」「sscanfとの違いがよく分からない」——この記事にたどり着いた方は、C言語の入門段階でこの壁にぶつかっているはずです。
結論から言うと、数値を読み込むならscanf("%d", &num);、文字列ならscanf("%s", str);が基本形です。ただし、scanfには改行文字の取り扱い・バッファオーバーラン・入力異常といった、初心者がつまずきやすい落とし穴が複数あります。
この記事では、scanfの基本構文から、sscanf・scanf_sとの使い分け、実務で事故になりやすい注意点まで、コード例つきで整理します。あわせて、弊社(株式会社GENAI)がClaude Codeを全社で運用している立場から、「バッファオーバーランのようなコードリスクを、経営としてどう減らすか」という視点も加えて解説します。
この記事を最後まで読むと、次の6つが明確になります。
01 BASICS scanfとは何か|基本構文を理解する 非エンジニアにも分かる例え話で理解する
scanfは、C言語でキーボードから入力された値をプログラムに読み込むための標準関数です。入力用紙の記入欄に、どんな種類のデータを書き込むかを事前に指定しておくようなイメージだと理解しやすくなります。
📚 用語解説
scanf:C言語の標準ライブラリに含まれる、キーボードなどからの入力を読み取る関数。「どんな形式のデータを、どの変数に格納するか」を指定して呼び出します。C言語で最初に学ぶ入出力関数の代表格です。
基本構文は以下の通りです。
scanf("変換指定子", &変数名);
変換指定子とは、「ここには整数が入る」「ここには小数が入る」といったデータの型を示す記号です。&(アンパサンド)は、変数の「置き場所(アドレス)」を渡すための記号で、scanfが値を直接書き込めるようにする役割を持っています。
📚 用語解説
変換指定子 (conversion specifier):%d(整数)、%f(浮動小数点数)、%s(文字列)のように、読み込むデータの型を指定する記号。scanf・printfの両方で使われますが、型によって記号が異なる点に注意が必要です。
📚 用語解説
アドレス演算子 (&):変数の「メモリ上の置き場所」を取得する演算子。scanfは読み取った値を直接その場所に書き込むため、通常の変数には&を付けて渡します。ただし配列(文字列)を渡す場合は、配列名自体が既に置き場所の情報を持っているため&は不要です。
1-1. scanfを使うために必要な準備
scanfを使うには、ソースコードの先頭で標準入出力ライブラリを読み込む#include という1行が必要です。これは「入力・出力に関する道具箱を使えるようにする」宣言のようなもので、printfなど他の入出力関数を使う場合も同様に必要になります。
#include <stdio.h>
int main(void) {
// ここにscanfやprintfを書く
return 0;
}
C言語のプログラムはmain関数から実行が始まります。scanfやprintfは、このmain関数(または呼び出された別の関数)の中で使うのが基本です。
scanfが呼ばれてから変数に値が入るまでの流れを図解すると、以下のようになります。
ユーザーが
文字を入力
Enterまで
一時的に保持
%dや%sの
指定に従って解析
指定したアドレスに
値を書き込む
この4段階のうち、「入力バッファ」の存在を意識していないと、4章で解説する改行文字の残留問題でつまずくことになります。scanfは一度に全てを処理しているわけではなく、バッファを介した段階的な処理である、という理解が重要です。
02 NUMERIC INPUT 数値を入力する方法【変換指定子の一覧】 整数・小数それぞれの正しい書き方
数値の入力でまず押さえるべきは、変換指定子と型の対応です。以下に主な変換指定子を一覧でまとめます。
| 変換指定子 | 対応する型 | 用途 |
|---|---|---|
| %d | int | 整数(10進数)の入力 |
| %f | float | 単精度浮動小数点数の入力 |
| %lf | double | 倍精度浮動小数点数の入力 |
| %c | char | 1文字の入力 |
| %s | char[](文字列) | 文字列(空白まで)の入力 |
printf(出力)では%fでfloat・doubleどちらも扱えますが、scanf(入力)では明確に使い分ける必要があります。double型の変数に%fを使うと、正しく値が読み込まれず不正な動作の原因になります。double型には必ず%lfを使ってください。
整数を1つ入力する例は以下の通りです。
#include <stdio.h>
int main(void) {
int num;
printf("整数を入力してください: ");
scanf("%d", &num);
printf("入力値: %d\n", num);
return 0;
}
double型(倍精度小数)を入力する場合は、%lfを使います。
#include <stdio.h>
int main(void) {
double price;
printf("価格を入力してください: ");
scanf("%lf", &price);
printf("入力値: %.2f\n", price);
return 0;
}
03 STRING & MULTIPLE INPUT 文字列・複数の値を入力する方法 配列への読み込みと、複数値の同時取得
3-1. 文字列を入力する場合
文字列(char型の配列)を入力する場合は%sを使い、変数名に&を付けません。配列名は既に先頭アドレスを表しているためです。
#include <stdio.h>
int main(void) {
char name[64];
printf("名前を入力してください: ");
scanf("%s", name);
printf("こんにちは、%sさん\n", name);
return 0;
}
%sは、スペースやタブ、改行が現れた時点で読み込みを終了します。「山田 太郎」のようにスペースを含む文字列をまるごと読み込みたい場合、scanfの%sでは対応できず、fgetsなど別の関数を検討する必要があります。
3-2. 複数の値をまとめて入力する場合
scanfは1回の呼び出しで複数の値をまとめて読み込むこともできます。変換指定子を並べて、対応する変数もその順番で渡します。
#include <stdio.h>
int main(void) {
int year, month, day;
printf("生年月日を 年 月 日 の順で入力してください: ");
scanf("%d %d %d", &year, &month, &day);
printf("%d年%d月%d日\n", year, month, day);
return 0;
}
変換指定子の間の半角スペースは、入力側の空白・タブ・改行を0個以上読み飛ばす指示です(入力側に空白が無くても失敗しません)。つまり、ユーザーが空白区切り・改行区切りのどちらで入力しても、上記のコードは同じように動作します。
数値と文字列を混在させて入力することもできます。例えば「商品名と価格」のように型が異なるデータを1行でまとめて読み込む場面です。
#include <stdio.h>
int main(void) {
char item[32];
double price;
printf("商品名と価格をスペース区切りで入力してください: ");
scanf("%31s %lf", item, &price);
printf("商品: %s / 価格: %.2f円\n", item, price);
return 0;
}
この例では、文字列側にも%31sという幅指定子を付けています。char item[32]に対して、終端文字1つ分を差し引いた31文字を上限としています。数値と文字列が混在する入力ほど、それぞれの型に応じた安全策を個別に検討する必要がある点に注意してください。
3-3. 配列(複数要素)へのループ入力
複数個のデータをまとめて配列に格納したい場合は、forループと組み合わせます。
#include <stdio.h>
int main(void) {
int scores[5];
for (int i = 0; i < 5; i++) {
printf("%d番目の点数を入力: ", i + 1);
scanf("%d", &scores[i]);
}
return 0;
}
04 PITFALLS 見落としがちな4つの注意点 初心者のつまずきポイントを実行例つきで解説
scanfには、コンパイルは通るのに意図しない動作を引き起こす落とし穴が複数あります。ここでは代表的な4つを解説します。
4-1. 改行文字が入力バッファに残る問題
scanf("%d", &num);で数値を入力すると、ユーザーが最後に押したEnterキー(改行文字)は消費されずに入力バッファに残ったままになります。この状態で続けてscanf("%c", &ch);を呼ぶと、ユーザーの入力を待たずに、残っていた改行文字がそのまま読み込まれてしまいます。
int num;
char ch;
scanf("%d", &num); // 例: "5" + Enter
scanf(" %c", &ch); // %cの前に半角スペースを入れて改行を読み飛ばす
%cの直前に半角スペース1つを入れておくと、scanfは直前に残っている空白文字(改行含む)を自動的に読み飛ばしてくれます。%dや%f、%sは元々この読み飛ばしを自動で行いますが、%cだけは明示的にスペースを書かないと行われません。
4-2. 空白・タブの読み飛ばし
%dや%f、%sは、変換を始める前に先頭の空白・タブ・改行を自動的に読み飛ばします。一方%cだけは、直前の変換指定子に明示的なスペースがない限り読み飛ばしを行わないため、前項のような問題が起きます。
4-3. バッファオーバーラン
scanf("%s", str);のように文字数の上限を指定しない書き方は、確保した配列のサイズを超える長さの文字列が入力された場合、メモリの想定外の領域に書き込みが発生します。これが「バッファオーバーラン(バッファオーバーフロー)」と呼ばれる不具合・脆弱性です。
📚 用語解説
バッファオーバーラン:プログラムが確保したメモリ領域(バッファ)の容量を超えるデータを書き込んでしまう不具合。プログラムの異常終了だけでなく、悪意ある攻撃者がこの隙を突いて不正なコードを実行させる攻撃手法(バッファオーバーフロー攻撃)にも悪用される、代表的なセキュリティ脆弱性の一つです。
char buf[16];
// 危険: 16文字を超える入力があると想定外の領域を書き換える
scanf("%s", buf);
// 安全: 幅指定子で読み込む最大文字数を制限する(配列サイズ-1まで)
scanf("%15s", buf);
C言語の文字列は末尾に自動で終端文字\0が付与されます。char buf[16]であれば、幅指定子は最大15(%15s)にする必要があります。配列サイズと同じ数値を指定すると、終端文字の分だけあふれてしまいます。
4-4. 入力異常(不正な入力)への対処
数値を期待している箇所に文字列が入力されるなど、変換に失敗するケースもscanfでは起こり得ます。scanfは実際に正しく読み込めた項目の数を戻り値として返すため、これを確認することで入力異常を検知できます。
int num;
int result = scanf("%d", &num);
if (result != 1) {
printf("数値以外が入力されました\n");
// 不正な入力をバッファから読み捨てる処理が別途必要
}
戻り値のチェックを省略しているコードは、入門書のサンプルコードにも意外と多く見られます。学習目的の短いプログラムでは問題が表面化しにくいものの、実務で長期間運用するプログラムほど、想定外の入力に一度は遭遇すると考えておくべきです。
4-5. 入力バッファをクリアする実装例
入力異常を検知した後、バッファに残った不正な文字をそのままにしておくと、次のscanf呼び出しにも影響してしまいます。getchar()を使って、改行文字が出てくるまで1文字ずつ読み捨てる処理が定番です。
#include <stdio.h>
int main(void) {
int num;
int c;
printf("整数を入力してください: ");
while (scanf("%d", &num) != 1) {
printf("数値以外が入力されました。再入力してください: ");
while ((c = getchar()) != '\n' && c != EOF) {
// バッファに残った不正な文字を読み捨てる
}
}
printf("入力値: %d\n", num);
return 0;
}
このように、「入力チェック」と「バッファクリア」はセットで実装する必要があります。片方だけを実装すると、一見正常に動いているように見えて、特定の入力パターンでだけ無限ループやフリーズを起こすバグに発展することがあります。
GCCやClangでは-Wformatオプションを付けてコンパイルすると、変換指定子と変数の型が一致していない箇所(例: doubleに%fを使っている等)を警告として検出してくれます。目視レビューだけに頼らず、コンパイラの警告を必ず確認する習慣をつけると、型の不一致ミスをかなりの割合で事前に防げます。
05 SSCANF & SCANF_S sscanfの使い方とscanf_sという選択肢 文字列からの読み取りと、より安全な入力方法
5-1. sscanfの使い方
sscanfは、キーボード入力ではなく既に変数に入っている文字列からデータを取り出すための関数です。構文はscanfとほぼ同じで、先頭に読み取り元の文字列を指定します。
#include <stdio.h>
int main(void) {
char input[] = "2026-09-11";
int year, month, day;
sscanf(input, "%d-%d-%d", &year, &month, &day);
printf("%d年%d月%d日\n", year, month, day);
return 0;
}
この例のように、「YYYY-MM-DD」形式の文字列を年月日に分解するといった処理で頻繁に使われます。ファイルから読み込んだ1行分のテキストを解析する場面などでも定番の関数です。
📚 用語解説
sscanf:scanfの仲間で、標準入力(キーボード)ではなく指定した文字列からデータを読み取る関数。CSVやログファイルの1行を分解して数値・文字列に変換する処理でよく使われます。
sscanfもscanfと同様に戻り値でチェックが可能です。以下のように、期待した項目数がすべて読み取れたかを確認しておくと、フォーマットが崩れたデータを誤って処理してしまう事故を防げます。
char log_line[] = "ERROR 404 not_found";
char level[16];
int code;
char detail[32];
int n = sscanf(log_line, "%15s %d %31s", level, &code, detail);
if (n != 3) {
printf("ログの形式が想定と異なります\n");
}
この例のように、ログファイルの解析やCSVの読み込みなど、外部から受け取ったテキストデータを扱う処理では、想定外のフォーマットが混じっている可能性を常に考慮し、戻り値のチェックをセットで実装することが推奨されます。
5-2. scanf_s:より安全な入力を目指した関数
scanf_sは、C11規格の付属仕様(Annex K)で追加された、バッファオーバーランを起こしにくくするための拡張版です。%sや%cを使う際に、書き込み先のバッファサイズを追加の引数として明示的に渡す点が最大の違いです。
char buf[16];
scanf_s("%s", buf, (unsigned)sizeof(buf));
scanf_sはC11のAnnex K(オプション扱いの拡張仕様)に含まれており、すべてのコンパイラで使えるわけではありません。Windows環境(Visual Studio)では利用できますが、Linux環境で標準的に使われるglibcは対応していないため、移植性が求められるコードでは使用を避けるか、代替の安全策(幅指定子の徹底など)を検討する必要があります。
| 関数 | 読み取り元 | バッファ長の安全性 | 移植性 |
|---|---|---|---|
| scanf | キーボード(標準入力) | 幅指定子を書かない限り無防備 | 高い(ほぼ全環境で利用可) |
| sscanf | 既存の文字列変数 | 幅指定子を書かない限り無防備 | 高い(ほぼ全環境で利用可) |
| scanf_s | キーボード(標準入力) | バッファ長を引数で強制指定 | 低い(環境により非対応) |
06 BUSINESS RISK なぜバッファオーバーランは経営リスクなのか 技術的な話を、経営者が判断できる言葉に翻訳する
ここまで解説してきた「バッファオーバーラン」は、単なるプログラムの不具合ではなく、経営者が向き合うべきリスクでもあります。ここでは非エンジニアの視点で、なぜこれが問題になるのかを整理します。
制限し忘れる
コードレベルの
小さなミス
メモリ書き換え
プログラムの
不安定動作
悪用される
情報漏えい・
不正操作のリスク
この一連の流れは、「たった1行、幅指定子を書き忘れただけ」から発生するという点が恐ろしいところです。開発者個人の注意力だけに依存していると、こうした小さな見落としが積み重なり、いつか重大なインシデントにつながるリスクを常に抱えることになります。
07 GENAI CASE STUDY Claude Codeにコードレビューを任せるという選択肢 弊社GENAIの実運用データで見る、開発リスクの減らし方
弊社(株式会社GENAI)ではClaude Max 20xプラン(月額$200・約30,000円)を契約し、経営・営業・広告・開発・経理・秘書業務まで社内のあらゆる業務でClaude Codeを活用しています。開発領域では、コードレビューもその一つです。
Claude Codeは、「このコードにバッファオーバーランのリスクがないか確認して」と日本語で頼むだけで、該当箇所を指摘し、修正案まで提示してくれます。scanfの幅指定子の書き忘れのような細かい見落としも、機械的にチェックできる領域です。
| チェック内容 | 人力レビューのみの場合 | Claude Codeを併用する場合 |
|---|---|---|
| 幅指定子の書き忘れ | レビュアーの注意力に依存 | 該当パターンを機械的に検出 |
| %fと%lfの型不一致 | 見落とされがちな細部 | コードを読み取って指摘 |
| 入力異常時の処理漏れ | テストケースが漏れると発見できず | 想定外の入力ケースを洗い出して提案 |
| レビューにかかる時間 | 担当者の稼働に依存 | 即座に初期チェックが完了 |
弊社の開発領域(WordPress・LP制作・各種スクリプトの書き捨て等)では、コードの書き捨てと同時にレビュー観点のチェックもClaude Codeに任せることで、都度数時間かかっていた確認作業がその場で完結する肌感で削減できています。
本章の削減時間は弊社の肌感ベースの参考値であり、業種・業態・担当者のスキルによって変動します。「完全自動化」ではなく、最終確認は引き続き人の判断が必要です。
7-1. 「コードが読めない経営者」でも判断できる体制づくり
弊社がClaude Codeを導入して感じているのは、「コードを読めるかどうか」と「コードのリスクを判断できるかどうか」は別物になったということです。以前は、開発の細部を理解している人にしかレビューを頼めませんでしたが、今は「このコードに危険な書き方はないか確認して」とClaude Codeに投げれば、要点を日本語で説明してもらえます。
これにより、経営者やプロジェクト管理者がコードの中身を直接読まなくても、リスクの有無を把握したうえで意思決定できる体制に近づきます。もちろん最終的な技術判断はエンジニアが担うべきですが、「そもそも確認する仕組みがあるかどうか」という一段階目のガバナンスは、非エンジニアの経営者でも十分に設計できる領域です。
08 CONCLUSION まとめ ── コードの正確さを、個人の注意力に頼らない 技術理解と、組織としてのリスク管理を両立させる
この記事では、scanfで数値・文字列を入力する基本から、sscanf・scanf_sとの違い、バッファオーバーランなどの注意点、そしてそれが経営リスクにつながる構造までを整理しました。最後にポイントを振り返ります。
scanf("%d", &num);、文字列はscanf("%s", str);(&不要)%fではなく%lfを使う%cの前に半角スペースを入れないと、直前の改行文字をそのまま読み込んでしまう%sは幅指定子(例: %15s)を付けないとバッファオーバーランのリスクがあるC言語のscanfは、書き方自体はシンプルですが、「正しく動く」と「安全に動く」の間にギャップがある関数です。このギャップを個人の注意力だけで埋め続けるのではなく、機械的なチェックを組み合わせて組織としてリスクを減らす、という発想が重要になります。
C言語に限らず、入力処理まわりの小さな見落としは、どのプログラミング言語でも起こり得ます。「言語ごとの細かい仕様を全員が完璧に覚える」ことを目指すのではなく、見落としを機械的に拾い上げる仕組みを組織に組み込む方が、現実的でコストの低いリスク管理と言えます。
この記事で紹介した注意点(改行文字の残留、%fと%lfの混同、バッファオーバーラン、入力異常)は、いずれもC言語の入門書で必ず触れられるにもかかわらず、実務コードでも繰り返し見つかる典型的なミスです。基本を正しく押さえたうえで、レビューの仕組みまで含めて整備しておくことが、事故を未然に防ぐ一番の近道になります。
次にscanfのコードを書く、あるいはレビューする機会があれば、この記事で紹介したチェックリストと変換指定子の対応表を見返してみてください。細部の積み重ねが、動くコードと安全なコードの差になります。
コードレビューの属人化を、Claude Codeで仕組み化しませんか
バッファオーバーランのような細かいリスクを、個人の注意力だけに頼らない体制づくりを支援します。
弊社の実運用ノウハウをベースに、個別に導入設計のご相談を承ります。
ここから先の進め方は、大きく2つあります。
自社で回せるようになりたい方は、AI鬼管理でClaude Code/Codexの使い方から業務設計・社内定着まで伴走を受けながら、社内に仕組みを作る道があります。
覚えるより任せたい方は、AI社員AIKATAでこの記事のような定型業務を丸ごと預ける道があります。料金は月30万円の月額定額、追加費用は0円です。
どちらが合うかは、業務量と社内体制次第です。無料相談・無料適合診断で、貴社の場合はどちらが向くかからご相談いただけます。
NEXT STEP
この記事の内容を、あなたのビジネスで
実践してみませんか?
よくある質問
Q. scanfで%dと%lfを間違えるとどうなりますか?
A. 型のサイズが異なるため、正しく値が読み込まれず、変数に意図しない値が入ったり、他の変数の領域を破壊したりする可能性があります。特にdouble型に%fを使う間違いは初心者に多いミスなので注意してください。
Q. scanfで文字列を入力する時、なぜ&を付けないのですか?
A. 配列名(文字列変数)は、既にその先頭要素のアドレスを表す形でscanfに渡されるためです。通常のint型やdouble型の変数には&を付けますが、配列だけはこの例外があります。
Q. sscanfとscanfの違いは何ですか?
A. scanfはキーボードなどの標準入力から読み込みますが、sscanfは既にメモリ上にある文字列から読み込みます。ファイルの1行や、通信で受け取った文字列を分解する処理でよく使われます。
Q. scanf_sはどの環境でも使えますか?
A. 使えません。scanf_sはC11のAnnex K(オプション扱いの拡張仕様)に含まれており、Windows(Visual Studio)では利用できますが、Linuxで標準的に使われるglibcは対応していません。移植性が必要なコードでは注意が必要です。
Q. バッファオーバーランを防ぐ最も簡単な方法は何ですか?
A. %sを使う際に、配列サイズ-1の幅指定子(例: char buf[16]なら%15s)を必ず付けることです。これだけで、確保した領域を超えるデータの書き込みを防げます。
Q. 非エンジニアの経営者は、こうしたコードの細部をどこまで理解すべきですか?
A. コードを1行ずつ読む必要はありませんが、「小さな書き忘れが重大なリスクに発展する構造」があることは理解しておくべきです。そのうえで、Claude Codeなどによる機械的なレビュー体制を組織としてどう作るかを判断するのが経営者の役割です。
Q. scanfの戻り値を無視するとどんな問題が起きますか?
A. 入力異常が起きても検知できないため、初期化されていない変数の値がそのまま以降の処理に使われる可能性があります。想定外の値による誤動作の原因になるため、戻り値のチェックは基本的に省略すべきではありません。
Q. getchar()でバッファをクリアする処理は毎回必要ですか?
A. 数値・文字列の入力後に%cで1文字だけ読み込む処理を続けて行う場合や、入力異常のリトライ処理を実装する場合には必要になります。単純に%dや%sだけを連続して使う場合は、先頭の空白読み飛ばしが自動で働くため、通常は意識しなくても問題になりにくいです。
Claude Codeで業務自動化を90日で叩き込む
経営者向けの伴走型パーソナルトレーニング
AI鬼管理/AI社員AIKATAへのお問い合わせ
この記事を読んで気になった方へ。
専門スタッフが、御社に最適な
業務自動化・業務代行プランを無料でご提案します。




