scanfを使ってみようズ

C言語のscanfは、C++でいうcinの役割をする関数です。
cinでは、標準入力ストリームに変数を流してあげることで、標準入力からの入力値が変数に適した値に変換されていました。

ソースコード
#include <iostream>
 
int main()
{
    char str[80];
    int n;
    double d;
 
    std::cin >> str >> n >> d;
 
    std::cout << str << "\n"
              << n << "\n"
              << d << std::endl;
}

結果
std::cin >> str >> n >> d;

なので、char [], int, double(文字列 整数 実数)の値を順にストリームに流さなければならない。
以下のように入力してみる。
moji 10 3.14

> clang++-7 -pthread -std=c++17 -o main main.cpp(入力)
> ./main⏎(入力)
> moji 10 3.14(入力)
> moji⏎
> 10> 3.14

変数に値が入力され、正しく表示されているのがわかる。

これをscanfで同じように実装すると以下のようになる。

#include <stdio.h>
 
int main()
{
    char str[80];
    int n;
    double d;
 
    scanf("%s %d %lf", str, &n, &d);			
    printf("%s %d %f\n", str, n, d);
 
    return 0;
}

scanfでも、printfとよく似た書き方をします。

scanf("書式指定文字列", 変数アドレス,変数アドレス...);

書式指定は、入力の書式を設定する書式指定子を並べる。
変数アドレスは、入力された値が格納される変数のアドレスを並べる。
関数の引数経由で値を入力するときは変数のアドレスが必要なんだったね!覚えてる?
整数変数int a;があるときに、scanfを使って整数値をaに代入したいときは以下のようにする。

/* 書式指定は整数なので %d これはprintfの時と一緒 */
/* aに値を代入したいのでaのアドレスである &a を書く */
/* 入力なので \n とか書かない */ 
scanf("%d", &a);

Visual studio 2019 でプロジェクトを作っちゃうと、ソースコードを拡張子.cで登録すれば何とかなると思ってたのですが、やっぱりscanfでエラー吐くようです。
そこで、includeの前に、コンパイラに渡すパラメータを書いたdefine文を書いておきます。
(それでもscanfはintの値を返すからちゃんと変数で受けろ、とかほざくけど無視してください。理由はうざいから)

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
 
int main(void)
{
	int dval;
	int dummy;
 
	scanf("%d", &dval);
	return 0;
}

正確にはキーボード入力じゃなく、標準入力(stdin)なんだけどね。
stdinから値を読み込んで、プログラム中で使いたいときはscanfを使います。
scanfの基本的な構文は以下のようになっています。

    scanf("フォーマット指定文字列", 変数アドレス1, 変数アドレス2, ...);
 
    int n;
    scanf("%d", &n); 

ここまでは、もう理解済みかと思います。ここからは、型別に具体例を見ていきます。

整数を読み込むには、%dを使います。

    int dval;
 
    printf("dvalの値を整数で入力:");
    scanf("%d", &dval); 

これは、特に問題なく理解できると思います。 値が2つ以上の時は以下のようにします。

    int dval1, dval2;
 
    printf("値を整数で入力(dval1 dval2):");
    scanf("%d%d", &dval1, &dval2); 

実行結果は以下のようになります。
画面が縮小されてるので大きい画面で、最大化してみてください。(そこまでしてみる価値もあるかわからんけども)

Fig. 1: 実行結果
入力時の書式設定の謎

勘の良い人は気づいたかもしれないですが、scanfの書式設定は入力のフォーマットを表しているわけではありません。(めんどくせ)
結果の動画では、“%d%d”の書式指定に対して、“250 200”を入力し、変換対象の2つの変数のアドレス&dval1, &dval2に値を代入しています。
つまり、scanfに対する入力(標準入力=だいたいキーボード)では以下のようなルールが存在します。

<scanfは複数の入力がある場合は空白類を区切りとして入力を読み込む>

空白類とは、

  • 半角スペース
  • タブ
  • 改行

などの事を言います。

区切り文字として空白類(半角スペース、タブ、改行など)を利用するという事は空白類文字類自体をデータとして読み込めないとも言えます。
文字データとして空白を読み込みたいときは、別の関数を使います。(調べてみてね)

複数入力の例

ソースコード
/* scanf関数では半角スペース,タブ,改行などの空白類を区切り文字として使います。 */
    int i, j, k;
 
    scanf("%d%d%d", &i, &j, &k);
入力例

入力例:

10 20 30⏎
/* のように空白を区切りにデータ入力をすることもできます。逆に空白を入力データに含めることはできません。 */
  
/* また、この例では,一つ入力するたびにEnterを押しても入力できます、 */
10⏎
20⏎
30⏎

単精度浮動小数点数(float)を読み込むには、%fを使います。

    float fval;
 
    printf("fvalの値を実数で入力:");
    scanf("%f", &fval); 

倍精度浮動小数点数(float)を読み込むには、%lfを使います。

    float lfval;
 
    printf("lfvalの値を実数で入力:");
    scanf("%lf", &lfval); 

1文字(char)を読み込むには、%cを使います。

    char cval;
 
    printf("cvalの値を実数で入力:");
    scanf("%c", &cval); 

文字変数を5文字読み込み

char型の配列を用意しておいて、連続で入力された文字を読み込むこともできます。
(このような場合は文字列配列(文字配列+'\0')として読み込んだ方が、いろいろ便利な気がします)

#include <stdio.h>
#define ASIZE 5
 
int main(void) {
	char c_arr[ASIZE];
 
	printf("半角文字を5文字入力:");
 
	scanf("%c%c%c%c%c",
	           c_arr,c_arr+1,c_arr+2,c_arr+3,c_arr+4 );
	printf("%c%c%c%c%c", c_arr[0],c_arr[1],c_arr[2],c_arr[3],c_arr[4]);
 
  return 0;
}
実行結果

実行結果小さかったら、最大化してみてください。

Fig. 2: 実行結果

このときに注意すべき点は、データの読み込み先を配列にするときは、読み込む時点できちんと変数としてメモリが確保されていなければならないところです。
char *str;のようにポインタのみを用意しても、scanfでは実体は作ってくれません。

C言語では文字列型がないので、文字配列+'\0'を文字列を表す配列として使います。(もうしつこい)
scanfで文字列を読み込むときは、変換指定子として%sを使います。
読込先の指定では、読み込まれる文字列を格納するのに十分な容量を持ったメモリ領域の先頭アドレスを指定しなければなりません。

20文字以内の文字列をキーボードから読み込むソース
char str[21]; // [?][?][?][?][?][?][?][?][?][?][?][?][?][?][?][?][?][?][?][?][?] 21個のchar型の容量を用意
printf("20文字以内の文字列(半角英数)を入力してください。\n");
scanf("%s", str); // Polymorphism
                  // ['P']['o']['l']['y']['m']['o']['r']['p']['h']['i']['s']['m']['\0'][?][?][?][?][?][?][?][?] 
printf("%s\n", str); 
実行結果
20文字以内の文字列(半角英数)を入力してください。
Polymorphism
Polymorphism

ちょっと補足

ここで、気を付けてほしいことは、キーボードからは文字列を入力するわけだけれども
ソースコード中に文字列を書くときは“strings”のようにダブルクォートで囲むが、scanfで読み込むときは%sが変換してくれるのでそのまま文字だけを打てばよい。
“を入力するとそれも1文字分のデータとして入力されるよ

Fig. 3: 標準入力からの文字列入力1
 

また、逆に言うと、数値や記号などもすべて文字列として変換されるので注意が必要!
さらに、This is a Pen. のような入力は空白文字(スペース)を含んでいるので、区切りとして判断されThisしか文字配列に変換されない

Fig. 4: 標準入力からの文字列入力2
 
  • game-engineer/classes/2021/game-programing-1/clang/clang-scanf.txt
  • 最終更新: 4年前
  • by root