9

ユーザーが文字列を入力するときにscanfを使用しないように言われました。代わりに、ほとんどのエキスパートとStackOverflowのユーザーによるgets()を利用してください。StackOverflowで、文字列にscanfovergetを使用すべきではない理由を尋ねたことはありません。これは実際の質問ではありませんが、この質問への回答をいただければ幸いです。

今、実際の質問に来ています。私はこのタイプのコードに出くわしました-

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

これは、ユーザーが新しい行文字を入力するまで文字列を読み取ります。空白も文字列と見なされます。

使用しても問題ありませんか

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

取得する代わりに?

音としてはscanf関数よりも最適化されており、getsは純粋に文字列の処理専用です。これについて教えてください。

アップデート

このリンクは私がそれをよりよく理解するのに役立ちました。

4

2 に答える 2

6

gets(3)危険であり、絶対に避ける必要があります。セキュリティ上の欠陥gets(3)ない場合の使用は想定できません。

scanf(3)%sも危険です。割り当てたバッファのサイズを示すには、「フィールド幅」指定子を使用する必要があります。フィールド幅がないと、このルーチンは次のように危険gets(3)です。

char name[64];
scanf("%63s", name);

GNU Cライブラリは、バッファを割り当てるa 修飾子を提供します。%sこの移植性のない拡張機能は、おそらく正しく使用するのがそれほど難しくありません。

   The GNU C library supports a nonstandard extension that
   causes the library to dynamically allocate a string of
   sufficient size for input strings for the %s and %a[range]
   conversion specifiers.  To make use of this feature, specify
   a as a length modifier (thus %as or %a[range]).  The caller
   must free(3) the returned string, as in the following
   example:

       char *p;
       int n;

       errno = 0;
       n = scanf("%a[a-z]", &p);
       if (n == 1) {
           printf("read: %s\n", p);
           free(p);
       } else if (errno != 0) {
           perror("scanf");
       } else {
           fprintf(stderr, "No matching characters\n"):
       }

   As shown in the above example, it is only necessary to call
   free(3) if the scanf() call successfully read a string.
于 2011-11-18T04:39:26.287 に答える
4

まず、それがsフォーマット文字列で何をしているのかが明確ではありません。この%[^\n]部分は、自給自足のフォーマット指定子です。%sあなたが信じているように、それはフォーマットの修飾子ではありません。これは、フォーマット文字列が2つの独立したフォーマット指定子として"%[^\n]s"解釈されることを意味します。その後に1つだけが続きます。これにより、検出されるまで(未読のまま)すべてを読み取るように指示され、次の入力文字がである必要があります。これはまったく意味がありません。このような自己矛盾する形式に一致する入力はありません。scanf%[^\n]sscanf\n\ns

第二に、明らかに意味されたのはですscanf("%[^\n]", a)。これは[もう利用できません] gets(またはfgets)にやや近いですが、同じではありません。scanf各フォーマット指定子が少なくとも1つの入力文字と一致する必要があります。scanf要求されたフォーマット指定子の入力文字と一致しない場合、失敗して中止します。これは、scanf("%[^\n]",a)空の入力行、つまり\n文字をすぐに含む行を読み取ることができないことを意味します。このような行を上記に入力すると、失敗を示すためscanfに戻り、変更されません。これは、一般的なラインベースの入力関数の動作とは大きく異なります。0a

(これはかなり驚くべきことであり、一見非論理的な形式です。個人的には、空のシーケンスを照合して空の文字列を生成できるようにし%[]たいと思いますが、それは標準の仕組みではありません。)%[]scanf

行ごとに入力を読み取りたい場合fgetsは、が最適なオプションです。

于 2016-11-10T20:59:46.453 に答える