使用gets
模仿scanf
的功能的最佳方法是什么?
这是我目前的尝试
int main()
{
char cvalue[20]; //char array to store input string
int iloop=0; //integer variable for loop
for(iloop=0;iloop<20;iloop++) // for loop to get the string char by char
{
scanf("%c",&cvalue[iloop]); //getting input
if(cvalue[iloop]=='\n') //if input is newline skip further looping
break;
} // end of loop
cvalue[iloop]='\0'; //set end of the character for given input
printf("%s",cvalue); //printing the given string
return 0;
}
答案 0 :(得分:2)
您可以scanf
这种方式使用gets
scanf("%[^\n]",&a);
答案 1 :(得分:0)
您的尝试并不真正模仿gets()
,因为gets()
只是将字节放入提供的缓冲区,直到到达行尾。你应该意识到gets()
是危险的,应该避免。它不提供缓冲区溢出的任何保护。因此,模仿它也是值得怀疑的。
鉴于此,你的尝试有一些我看到的缺陷。首先,它循环到输入缓冲区的完整大小。如果输入行是20字节或更长,这不会给你留下存储NUL终结符的空间。这意味着您可以尝试将\0
存储在数组边界外的cvalue[20]
。您可以通过缩短for
循环来解决此问题:
for(iloop=0;iloop<19;iloop++) // for loop to get the string char by char
第二个缺陷是您不检查scanf()
调用是否成功。如果您检测到故障,您还应该离开循环:
if (scanf("%c",&cvalue[iloop]) != 1) { //getting input
break;
}
以下是我尝试使用gets()
创建更安全的scanf()
版本。
char *getsn (char *s, size_t sz) {
char c;
char fmt[sizeof(sz) * CHAR_BIT + sizeof("[^\n]")];
if (sz == 0) return 0;
if (sz == 1) {
s[0] = '\0';
return s;
}
s[sz-2] = '\0';
snprintf(fmt, sizeof(fmt), "%%%lu%s", (unsigned long)sz-1, "[^\n]");
switch (scanf(fmt, s)) {
case 0: s[0] = '\0';
scanf("%c", &c);
return s;
case 1: scanf("%c", &c);
if (s[sz-2] != '\0' && c != '\n') {
ungetc(c, stdin);
}
return s;
default: break;
}
return 0;
}
更安全的版本使用snprintf()
创建一个格式字符串,用于限制scanf()
应存储的字符数。因此,如果提供的sz
参数为100,则生成的格式字符串将为"%99[^\n]"
。然后,它确保仅从输入流中删除\n
(如果实际遇到它)。
答案 2 :(得分:0)
您需要观察gets()
的常见危险。
使用scanf()
的挑战是
1)确保消耗\n
。 scanf("%[^\n]",...
不这样做。
2)如果仅读取str
,则确保\0
获得\n
3)处理EOF和I / O错误并返回0
4)确保前导空格被str
读入,scanf("%s"
跳过它们。
#include <stdio.h>
// On success, the gets() returns str.
// If EOF encountered, the eof indicator is set (feof).
// If this happens before any characters could be read,
// pointer returned is a null pointer.
// If a read error occurs, the error (ferror) is set
// and a null pointer is also returned.
char *gets_via_scanf( char * str ) {
// Reads characters from stdin & saves them into str until \n or the end-of-file.
// \n, if found, is not copied into str.
int retval = scanf("%[^\n]",str); // %[ does not skip leading whitespace
if (retval == EOF) return 0;
if (retval == 0) {
*str = '\0'; // Happens when users only types in \n
}
char ch;
scanf("%c",&ch); // Consume leftover \n, could be done with getc()
return str;
}