★scanfと文字列★


「文字列」の入力用にscanfを使ってきましたが、scanfには色々と知っておかなければならない点があります。

<sample program 082-01>に↓の文字列を打ち込んでみてください。

入力文字列

 ABC DEF

 ※ABCとDEFの間に半角空白を入れてください。

<実行結果>

ABC DEF ←scanfの入力
ABC
続行するには何かキーを押してください・・・

scanfは「%s」を指定した場合、半角空白を「区切り文字」として認識し、"DEF"を入力バッファという場所に残してしまいます。

"DEF"は残っていますから、再びscanfを実行すると読み込むことが出来ます。

<sample program col027-01>

#include <stdio.h>

#define MAX_STRING 10

int main(void)
{
    char str[MAX_STRING];

    scanf("%s", str);

    printf("%s\n", str);

    scanf("%s", str);

    printf("%s\n", str);

    return 0;
}

<実行結果>

ABC DEF ←1回目のscanfの入力
ABC
DEF
続行するには何かキーを押してください・・・

1回しか入力していないのですが、scanfは2回実行されました。

1回目のscanfで"ABC"を読み込み、2回目のscanfで"DEF"を読み込んでいます。

これを解消するためには、新しい書式が必要になります。

<sample program col027-02>

#include <stdio.h>

#define MAX_STRING 10

int main(void)
{
    char str[MAX_STRING];

    scanf("%[^\n]", str);

    printf("%s\n", str);

    return 0;
}

<実行結果>

ABC DEF ←scanfの入力
ABC DEF
続行するには何かキーを押してください・・・

まず、"%[]"は、[]内に書かれた文字が続く間、バッファから文字を取り出すという意味になります。

次のようにプログラムを書くと実際に見ることが出来ます。

<sample program col027-03>

#include <stdio.h>

#define MAX_STRING 10

int main(void)
{
    char str[MAX_STRING];

    scanf("%[abcdef]", str);

    printf("%s\n", str);

    return 0;
}

<実行結果>

abc ←scanfの入力
abc
続行するには何かキーを押してください・・・

<実行結果>

aakk ←scanfの入力
aa
続行するには何かキーを押してください・・・

<実行結果>

aakkaa ←scanfの入力
aa
続行するには何かキーを押してください・・・

[]内に書かれている"abcdef"のいずれかの文字が入力されている間は配列strに文字を読み込んでいます。

しかし、それ以外の文字が出てくると、文字を読み込むのをやめています

読み込まれなかった文字はバッファに残り、次の入力で読み込まれます。


では、"%[^\n]"はどういう意味かと言うと、

「^(カレット)」は「否定(〜以外)」という意味で使われており、「改行以外の文字」という意味になります。

ですから、「改行以外の文字が続いている間は読み込まれる」という意味です。

こうすれば、半角空白も読み込んでくれますが、入門書などには書かれていないことが多いです。


もう一つ、知っておいて欲しいことを書きます。

下のプログラムで10文字以上の文字を入力するとどうなるか、以前試しましたよね。

<sample program col027-04>

#include <stdio.h>

#define MAX_STRING 10

int main(void)
{
    char str[MAX_STRING];

    scanf("%s", str);

    printf("%s\n", str);

    return 0;
}

<実行結果>

abcdefghijklmn ←scanfの入力
abcdefghijklmn

※ここまで表示された時点で↓のダイアログが表示される。


続行するには何かキーを押してください・・・

9文字までしか入力できない!と分かっていてもミスなどが起きる可能性もあります。

誰がどのように使うか分からないため、対策を書きます。

<sample program col027-05>

#include <stdio.h>

#define MAX_STRING 10

int main(void)
{
    char str[MAX_STRING];

    scanf("%9s", str);

    printf("%s\n", str);

    return 0;
}

<実行結果>

abcdefghijklmn ←scanfの入力
abcdefghi
続行するには何かキーを押してください・・・

入力は15文字分ですが、配列strには9文字しか入っていません。

入力の書式を"%s"から"%9s"に変更したため、9文字までしか読み込まなくなりました

これなら大丈夫そうですね。


しかしこれでは半角空白の問題が再浮上してきます・・・

両方を合わせると↓のような書式になります。

<sample program col027-06>

#include <stdio.h>

#define MAX_STRING 10

int main(void)
{
    char str[MAX_STRING];

    scanf("%9[^\n]", str);

    printf("%s\n", str);

    return 0;
}

<実行結果>

abc def ghi jkl ←scanfの入力
abc def g
続行するには何かキーを押してください・・・

ちゃんと両方に対応出来ていることを確認してください。


入力できる文字数を制限しましたが、問題が残っています。

制限されて残った文字は入力バッファに残り、再びscanfを実行すると読み込める、と先頭で書きました。

今回も同じように確かめてみましょう。

<sample program col027-07>

#include <stdio.h>

#define MAX_STRING 10

int main(void)
{
    char str[MAX_STRING];

    scanf("%9[^\n]", str);

    printf("%s\n", str);

    scanf("%9[^\n]", str);

    printf("%s\n", str);

    return 0;
}

<実行結果>

abc def ghi ←scanfの入力
abc def g
hi
続行するには何かキーを押してください・・・

9文字しか入りませんので、"hi"という文字列はバッファに残っていました。

もう一度scanfを実行することで、バッファにあった"hi"を読み込んで表示されました。

しかし、毎回バッファに文字が残っているかどうかは分かりません。

9文字以内できちんと入力される時もあれば、オーバーして残る場合もあります。


そこで、次の書式です。

<sample program col027-08>

#include <stdio.h>

#define MAX_STRING 10

int main(void)
{
    char str[MAX_STRING];

    scanf("%9[^\n]%*[^\n]", str);

    printf("%s\n", str);

    scanf("%9[^\n]%*[^\n]", str);

    printf("%s\n", str);

    return 0;
}

<実行結果>

abc def ghi ←scanfの入力
abc def g
abc def g
続行するには何かキーを押してください・・・

"%[^\n]"の後ろに"%*[^\n]"を追加しました。

"%*"は後ろに続く書式に合わせてデータをバッファから取り出しますが、配列には入れません。

今回の書式は"[^\n]"改行以外、ですから改行以外の文字を取り除きました

でも、おかしいです。 みなさんも実際に実行していれば気づくと思います。

↑のプログラムが、きちんと動作するのであれば、2回目のscanfの前に入力バッファはクリアされ、2回目のscanfで別も文字列を入力出来るはずです。

原因は3行上にありますが、「改行」が残っているからです。

2回目のscanfは、残った「改行」だけを読み込んで終わっているのです。


この「改行」を消すため、↓のように書式を追加します。

<sample program col027-09>

#include <stdio.h>

#define MAX_STRING 10

int main(void)
{
    char str[MAX_STRING];

    scanf("%9[^\n]%*[^\n]%*c", str);

    printf("%s\n", str);

    scanf("%9[^\n]%*[^\n]%*c", str);

    printf("%s\n", str);

    return 0;
}

<実行結果>

abc def ghi ←1回目のscanfの入力
abc def g
jkl mno pqr ←2回目のscanfの入力
jkl mno p
続行するには何かキーを押してください・・・

一番後ろに"%*c"を付けて、改行文字を取り除きました。

きちんと2回目の文字列も入力出来ています。

ということは、1回目の入力ではみ出した部分は2回目の入力時には無くなっているということです。


ブラウザの戻るボタンで戻ってください。