Changes between Version 29 and Version 30 of HowTo/CTutorial


Ignore:
Timestamp:
Sep 28, 2010, 1:08:13 AM (14 years ago)
Author:
村山 俊之
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • HowTo/CTutorial

    v29 v30  
    305305
    306306{{{
    307 #!sh
    308307$ gcc test.c
    309308}}}
     
    312311
    313312{{{
    314 #!sh
    315313$ ./a.out
    316314}}}
     
    321319
    322320{{{
    323 #!sh
    324321$ gcc -o test test.c
    325322$ ./test
     
    548545さて次に、ユーザーに文章ではなく数字を入力させ、それを数値として扱いたい場合にはどうしようか、という問題です。いくつかのアプローチが考えられますが、恐らく最も手軽なのは、上記のサンプルで使用している '''scanf() 関数''' を用いることでしょう。 printf() 関数が書式を指定して表示を行うのとは逆に、 scanf() 関数は指定した書式でのみ入力を受け付けて、そこから値を拾い上げるというものです。
    549546
     547ただ、 scanf() 関数の書式指定はクセが強いので、あまりあてにしない方が良いかも知れません。以下のプログラムを見てみましょう。
     548
     549{{{
     550#!c
     551#include <stdio.h>
     552
     553int main()
     554{
     555    int a = 0, b = 0;
     556    printf("a,b >> ");
     557    scanf("%d,%d", &a, &b); /* ←注目!! */
     558    printf("a + b = %d\n", a + b);
     559    return 0;
     560}
     561}}}
     562
     563scanf() 関数で指定した書式指定は "%d,%d" となっていますね。この場合、入力する側もこの通り、2つの数字をカンマ "," で挟んで入力する必要があります。ちょっと、実行して、いろいろ試してみましょう。
     564
     565{{{
     566$ gcc -o hoge hoge.c
     567$ ./hoge
     568a,b >> 1,3
     569a + b = 4
     570$ ./hoge
     571a,b >> 1 3
     572a + b = 1
     573$ ./hoge
     574a,b >> 1, 3
     575a + b = 4
     576$ ./hoge
     577a,b >> 1 , 3
     578a + b = 1
     579$ ./hoge
     580a,b >> 1,3,5
     581a + b = 4
     582$ ./hoge
     583a,b >> ,1,3
     584a + b = 0
     585$ ./hoge
     586a,b >> 1
     587a + b = 1
     588$
     589}}}
     590
     591カンマの後ろに空白が入るのは許容されるようですが、カンマの手前に空白が入ると、 2つ目の数字は無視されてしまうようです。それから、カンマで挟んで 3つ数字を入力しようとした場合は頑張って最初の 2つを読み取ってくれますが、いきなりカンマで始まるようなケースでは 1つも数字を読み取ってくれません。さらに、数字を 1つだけ入力した場合は、 2つ目の入力を待たずに終了してしまうようです。
     592
     593それでは、書式指定を "%d,%d" ではなく、 "%d %d" と、空白で挟んだ場合はどうでしょうか。
     594
     595{{{
     596#!c
     597#include <stdio.h>
     598
     599int main()
     600{
     601    int a = 0, b = 0;
     602    printf("a b >> ");
     603    scanf("%d %d", &a, &b); /* カンマではなくスペースで挟む */
     604    printf("a + b = %d\n", a + b);
     605    return 0;
     606}
     607}}}
     608
     609実行してみましょう。
     610
     611{{{
     612$ gcc -o hoge hoge.c
     613$ ./hoge
     614a b >> 1 3
     615a + b = 4
     616$ ./hoge
     617a b >> 1,3
     618a + b = 1
     619$ ./hoge
     620a b >> 1 , 3
     621a + b = 1
     622$ ./hoge
     623a b >> 1 3 5
     624a + b = 4
     625$ ./hoge
     626a b >>  1 3
     627a + b = 4
     628$ ./hoge
     629a b >> 1
     6303
     631a + b = 4
     632$ ./hoge
     633a b >>
     634
     6351
     6363
     637a + b = 4
     638$
     639}}}
     640
     6412つの数字の間に空白以外の文字が入ると、 2つ目以降の数字は無視されてしまうようですね。数字を 3つ入力した場合も最初の 2つまで受け付けてくれるのは、概ね想像通りでしょう。しかし、最初に空白を入れた場合でも問題なく 2つの数字を読み取ってくれたり、数字を 1つだけ入力しても 2つ目の数字の入力を待ってくれたり、あるいは何も入力せずにひたすら Enter を押しても数字の入力を待ち続けてくれたりする辺りは、ちょっと意外だったのではないでしょうか。
     642
     643scanf() 関数は整数以外に、実数や文字列を受け取ることもできます。以下のプログラムを見てみましょう。
     644
     645{{{
     646#!c
     647#include <stdio.h>
     648
     649int main()
     650{
     651    char name[BUFSIZ] = "", format[BUFSIZ];
     652    int age = 0;
     653    float tall = 0, weight = 0;
     654    printf("名前 >> ");
     655    (void) sprintf(format, "%%%ds", BUFSIZ - 1);    /* BUFSIZ == 512 の場合、 "%511s" となる。 */
     656    scanf(format, name);    /* 文字列を受け取る; name は配列なので & は不要 */
     657    printf("年齢 >> ");
     658    scanf("%d", &age);
     659    printf("身長(cm), 体重(kg) >> ");
     660    scanf("%f,%f", &tall, &weight);
     661   
     662    printf("%s、%d歳。身長%.1fcm、体重%.1fkg。\n", name, age, tall, weight);
     663   
     664    return 0;
     665}
     666}}}
     667
     668とりあえず、実行する様子を見てみましょう。
     669
     670{{{
     671$ gcc -o hoge hoge.c
     672$ ./hoge
     673名前 >> 村山俊之
     674年齢 >> 32
     675身長(cm), 体重(kg) >> 161.0, 69.4
     676村山俊之、32歳。身長161.0cm、体重69.4kg。
     677$
     678}}}
     679
     680名前、年齢、身長、体重を問われ、指示に従って入力すると、入力した通りの内容を表示する、というプログラムです。ここでは、名前として文字列を、身長や体重として実数値を入力しています。
     681
     682名前の入力については、ちょっと解りづらいプログラム内容になっていますね。
     683
     684{{{
     685#!c
     686    printf("名前 >> ");
     687    (void) sprintf(format, "%%%ds", BUFSIZ - 1);    /* BUFSIZ == 512 の場合、 "%511s" となる。 */
     688    scanf(format, name);    /* 文字列を受け取る; name は配列なので & は不要 */
     689}}}
     690
     6912行目の '''sprintf() 関数''' は、 3行目の scanf() 関数に渡す書式指定文字列を作っています。もしも、定数 BUFSIZ の値が 512 だった場合、この部分は以下のように記述するのと同じ意味になります。
     692
     693{{{
     694#!c
     695    printf("名前 >> ");
     696    scanf("%511s", name);
     697}}}
     698
     699文字列を取得する場合の書式指定は "%s" ですが、 "%s" だけだと何文字でも受け取って良いことになってしまい、配列 name に確保した領域よりも長い文字列が入力されると、メモリーが破壊されてしまいます。そこで、受け付ける文字列の長さをあらかじめ制限する必要があります。 "%511s" とやると、 char 型配列の要素 511 個分までの文字列を入力し、残りは捨てる、という動作になり、とりあえず安全です。
     700
    550701[[FootNote]]