「C言語の基礎 - 標準入力から安全に文字列を取得する」の版間の差分

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動
(ページの作成:「== 指定サイズ内で1行を受け取る == 次のように、文字列の格納領域が256[byte]用意されているとする。<br> <source lang="c"> char buffer…」)
 
25行目: 25行目:


== scanf関数の利用 ==
== scanf関数の利用 ==
scanf関数は多機能であり、フォーマットを記述することで動作のカスタマイズが可能である。
scanf関数は多機能であり、フォーマットを記述することで動作のカスタマイズが可能である。<br>
<br>
<br>
'''scanf関数のフォーマット'''<br>
以下に、<code>scanf</code>関数のフォーマットを記載する。<br>
* %sは全ての空白文字を無視する。そこで、%sの代わりに%[^\n]と指定することで、無視する対象を改行だけに限定することができる。<br>%255[^\n]は、改行以外を1〜255文字読み込むことを意味する。
* %sは全ての空白文字(半角スペースも含む)を無視するため、%sの代わりに%[^\n]と指定することで、無視する対象を改行だけに限定できる。<br>例えば、<code>%255[^\n]</code>は、改行以外の文字列を1〜255文字読み込むことを意味する。
* %の代わりに%*を使用すると、その部分を読み飛ばすことができる。<br>1行に256文字以上入力された場合、最初の255文字までを受け取って残りを捨てる場合は、%255[^\n]%*[^\n]と記述する。
* <code>%</code>の代わりに<code>%*</code>を使用すると、その部分を読み飛ばすことができる。<br>例えば、256文字以上入力する場合、最初の255文字までを受け取り、残りを捨てる場合は、<code>%255[^\n]%*[^\n]</code>と記述する。
* 再度scanf関数を使用する場合に備えて、残った改行は%*cで読み飛ばす。これで保持されていた入力データは全て処理されたことになる。<br>ただし、次に読み取るものが%dなど数値である場合には、これをしなくても特に影響はない。
* 再度<code>scanf</code>関数を使用する場合に備えて、残った改行は<code>%*c</code>で読み飛ばす。<br>これにより、保持されていた入力データは全て処理されたことになる。<br>ただし、次に読み取るものが<code>%d</code>等の数値である場合には、これをしなくても特に影響はない。
<br>
<br>
また、scanf関数は正常に読み取って変数に格納できたパラメータの数を返すので、これを成功したかどうかの判定に用いることができる。<br>
また、<code>scanf</code>関数は正常に読み取って変数に格納できたパラメータの数を返すので、これを成功したかどうかの判定に用いることができる。<br>
%255[^\n]%*[^\n] で実行した場合の返り値は以下のようになる。<br>
<code>%255[^\n]%*[^\n]</code>を実行した場合の戻り値は、以下のようになる。<br>
* 1文字以上読み取れたときは 1
* 1文字以上読み取れたときは 1
* 改行だけが入力されたときは 0
* 改行だけが入力されたときは 0
* 最初から Ctrl+D (Windowsの場合は Ctrl+Z) でEOFが入力されたときは EOF(EOF定数の値は、-1である)
* 最初から [Ctrl] + [D](Linux)または[Ctrl] + [Z](Windows)でEOFが入力された時は、EOF(EOF定数の値 : -1)
* 失敗した場合は、return 1;としてプログラムを異常終了扱いにするとよい。
* 失敗した場合は、<code>return 1;</code>としてプログラムを異常終了扱いにするとよい。
<br>
<br>
以下の例では、必ず1文字以上入力させている。<br>
以下の例では、必ず1文字以上入力させている。<br>
43行目: 43行目:
  #include <stdio.h>
  #include <stdio.h>
   
   
  int main(void)
  int main()
  {
  {
     char buffer[256] = {'\0'};
     char buffer[256] = {'\0'};
64行目: 64行目:
  #include <stdio.h>
  #include <stdio.h>
   
   
  int main(void)
  int main()
  {
  {
     char buffer[256] = {'\0'};
     char buffer[256] = {'\0'};

2020年12月15日 (火) 21:55時点における版

指定サイズ内で1行を受け取る

次のように、文字列の格納領域が256[byte]用意されているとする。

 char buffer[256] = {'\0'};


scanf関数とfgets関数の主な違いを纏めると以下のようになる。
NULL文字\0が終端に自動付与されることを考慮すると、ユーザが実質入力できるのは255[byte]までであることに注意する。
また、scanf関数はscanf("%s", buffer);のようにサイズを指定せずに使用できるが、バッファオーバーランの危険性があるので避けること。

説明 scanf関数 fgets関数
基本的な使用法 scanf("%255s", buffer) fgets(buffer, 256, stdin)
改行の扱い 改行文字の直前まで読み込む 改行文字も一緒に読み込む
成功時の戻り値 読み込んだパラメータ数 buffer
失敗時の戻り値 0
または
EOF (-1)
NULL
入力文字の取得 できる できない



scanf関数の利用

scanf関数は多機能であり、フォーマットを記述することで動作のカスタマイズが可能である。

以下に、scanf関数のフォーマットを記載する。

  • %sは全ての空白文字(半角スペースも含む)を無視するため、%sの代わりに%[^\n]と指定することで、無視する対象を改行だけに限定できる。
    例えば、%255[^\n]は、改行以外の文字列を1〜255文字読み込むことを意味する。
  • %の代わりに%*を使用すると、その部分を読み飛ばすことができる。
    例えば、256文字以上入力する場合、最初の255文字までを受け取り、残りを捨てる場合は、%255[^\n]%*[^\n]と記述する。
  • 再度scanf関数を使用する場合に備えて、残った改行は%*cで読み飛ばす。
    これにより、保持されていた入力データは全て処理されたことになる。
    ただし、次に読み取るものが%d等の数値である場合には、これをしなくても特に影響はない。


また、scanf関数は正常に読み取って変数に格納できたパラメータの数を返すので、これを成功したかどうかの判定に用いることができる。
%255[^\n]%*[^\n]を実行した場合の戻り値は、以下のようになる。

  • 1文字以上読み取れたときは 1
  • 改行だけが入力されたときは 0
  • 最初から [Ctrl] + [D](Linux)または[Ctrl] + [Z](Windows)でEOFが入力された時は、EOF(EOF定数の値 : -1)
  • 失敗した場合は、return 1;としてプログラムを異常終了扱いにするとよい。


以下の例では、必ず1文字以上入力させている。

 #include <stdio.h>
 
 int main()
 {
    char buffer[256] = {'\0'};
 
    printf("Input: ");
    if (scanf("%255[^\n]%*[^\n]", buffer) != 1)
    {
       return 1;
    }
    scanf("%*c");
 
    printf("Output: %s\n", buffer);
 
    return 0;
 }


以下の例では、改行だけの入力を認めている。

 #include <stdio.h>
 
 int main()
 {
    char buffer[256] = {'\0'};
 
    printf("Input: ");
    if (scanf("%255[^\n]%*[^\n]", buffer) == EOF)
    {
       return 1;
    }
    scanf("%*c");
 
    printf("Output: %s\n", buffer);
 
    return 0;
 }


以下の例では、入力された文字数も取得している。(%255[^\n]の後ろは、unsigned / intの場合は%n、size_t / ssize_tの場合は%znを指定する)
(%n系は符号付き整数で取得するように定義されているが、負の値が出現する可能性がゼロなので、符号無し整数でも問題ない)

 #include <stdio.h>
 
 int main(void)
 {
    char buffer[256] = {'\0'};
    size_t length;
 
    printf("Input: ");
    if (scanf("%255[^\n]%zn%*[^\n]", buffer, &length) != 1)
    {
       return 1;
    }
    scanf("%*c");
 
    printf("Output: %s\n", buffer);
    printf("Length: %zu\n", length);
 
    return 0;
 }



fgets関数の利用

fgets関数は、改行も1行に含めて一緒に取得する。
削除する場合は、各自でコードを記述しなければならない。
strlen関数を使用するなどして、文字列長を求めることも必要である。

また、戻り値は以下のようになる。

  • 1文字以上読み取れた場合は、buffer(改行だけでも1文字以上という扱いになる)
  • 最初からCtrl+D(Windowsの場合はCtrl+Z)でEOFが入力された場合は、NULL
  • 失敗した場合は、そのままreturn 1;としてプログラムを異常終了扱いにさせるとよい。


以下の例では、必ず1文字以上入力させて改行を削除している。

 #include <stdio.h>
 #include <string.h>
 
 int main(void)
 {
    char buffer[256] = {'\0'};
    size_t length;
 
    printf("Input: ");
    if (fgets(buffer, 256, stdin) == NULL || buffer[0] == '\n')
    {
       return 1;
    }
    length = strlen(buffer);
    if (buffer[length - 1] == '\n')
    {
       buffer[--length] = '\0';
    }
 
    printf("Output: %s\n", buffer);
    printf("Length: %zu\n", length);
 
    return 0;
 }


以下の例では、改行だけの入力を認めて改行を削除している。

 #include <stdio.h>
 #include <string.h>
 
 int main(void)
 {
    char buffer[256];
    size_t length;
 
    printf("Input: ");
    if (fgets(buffer, 256, stdin) == NULL)
    {
       return 1;
    }
    length = strlen(buffer);
    if (length > 0 && buffer[length - 1] == '\n')
    {
       buffer[--length] = '\0';
    }
 
    printf("Output: %s\n", buffer);
    printf("Length: %zu\n", length);
 
    return 0;
 }


以下の例では、改行だけの入力を認めて改行を削除している。

 #include <stdio.h>
 
 int main(void)
 {
    char buffer[256];
 
    printf("Input: ");
    if (fgets(buffer, 256, stdin) == NULL)
    {
       return 1;
    }
 
    printf("Output: %s\n", buffer);
 
    return 0;
 }