几乎每个人都会说,最好使用
fgets(..., stdin)
来处理这个问题。
在下面的链接中,我提出了一种安全和正确的技术,可以通过一个可靠的
宏来替换
scanf()
:
一个可以安全替换scanf()的宏
我提出的宏(适用于兼容的
C99编译器)是
safe_scanf()
,如下所示:
#include <stdio.h>
#define safe_scanf(fmt, maxb, ...) { \
char buffer[maxb+1] = { [maxb - 1] = '\0' }; \
fgets(buffer, maxb+1, stdin); \
if ((buffer[maxb - 1] != '\0') && (buffer[maxb - 1] != '\n')) \
while(getchar() != '\n') \
; \
sscanf(buffer, fmt, __VA_ARGS__); \
}
#define MAXBUFF 20
int main(void) {
int x; float f;
safe_scanf("%d %g", MAXBUFF+1, &x, &f);
printf("Your input was: x == %d\t\t f == %g", x, f);
return 0;
}
您需要根据自己的需求调整
MAXBUFF
的值...尽管宏
safe_scanf()
相当可靠,但使用宏的方法存在一些弱点:参数缺少类型检查、缺少返回值(与返回有价值的错误检查信息的“真正”
scanf()
函数几乎没有区别)等。所有这些问题都有解决办法,但这是另一个话题的一部分...也许最精确的解决方案是定义一个具有可变数量参数的函数
my_scanf()
,通过调用联合
fgets()
和
vsscanf()
的
stdarg.h
库来实现。以下是代码:
#include <stdio.h>
#include <stdarg.h>
int my_scanf(const char* fmt, const unsigned int maxbuff, ...) {
va_list ptr;
int ret;
if (maxbuff <= 0)
return EOF;
char buffer[maxbuff+1];
buffer[maxbuff-1] = '\0';
if (fgets(buffer, maxbuff+1, stdin) == NULL)
return EOF;
else {
if ((buffer[maxbuff-1] != '\n') && (buffer[maxbuff-1] != '\0'))
while (getchar() != '\n')
;
va_start(ptr, maxbuff);
ret = vsscanf(buffer, fmt, ptr);
va_end(ptr);
return ret;
}
}
#define MAXBUFF 20
int main(void) {
int x;
float z;
int scanf_ret = my_scanf("%d %g", MAXBUFF, &x, &z);
printf("\nTest:\n x == %d\n z == %g\n scanfret == %d", x, z, scanf_ret);
getchar();
return 0;
}
函数my_scanf()的原型如下:
int my_scanf(const char* fmt, const int maxbuff, ...);
它接受一个格式字符串
fmt
,其行为与任何其他类似于
scanf()
的函数相同。
第二个参数是从标准输入(键盘)实际接受的
字符的最大数量。
返回值是一个
int,如果
maxbuff
没有意义或出现输入错误,则为
EOF
。如果返回非负值,则与标准函数
sscanf()
或
vsscanf()
返回的值相同。
在函数内部,
maxbuff
增加1,因为
fgets()
为额外的'\0'字符腾出了一些空间。
非正数值的
maxbuff
会立即被丢弃。
fgets()
将从
stdin
(键盘)读取一个字符串,最多包含
maxbuff
个字符,包括'\n'。
如果用户输入了一个非常长的字符串,则它将被截断,并且需要某种“刷新”机制以丢弃所有字符到下一个'\n'(
ENTER)。否则,下一个键盘读取可能具有旧字符,这是不可取的。
“刷新”的条件是
fgets()
在读取
stdin
后未达到'\n'。
只有当
buffer[maxbuff - 1]
不等于'\0'或'\n'时,才会出现这种情况。
(
检查一下!)
最后,使用
stdarg.h
的适当组合
宏和函数
vsscanf()
来处理可变参数列表。
MAX_STR_LEN
? - amulous"%100s"
,那么分配需要101个字节,所以在你的例子中,你需要malloc(MAX_STR_LEN+1)
或者是"%99s"
。 - Tim Sylvester