scanfって使ってますか?C言語ではscanfを使ってキーボードで値を入力することができます。入力した値は基本的には文字列として扱われます。
でも、書式を設定することで数値として変換して使用することもできるので便利です。
この記事では、文字列の入力と変換について
- scanfの使い方について
という基本的な内容から、
- scanfを使う上での注意点
- sscanfの使い方について
- scanf_sについて
など応用的な使い方の内容についても解説していきます。
今回は文字列の入力と変換について、使い方をわかりやすく解説します!
scanfの使い方について
scanf関数を使うとキーボードから書式付きで入力することができます。
scanf関数の第1引数には出力する書式を指定し、第2引数以降には入力する変数のアドレスを記入します。
scanf(”書式文字列”, &変数名1, &変数名2, ・・・)
第2引数以降は可変長引数で必要に応じて指定することができます。
第1引数の書式文字列は変換指定子を使って指定します。まずは変換指定子について説明していきます。
なお、アドレスについてはこちらのサイトで詳しく解説していますので、ぜひ参考にしてください。
変換指定子とは(dobule型で入力)
入力する文字列の変数の型を指定するために、変換指定子という記号を使用します。変数の型の種類によって使用する変換指定子は変わってきます。
主な変換指定子とそれに対応する変数の型は次の通りです。
%指定子 | 対応する型 | 説明 |
---|---|---|
%c | char | 文字 |
%s | char * | 文字列 |
%d | int, short | 10進の整数 |
%f | float | 浮動小数点数 |
%lf | double | 倍精度浮動小数点数 |
ここではdouble型の数値を入力する場合について、サンプルコードで確認しましょう。
#include <stdio.h> int main(void) { printf("文字列を入力してEnterボタンを押してください\n"); double d; scanf("%lf", &d); printf("入力された数値は:%lf\n", d); return 0; }
実行結果:
文字列を入力してEnterボタンを押してください 0.5 入力された数値は:0.500000
このサンプルコードでは、キーボード入力した文字列を変換指定子「%lf」を使ってdouble型に変換して、変数dに格納しています。
変換指定子について、こちらのサイトで詳しく解説していますので、ぜひ参考にしてください。
数値を入力する場合
scanf関数で入力した値は基本的には文字列として扱われます。
しかし、scanf関数の第1引数の書式文字列で数値型の変換指定子を指定すると、数値として変数に格納することができます。数値として変数に格納されますので、算術演算子を使って計算をすることも可能です。
サンプルコードで確認しましょう。
#include <stdio.h> int main(void) { printf("文字列を入力してEnterボタンを押してください\n"); double d; scanf("%lf", &d); printf("計算結果は:%lf\n", d + 1.0); return 0; }
実行結果:
文字列を入力してEnterボタンを押してください 0.5 計算結果は:1.500000
このサンプルコードでは、キーボード入力した文字列を変換指定子「%lf」を使ってdouble型に変換して、変数dに格納しています。
その後、変数dに1.0を加算した値を出力表示しています。
文字列を入力する場合
scanf関数を使って文字列を入力する場合について、サンプルコードで確認しましょう。
#include <stdio.h> int main(void) { printf("文字列を入力してEnterボタンを押してください\n"); char str[8]; scanf("%s", str); printf("入力した文字列は:%s\n", str); return 0; }
実行結果:
文字列を入力してEnterボタンを押してください Hello 入力した文字列は:Hello
このサンプルコードでは、キーボード入力した文字列を変換指定子「%s」を使って文字列型に変換して、変数strに格納しています。
複数入力する方法
複数入力する場合は、scanf関数の第1引数の書式文字列で指定します。
入力する値の間にスペース(空白文字)を区切り文字とする場合について、サンプルコードで確認しましょう。
#include <stdio.h> int main(void) { printf("文字列を入力してEnterボタンを押してください\n"); char str1[16]; char str2[16]; scanf("%s %s", str1, str2); printf("入力された文字列は:%s, %s\n", str1, str2); return 0; }
実行結果:
文字列を入力してEnterボタンを押してください Hello World! 入力された文字列は:Hello, World!
このサンプルコードでは、キーボード入力の書式を空白文字で区切られた文字列2つで指定しています。
キーボード入力後に空白文字で区切られた文字列はそれぞれ「str1」、「str2」のアドレスに値に格納され、printf関数を使って出力表示されています。
配列を入力する場合
文字列以外の配列に値を入力する場合について、サンプルコードで確認しましょう。
#include <stdio.h> int main(void) { printf("文字列を入力してEnterボタンを押してください\n"); int num[3]; scanf("%d %d %d", &num[0], &num[1], &num[2]); printf("配列に入力した値は:%d, %d, %d\n", num[0], num[1], num[2]); return 0; }
実行結果:
文字列を入力してEnterボタンを押してください 1 10 100 配列に入力した値は:1, 10, 100
このサンプルコードでは、空白文字で区切られた文字列3つをキーボードで入力しています。
キーボード入力後に空白文字で区切られた文字列はそれぞれ「num[0]」、「num[1]」、「num[2]」のアドレスに値に変換後格納され、printf関数を使って出力表示されています。
なお、配列の使い方についてはこちらのサイトで詳しく解説していますので、ぜひ参考にしてください。
scanfを使う上での注意点
scanf関数は使う上でいくつか注意点があります。
改行文字の取り扱いについて
キーボードから入力された文字はバッファと呼ばれるメモリ領域にいったん読み込まれます。Enterキーが入力されるとバッファをクリアし、再びバッファが行える状態になります。
scanf関数では最後の改行文字はバッファの中に残ります。
したがって1番目の入力のあとに2番目に文字を1文字入力する場合などは、バッファの中に残った改行文字列を入力した文字として間違って処理しますので注意が必要です。
実際にサンプルコードで確認しましょう。
#include <stdio.h> int main(void) { printf("文字列を入力してEnterボタンを押してください\n"); char str1[256]; scanf("%s", str1); printf("入力された文字列は:%s\n", str1); printf("1文字入力してEnterボタンを押してください\n"); char chr1; scanf("%c", &chr1); printf("入力された文字は:%c\n", chr1); printf("文字列を入力してEnterボタンを押してください\n"); char str2[256]; scanf("%s", str2); printf("入力された文字列は:%s\n", str2); return 0; }
実行結果:
文字列を入力してEnterボタンを押してください Hello 入力された文字列は:Hello 1文字入力してEnterボタンを押してください 入力された文字は: 文字列を入力してEnterボタンを押してください & 入力された文字列は:&
このサンプルコードでは1番目に文字列を入力し、2番目に1文字入力し、3番目に文字列を入力するように記述しています。
1番目にHelloと入力しEnterキーを押すと改行文字列を入力した文字として処理し、改行した空の1行を出力する処理が行われます。その後に2番目の&と1文字を入力しても、3番目の文字列を入力した処理が行われ表示されています。
したがって3番目の文字列の入力は実行できずに意図した処理ができていません。
これを改善するためには、下記のように「%*c」句を「%c」変換子の前に記述します。
「%*c」句で改行文字を除去します。
改善前:
scanf("%c", &chr1);
改善後:
scanf("%*c%c", &chr1);
実行結果:
文字列を入力してEnterボタンを押してください Hello 入力された文字列は:Hello 1文字入力してEnterボタンを押してください & 入力された文字は:& 文字列を入力してEnterボタンを押してください World! 入力された文字列は:World!
改善後の実行結果を確認すると改善前の改行文字による空の1行が出力されることはなく、意図通りに処理されています。
空白、タブの読み飛ばしについて
英文のように単語ごとに空白で区切って入力する場合も注意が必要です。
空白やタブが入力の中に含まれると、空白やタブの前までしかバッファーに読み取られません。サンプルコードで確認しましょう。
#include <stdio.h> int main(void) { printf("文字列を入力してEnterボタンを押してください\n"); char str1[256]; scanf("%s", str1); printf("入力された文字列は:%s\n", str1); return 0; }
実行結果:
文字列を入力してEnterボタンを押してください Hello World! 入力された文字列は:Hello
このサンプルコードでは、「Hello World!」とキーボード入力していますが、バッファーの内容を出力表示しても「Hello」とのみ表示されています。
空白以降はバッファーに読み取られていないことがわかります。
バッファーのオーバーランについて
バッファーのオーバーランとはメモリ上に確保した領域よりも大きなデータが渡されているのに、それを見逃して領域からあふれることをいいます。
あふれたデータがバッファに残って後で不具合を起こす可能性もあるので注意が必要です。サンプルコードで確認しましょう。
#include <stdio.h> int main(void) { printf("文字列を入力してEnterボタンを押してください\n"); char str1[4]; scanf("%s", str1); printf("入力された文字列は:%s\n", str1); printf("文字列を入力してEnterボタンを押してください\n"); char str2[4]; scanf("%s", str2); printf("入力された文字列は:%s\n", str2); return 0; }
実行結果:
文字列を入力してEnterボタンを押してください Hello 入力された文字列は:Hello 文字列を入力してEnterボタンを押してください World! 入力された文字列は:World!
このサンプルコードでは4文字分のバッファーの確保に対して、いずれも4文字以上をキーボードから入力しています。
しかしscanf関数を使って入力データを格納し、printf関数を使って出力した結果を確認すると確保したバッファー以上のデータが表示されています。
これはC言語ではNULL文字(\0)が見つかるまで文字を出力し続けるようになっているためです。確保したメモリからあふれたデータが不具合を起こす可能性がありますので、注意が必要です。
入力異常の対処について
入力する際に意図した型と異なるデータを入力すると、意図した処理が行われないので注意が必要です。
サンプルコードで確認しましょう。
#include <stdio.h> int main(void) { printf("整数を入力してEnterボタンを押してください\n"); int num; scanf("%d\n", &num); printf("入力された整数は:%d\n", num); return 0; }
実行結果:
整数を入力してEnterボタンを押してください Hello 入力された整数は:0
このサンプルコードでは、int型のデータのキーボード入力に対応していますが、「Hello」と文字配列を入力しています。
したがって、出力表示は意図しない結果となっています。
sscanfの使い方について
文字列を入力し変換する方法としてほかにもsscanf関数があります。
scanf関数ではコマンドラインでのキーボード入力に対して、sscanf関数ではファイルからの入力もしくはソースコードでの文字列の代入になります。
sscanf関数は第1引数に文字列のアドレスを、第2引数には入力文字列の書式を、第3引数以降には入力文字列から取り出す変数のアドレスを入力します。
sscanf(入力文字列のアドレス, ”書式文字列”, &変数名1, &変数名2, ・・・)
サンプルコードで確認しましょう。
#include <stdio.h> int main(void) { char str[] = "Hello World!"; char substr1[16]; char substr2[16]; sscanf(str, "%s %s", substr1, substr2); printf("%s, %s\n", substr1, substr2); return 0; }
それではサンプルコードで確認しましょう。
実行結果:
Hello, World!
このサンプルコードでは文字配列「str」に文字列を入力しています。
これをsscanf関数の第1引数に代入し、第2引数の書式に従い、第3引数以降で2つの文字列のアドレスを指定しています。文字列の入力から得られた結果をprintf関数を使って出力表示しています。
scanf_sについて
Visual StudioのC++の環境でコンパイルする際には注意が必要です。
VisualC++ではscanf関数を使用するとコンパイルエラーが発生し、scanf_s関数を使うようにメッセージが表示される場合があります。
scanf_s関数を使う場合は、文字列で受け取る領域のサイズを指定する必要があります。
scanf_s(”書式文字列”, 文字列のアドレス, サイズ)
なお、書式文字列に%dを使って整数値を入力する場合などはサイズが決まっているので、サイズを指定する必要はありません。
サンプルコードで確認しましょう。
#include <stdio.h> #include <stdlib.h> int main(void) { printf("文字列を入力してEnterボタンを押してください\n"); char str[16]; scanf_s("%s", str, 16); printf("入力された文字列は:%s\n", str); system("pause"); // 出力表示のための一時停止 return 0; }
実行結果:
まとめ
ここでは、文字列の入力と変換について説明しました。
キーボード入力の場合に使われるscanf関数と文字列入力の場合に使われるsscanf関数の使い方について確認してきました。
データの型や入力文字列の書式、文字数が意図したものと異なる場合などは注意が必要です。使いこなすことができるように、この記事を何度も参考にして下さいね!