ユーザーが文字列を入力するときにscanfを使用しないように言われました。代わりに、ほとんどのエキスパートとStackOverflowのユーザーによるgets()を探してください。 StackOverflowで、文字列にscanf overgetを使用しない理由を尋ねたことはありません。これは実際の質問ではありませんが、この質問への回答をいただければ幸いです。
今、実際の質問に来ています。私はこのタイプのコードに出くわしました-
scanf("%[^\n]s",a);
これは、ユーザーが新しい行文字を入力するまで文字列を読み取り、空白も文字列と見なします。
使っても問題ありませんか
scanf("%[^\n]s",a);
取得する代わりに?
見た目はscanf関数よりも最適化されており、getsは純粋に文字列の処理専用です。これについて教えてください。
更新
This リンクは私がそれをよりよく理解するのを助けました。
gets(3)
は危険であり、絶対に避けてください。 gets(3)
がnotセキュリティ上の欠陥である場合の使用は想像できません。
scanf(3)
の%s
も危険です。割り当てたバッファのサイズを示すには、「フィールド幅」指定子を使用する必要があります。フィールド幅がないと、このルーチンはgets(3)
と同じくらい危険です。
char name[64];
scanf("%63s", name);
GNU Cライブラリはa
modifier to %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.
まず、s
がフォーマット文字列で何をしているのかが明確ではありません。 _%[^\n]
_の部分は、自給自足のフォーマット指定子です。ご存知のように、これは_%s
_形式の修飾子ではありません。これは、_"%[^\n]s"
_フォーマット文字列がscanf
によって2つの独立したフォーマット指定子として解釈されることを意味します:_%[^\n]
_の後に1つのs
が続きます。これにより、scanf
は、_\n
_が検出されるまで(_\n
_は未読のまま)すべてを読み取るように指示され、次の入力文字はs
である必要があります。これはまったく意味がありません。このような自己矛盾する形式に一致する入力はありません。
第二に、明らかに意味されたのはscanf("%[^\n]", a)
です。これは[もう利用できません] gets
(またはfgets
)にやや近いですが、同じではありません。 scanf
では、各形式指定子が少なくとも1つの入力文字と一致する必要があります。 scanf
は失敗し、要求されたフォーマット指定子の入力文字と一致しない場合は中止されます。これは、scanf("%[^\n]",a)
が空の入力行、つまり_\n
_文字を含む行をすぐに読み取ることができないことを意味します。このような行を上記のscanf
にフィードすると、失敗を示すために_0
_が返され、a
は変更されません。これは、一般的なラインベースの入力関数の動作とは大きく異なります。
(これは、_%[]
_形式のかなり驚くべき、一見非論理的です。個人的には、_%[]
_が空のシーケンスに一致し、空の文字列を生成できるようにしたいと思いますが、それは標準的なscanf
動作します。)
入力を行ごとに読み取りたい場合は、fgets
が最適なオプションです。