In their book The Practice of Programming (which is well worth reading), Kernighan and Pike discuss this problem, and they solve it by using snprintf()
to create the string with the correct buffer size for passing to the scanf()
family of functions. In effect:
int scanner(const char *data, char *buffer, size_t buflen)
{
char format[32];
if (buflen == 0)
return 0;
snprintf(format, sizeof(format), "%%%ds", (int)(buflen-1));
return sscanf(data, format, buffer);
}
Note, this still limits the input to the size provided as 'buffer'. If you need more space, then you have to do memory allocation, or use a non-standard library function that does the memory allocation for you.
Note that the POSIX 2008 (2013) version of the scanf()
family of functions supports a format modifier m
(an assignment-allocation character) for string inputs (%s
, %c
, %[
). Instead of taking a char *
argument, it takes a char **
argument, and it allocates the necessary space for the value it reads:
char *buffer = 0;
if (sscanf(data, "%ms", &buffer) == 1)
{
printf("String is: <<%s>>
", buffer);
free(buffer);
}
If the sscanf()
function fails to satisfy all the conversion specifications, then all the memory it allocated for %ms
-like conversions is freed before the function returns.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…