问题
I have been told that scanf should not be used when user inputs a string. Instead, go for gets() by most of the experts and also the users on StackOverflow. I never asked it on StackOverflow why one should not use scanf over gets for strings. This is not the actual question but answer to this question is greatly appreciated.
Now coming to the actual question. I came across this type of code -
scanf("%[^\n]s",a);
This reads a string until user inputs a new line character, considering the white spaces also as string.
Is there any problem if I use
scanf("%[^\n]s",a);
instead of gets?
Is gets more optimized than scanf function as it sounds, gets is purely dedicated to handle strings. Please let me know about this.
Update
This link helped me to understand it better.
回答1:
gets(3)
is dangerous and should be avoided at all costs. I cannot envision a use where gets(3)
is not a security flaw.
scanf(3)
's %s
is also dangerous -- you must use the "field width" specifier to indicate the size of the buffer you have allocated. Without the field width, this routine is as dangerous as gets(3)
:
char name[64];
scanf("%63s", name);
The GNU C library provides the a
modifier to %s
that allocates the buffer for you. This non-portable extension is probably less difficult to use correctly:
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.
回答2:
Firstly, it is not clear what that s
is doing in your format string. The %[^\n]
part is a self-sufficient format specifier. It is not a modifier for %s
format, as you seem to believe. This means that "%[^\n]s"
format string will be interpreted by scanf
as two independent format specifiers: %[^\n]
followed by a lone s
. This will direct scanf
to read everything until \n
is encountered (leaving \n
unread), and then require that the next input character is s
. This just doesn't make any sense. No input will match such self-contradictory format.
Secondly, what was apparently meant is scanf("%[^\n]", a)
. This is somewhat close to [no longer available] gets
(or fgets
), but it is not the same. scanf
requires that each format specifiers matches at least one input character. scanf
will fail and abort if it cannot match any input characters for the requested format specifier. This means that scanf("%[^\n]",a)
is not capable of reading empty input lines, i.e. lines that contain \n
character immediately. If you feed such a line into the above scanf
, it will return 0
to indicate failure and leave a
unchanged. That's very different from how typical line-based input functions work.
(This is a rather surprising and seemingly illogical properly of %[]
format. Personally, I'd prefer %[]
to be able to match empty sequences and produce empty strings, but that's not how standard scanf
works.)
If you want to read the input in line-by-lane fashion, fgets
is your best option.
来源:https://stackoverflow.com/questions/8177752/scanf-ns-a-vs-getsa