プログラムを実行する際に、内容によってはユーザーに手動でデータを入力してもらう必要がある場合もあります。
C言語には、キーボードから入力されたデータを取得するための関数である 「scanf」 関数が用意されています。
今回の記事では、scanf関数を使用して数値や文字列をキーボード入力する方法について、解説していきたいと思います。
C言語のscanfとは?
scanf関数は、プログラムの実行に必要な文字列や数値などの値を、キーボード入力によって取得する場合に使用する関数です。
この関数によって、ユーザーが入力した情報を変数に格納し、プログラム内で使用することができるようになります。
scanfの使い方
まずは、scanf関数の基本的な使い方から見ていきましょう。
基本構文と使い方
scanf関数を使用する際の基本構文は、以下のように記述します。
【基本構文】
scanf("フォーマット指定子", &変数名);
フォーマット指定子では、入力された値をどのデータ型として変数に格納するかを指定します。
そのため、格納先の変数と同じデータ型を指定するようにしましょう。
第2引数には、実際の格納先となる変数の名前を指定しますが、scanf関数を使用する際に注意すべきなのは、変数名の頭に 「&」 演算子を付ける必要があるという点です。
&演算子は、変数が確保しているメモリのアドレスを指定する場合に使用する演算子です。
C言語では、引数に変数を指定した場合に渡されるデータはすべて、メモリに記録されている値をコピーしたものとなっています。(値渡しといいます)
関数で使用される変数はあくまでデータのコピーに過ぎないため、そのままでは変数の中身を直接変更することはできません。
そこで必要になるのが、& 演算子です。
&を使って指定することで、データのコピーではなくアドレスが引数に渡されるため、入力結果を直接変数に格納することができるようになります。
scanf関数を使用する際は、変数名の頭に必ず & を付けるようにしましょう。
scanfの変換指定子とは?
第1引数のフォーマット指定子では、変換指定子と呼ばれる表記方法を使用して、データ型の指定を行います。
変換指定子は、それぞれのデータ型に対応するアルファベットと 「%」 を組み合わせて記述します。
(%は、「ここから変換の指定をしますよ」 というサインです)
主な変換指定子と、それに対応するデータ型を以下の一覧にまとめました。
変換指定子 | 対応する型 | 説明 |
---|---|---|
%d | int | 10 進符号付き整数として入力 |
%u | unsigned int | 10 進符号無し整数として入力 |
%o | int, short, unsigned int | 8 進符号無し整数として入力 |
%x | int, unsigned int | 16 進符号無し整数として入力 |
%f | float | 小数形式浮動小数点数として入力 |
%c | char | 1文字を入力 |
%s | char* | 文字列を入力 |
一例として、int型を指定する場合のサンプルコードを見てみましょう。
【サンプルコード】
#include <stdio.h>
int main(void) {
printf("整数を入力してEnterを押してください\n");
int num;
scanf("%d", &num);
printf("入力された数:%d\n", num);
return 0;
}
【実行結果】
整数を入力してEnterを押してください
5
入力された数:5
格納先の変数が int型のため、引数には 「%d」 を記述しています。
このように、データ型に合わせた変換指定子を使用します。
scanfで数値を入力する
先ほどのサンプルコードでも解説したように、整数を格納する場合は 「%d」 を指定し、int型の変数に格納します。
一方、浮動小数点数(float型)として値を格納したい場合は、フォーマット指定子に 「%f」 を記述することで指定が可能です。
以下のサンプルコードで確認してみましょう。
【サンプルコード】
#include <stdio.h>
int main(void) {
printf("数値を入力してEnterを押してください\n");
float num;
scanf("%f", &num);
printf("入力された数:%f\n", num);
return 0;
}
【実行結果】
数値を入力してEnterを押してください
5
入力された数:5.000000
float型として格納したため、出力結果には小数点以下の桁も表示されています。
数値として格納されているので、そのまま計算に使用することも可能です。
scanfで文字列を入力する
入力内容を文字として扱いたい場合は、1文字のみであれば 「%c」、文字列であれば 「%s」 をフォーマット指定子に記述しましょう。
ただし、scanf関数で文字列を入力する際は、気を付けるべきポイントが一点あります。
先ほどの解説で、変数の頭には&演算子を付ける必要があると説明しましたが、文字列に関しては &演算子を記述せずに、変数名のみを指定します。
その他のデータ型の場合と記述方法が異なるので、注意が必要です。
(1文字のみの場合は、&演算子を記述します。)
【サンプルコード】
#include <stdio.h>
int main(void) {
printf("名前を入力してEnterを押してください\n");
char name[16];
scanf("%s", name);
printf("あなたの名前は %s です\n", name);
return 0;
}
【実行結果】
名前を入力してEnterを押してください
山田太郎
あなたの名前は 山田太郎 です
scanfで複数の値を入力する
scanf関数では、複数の値を同時に入力することも可能です。
その場合は、フォーマット指定子に入力したい数だけ変換指定子を記述し、第2引数以降に同数の変数アドレスを指定します。
以下のサンプルコードで確認してみましょう。
【サンプルコード】
#include <stdio.h>
int main(void) {
printf("名前、年齢の順に入力してください\n");
char name[16];
int age;
scanf("%s %d", name, &age);
printf("名前: %s, 年齢: %d\n", name, age);
}
【実行結果】
名前、年齢の順に入力してください
山田太郎
18
名前: 山田太郎, 年齢: 18
実行結果を見ると分かるように、入力内容はコードに記述された順に変数へと格納されていきます。
scanfで配列に値を入力する
scanf関数を使用して、配列に値を格納することもできます。
以下のサンプルコードで動作を確認してみましょう。
【サンプルコード】
#include <stdio.h>
int main(void) {
printf("整数を入力してください\n");
int numArray[3];
int i;
for(i=0;i<3;i++){
scanf("%d", &numArray[i]);
printf("%dを格納しました\n", numArray[i]);
}
return 0;
}
【実行結果】
整数を入力してください
1
1を格納しました
2
2を格納しました
3
3を格納しました
配列に値を格納する際も、その他の変数と同様に&演算子を使用してアドレスを指定します。
要素へのアクセス方法は通常時と変わらないので、&演算子の後ろに配列名とインデックス番号を記述して、任意の要素にアクセスしましょう。
scanfを使用する際の注意点
既に上述した内容以外にも、scanf関数を使用する上で注意するべき点がいくつかあります。
順に見ていきましょう。
scanfでの改行文字の扱い
scanf関数を複数回に渡って使用する際に、ケースによっては上手く文字を読み取ることができない場合があります。
まずは、以下のサンプルコードを実行してみましょう。
【サンプルコード】
#include <stdio.h>
int main(void) {
char str[16];
char chr;
printf("文字列を入力してください\n");
scanf("%s", str);
printf("入力内容:%s\n", str);
printf("1文字入力してください\n");
scanf("%c", &chr);
printf("入力内容:%c\n", chr);
return 0;
}
【実行結果】
文字列を入力してください
サンプル
入力内容:サンプル
1文字入力してください
入力内容:
結果を見ると分かるように、このサンプルコードでは2度目の入力が正常に行われていません。
通常、キーボードから入力された文字は、バッファと呼ばれるメモリ領域にいったん記憶された後に、関数によるデータの読み取りが行われます。
一時保存されたデータが読み取られることでバッファがクリアされますが、scanf関数では最後の改行文字は読み取り後もバッファの中に残る仕様となっています。
int型などの場合は、残された改行文字が読み取りの際に無視されることで正常に作動しますが、char型を指定すると、バッファの中に残った改行文字がそのまま1文字として読み込まれてしまうため、上記のような現象が発生してしまいます。
したがって、2回目以降のscanf関数の使用で1文字を入力させる場合は、バッファの中に残った改行文字を別途で処理する必要があります。
処理の仕方については、主に以下の3つの方法があります。
- getchar関数を使用して改行文字を読み捨てる
- 改行文字を読み捨てるためのscanf関数処理を別で入れる
- 半角スペース、改行文字、あるいは 「%*c」 を変換指定子の前に記述する
1つ目と2つ目は、どちらも1文字のみの入力処理を新たに挟み、バッファに残った改行文字を読み捨ててからユーザーに再度入力をしてもらう方法となっています。
この方法を使用する場合は、scanf関数の使用後に上記の処理を挟むようにしましょう。
3つ目の方法では、フォーマット指定子の記述時に内容を追加することで、バッファに残された改行文字の処理を合わせて行います。
半角スペースと改行文字は、指定変換子の前に記述することで、本来読み込まれるはずの改行文字を無視して読み飛ばしてくれるようになります。
これにより、バッファの中に読み込める文字が残されていない状態となり、新たにキーボード入力を受け付けてくれるようになります。
「%*c」 は、読み込んだデータを格納せずに捨てることを意味する記述です。
上述のケースに限らず使える手法で、以下の例のように変換指定子の % とアルファベットの間に * を記述することで、入力された一部のデータを無視することができます。
【サンプルコード】
scanf("%*c%c", &chr);
読み込んだデータを格納する必要がないため、変数アドレスを指定する必要もありません。
この仕様を活用して、バッファに残された改行文字を読み捨てることができます。
一度の実行で scanf関数を何度も使用する場合は、必要に応じて改行文字の処理を行うようにしましょう。
空白文字がスキップされる
scanf関数では基本的に、空白文字は文字列の一部ではなく、値ごとの区切りとして認識されます。
そのため、入力した内容にスペースなどが含まれていると、それより前に入力した値のみが変数に格納されるため、注意が必要です。
以下のサンプルコードで動作を確認してみましょう。
【サンプルコード】
#include <stdio.h>
int main(void) {
printf("文字列を入力してください\n");
char str[16];
scanf("%s", str);
printf("入力内容:%s\n", str);
return 0;
}
【実行結果】
文字列を入力してください
Hello World!
入力内容:Hello
「Hello」 と 「World!」 の間にスペースがあるため、文字列が区切られて前半部分のみが格納されているのが分かると思います。
上記のようなケースで、空白文字も含めて変数に格納したい場合は、正規表現を活用してフォーマット指定子を記述しましょう。
以下は、指定する際の記述例です。
【正規表現の記述例】
%[^\n]
正規表現では、[]を使用すると、枠内に記述した条件に当てはまる文字を指定するという意味になります。
「^」 は、後述の条件に当てはまるもの以外を指定することを意味するため、上述のコード例の場合は、改行文字以外のすべての文字を指定することになります。
これにより、空白文字も読み込み対象となるため、スペースなどを含めた文字列の格納が可能となります。
サンプルコードで実際の動作を確認してみましょう。
【サンプルコード】
#include <stdio.h>
int main(void) {
printf("文字列を入力してください\n");
char str[16];
scanf("%[^\n]", str);
printf("入力内容:%s\n", str);
return 0;
}
【実行結果】
文字列を入力してください
Hello World!
入力内容:Hello World!
先ほどとは変わり、スペースやその後の文字列もすべて変数に格納されています。
なお、空白文字を含めずに文字列が区切られた場合に、変数へ格納されなかった値は先ほどの改行文字のケースと同様にバッファに残されたままとなります。
プログラムの実行内容によっては、意図せぬ動作を引き起こす原因にもなりかねないため、こちらも注意が必要です。
scanfの使用時にバッファオーバーランが発生する
scanf関数を使用する上で特に注意すべきなのが、バッファオーバーラン (バッファオーバーフロー) と呼ばれる現象です。
バッファオーバーランとは、メモリ上に確保した領域よりも大きなデータが渡されることによって、確保したメモリ領域を超えてデータを書き込んでしまう現象のことを言います。
scanf関数で起こり得る例では、格納先の配列サイズを超えた文字列が入力されたり、int型の上限値を超える数値が入力された場合などが該当します。
scanf関数の使用時にバッファオーバーランが引き起こされないよう防ぐには、フォーマット指定子のフィールド幅を活用しましょう。
フィールド幅を指定すると、読み取る文字数を制限することができます。
指定の際は、以下のように % とアルファベットの間に数値を記述します。
【記述例】
%5s
サンプルコードで実際の動きを確認してみましょう。
【サンプルコード】
#include <stdio.h>
int main(void) {
printf("文字列を入力してください\n");
char str[16];
scanf("%5s", str);
printf("入力内容:%s\n", str);
return 0;
}
【実行結果】
文字列を入力してください
HelloWorld!
入力内容:Hello
結果を見ると、フィールド幅に指定した5文字分だけが変数に格納されているのが分かりますね。
なお、このサンプルコードの場合、残りの文字列はバッファに残された状態となっています。
「指定の文字数を超えた文字列はそのまま切り捨てたい」 といった場合には、フォーマット指定子で以下のように記述しましょう。
【記述例】
%5s%*[^\n]
ポイントは、「%*[^\n]」 と記述された部分です。
既に解説した通り、* を変換指定子に付けることで、読み取ったデータを格納せずに無視することができます。
また、[^\n] は改行文字以外のすべての文字を指定することになるため、これによって超過した分の文字列を読み捨てることができます。
scanfで入力された値が正しくない場合の動作
scanf関数では、バッファに記憶されたデータを読み取る際に、フォーマット指定子に記述した型と一致する値のみが読み取られるため、入力した内容によっては意図しない動作を引き起こす可能性があります。
まずは、以下のサンプルコードを見てみてください。
【サンプルコード】
#include <stdio.h>
int main(void) {
printf("整数を入力してください\n");
int num;
scanf("%d\n", &num);
printf("入力内容:%d\n", num);
return 0;
}
【実行結果】
整数を入力してください
123abc
入力内容:123
実行時の入力内容にはアルファベットも含まれていますが、その後の結果表示では数値のみが変数に格納されているのが分かると思います。
scanf関数では、入力した文字を先頭から読み取り、指定の型に一致しない文字が現れた段階で読み取りが終了するため、読み取られなかった文字はそのままバッファに残されることになります。
これにより、プログラムが正常に実行されない場合があるため、注意が必要です。
【応用編】sscanf関数を使用する
C言語では、データ入力の際に使用する関数の1つに、「sscanf」 という関数があります。
これまで解説してきた scanf関数が、キーボードで入力されたデータから読み取りを行なっていたのに対し、sscanf関数は既存の文字列から値を読み取るための関数となっています。
sscanf関数を使用する際の構文は、以下のように記述します。
【基本構文】
sscanf(対象の文字列, ”フォーマット指定子”, &変数名)
scanf関数と異なる点は、第1引数に読み取り元となる文字列を指定することです。
フォーマット指定子や変数アドレスを指定する点は同様のため、これまでと同じ記述方法で内容を指定しましょう。
【サンプルコード】
#include <stdio.h>
int main(void) {
char *str = "abc 123";
char result1[16];
int result2;
sscanf(str, "%s %d", result1, &result2);
printf("文字列:%s, 数値:%d\n", result1, result2);
return 0;
}
【実行結果】
文字列:abc, 数値:123
まとめ
いかがでしたか?
今回は、C言語での値の入力や読み込み方法について解説しました。
scanf関数のように、事前にコードで定められている値や、APIなどの一定のルールに基づいて渡される情報とは異なるデータを扱う処理の使用は、イレギュラーが発生する確率も高くなりがちです。
使用の際は、ここまで解説してきた使用方法や注意点に気を付けながら活用してみてください。
C言語の勉強方法は?
書籍やインターネットで学習する方法があります。昨今では、YouTubeなどの動画サイトやエンジニアのコミュニティサイトなども充実していて多くの情報が手に入ります。
そして、より効率的に知識・スキルを習得するには、知識をつけながら実際に手を動かしてみるなど、インプットとアウトプットを繰り返していくことが重要です。特に独学の場合は、有識者に質問ができたりフィードバックをもらえるような環境があると、理解度が深まるでしょう。
ただ、C言語に限らず、ITスキルを身につける際、どうしても課題にぶつかってしまうことはありますよね。特に独学だと、わからない部分をプロに質問できる機会を確保しにくく、モチベーションが続きにくいという側面があります。独学でモチベーションを維持する自信がない人にはプログラミングスクールという手もあります。費用は掛かりますが、その分スキルを身につけやすいです。しっかりと知識・スキルを習得して実践に活かしたいという人はプログラミングスクールがおすすめです。
プログラミングスクールならテックマニアがおすすめ!

ITスキル需要の高まりとともにプログラミングスクールも増えました。しかし、どのスクールに通うべきか迷ってしまう人もいるでしょう。そんな方にはテックマニアをおすすめします!これまで多くのITエンジニアを育成・輩出してきたテックマニアでもプログラミングスクールを開講しています。
<テックマニアの特徴>
・たしかな育成実績と親身な教育 ~セカンドキャリアを全力支援~
・講師が現役エンジニア ~“本当”の開発ノウハウを直に学べる~
・専属講師が学習を徹底サポート ~「わからない」を徹底解決~
・実務ベースでスキルを習得 ~実践的な凝縮カリキュラム~
このような特徴を持つテックマニアはITエンジニアのスタートラインとして最適です。
話を聞きたい・詳しく知りたいという方はこちらからお気軽にお問い合わせください。