获取scanf以在读取换行符时退出?
如果我在终端输入5 5
,按回车键,再次按回车键,我想退出循环。
int readCoefficents(double complex *c){ int i = 0; double real; double img; while(scanf("%f %f", &real, &img) == 2) c[i++] = real + img * I; c[i++] = 1 + 0*I; // most significant coefficient is assumed to be 1 return i; }
显然,该代码并没有为我完成工作(是的,我知道有一个缓冲区溢出等待发生)。
除非我输入一个字母(或一些非数字,而不是空白字符串),否则scanf
不会退出。 读取空行后如何让scanf退出?
使用fgets读取控制台输入:
int res = 2; while (res == 2) { char buf[100]; fgets(buf, sizeof(buf), stdin); res = sscanf(buf, "%f %f", &real, &img); if (res == 2) c[i++] = real + img * I; } c[i++] = 1 + 0*I; // most significant coefficient is assumed to be 1 return i;
您遇到的具体问题是%f
的scanf
格式字符串将跳过空格( 包括换行符),直到找到要扫描的实际字符。 从c99标准:
转换规范按以下步骤执行:
– 跳过输入的空白字符(由isspace
函数指定),除非规范包含'['
,'c'
或'n'
说明符。
和其他地方,描述isspace()
:
标准的空格字符如下:空格
' '
,换页'\f'
,换行'\n'
,回车'\r'
,水平标签'\t'
和垂直标签'\v'
。
最好的办法是使用fgets
来获取行(这可以很容易地防止缓冲区溢出),然后在结果行上使用sscanf
。
scanf
函数是您应该非常谨慎地查看的函数之一。 以下代码是我经常用来处理行输入的代码:
#include #include #define OK 0 #define NO_INPUT 1 #define TOO_LONG 2 static int getLine (char *prmpt, char *buff, size_t sz) { int ch, extra; // Get line with buffer overrun protection. if (prmpt != NULL) { printf ("%s", prmpt); fflush (stdout); } if (fgets (buff, sz, stdin) == NULL) return NO_INPUT; // If it was too long, there'll be no newline. In that case, we flush // to end of line so that excess doesn't affect the next call. if (buff[strlen(buff)-1] != '\n') { extra = 0; while (((ch = getchar()) != '\n') && (ch != EOF)) extra = 1; return (extra == 1) ? TOO_LONG : OK; } // Otherwise remove newline and give string back to caller. buff[strlen(buff)-1] = '\0'; return OK; }
// Test program for getLine(). int main (void) { int rc; char buff[10]; rc = getLine ("Enter string> ", buff, sizeof(buff)); if (rc == NO_INPUT) { // Extra NL since my system doesn't output that on EOF. printf ("\nNo input\n"); return 1; } if (rc == TOO_LONG) { printf ("Input too long [%s]\n", buff); return 1; } printf ("OK [%s]\n", buff); return 0; }
使用各种组合进行测试:
pax> ./prog Enter string>[CTRL-D] No input pax> ./prog Enter string> a OK [a] pax> ./prog Enter string> hello OK [hello] pax> ./prog Enter string> hello there Input too long [hello the] pax> ./prog Enter string> i am pax OK [i am pax]
我要做的是使用此函数安全地获取一行,然后简单地使用:
sscanf (buffer, "%f %f", &real, &img)
获取实际值(并检查计数)。
事实上,这是一个更接近你想要的完整程序:
#include #include #define OK 0 #define NO_INPUT 1 #define TOO_LONG 2 static int getLine (char *prmpt, char *buff, size_t sz) { int ch, extra; // Get line with buffer overrun protection. if (prmpt != NULL) { printf ("%s", prmpt); fflush (stdout); } if (fgets (buff, sz, stdin) == NULL) return NO_INPUT; // If it was too long, there'll be no newline. In that case, we flush // to end of line so that excess doesn't affect the next call. if (buff[strlen(buff)-1] != '\n') { extra = 0; while (((ch = getchar()) != '\n') && (ch != EOF)) extra = 1; return (extra == 1) ? TOO_LONG : OK; } // Otherwise remove newline and give string back to caller. buff[strlen(buff)-1] = '\0'; return OK; }
int main (void) { int i = 1, rc; char prompt[50], buff[50]; float real, imag; while (1) { sprintf (prompt, "\nEnter real and imaginary for #%3d: ", i); rc = getLine (prompt, buff, sizeof(buff)); if (rc == NO_INPUT) break; if (*buff == '\0') break; if (rc == TOO_LONG) { printf ("** Input too long [%s]...\n", buff); } if (sscanf (buff, "%f %f", &real, &imag) == 2) { printf ("Values were %f and %f\n", real, imag); i++; } else { printf ("** Invalid input [%s]\n", buff); } } return 0; }
以及测试运行:
pax> ./testprog Enter real and imaginary for # 1: hello ** Invalid input [hello] Enter real and imaginary for # 1: hello there ** Invalid input [hello there] Enter real and imaginary for # 1: 1 ** Invalid input [1] Enter real and imaginary for # 1: 1.23 4.56 Values were 1.230000 and 4.560000 Enter real and imaginary for # 2: pax> _
有一种方法可以使用scanf做你想做的事:
int readCoefficents(double complex *c) { int i = 0; double real; double img; char buf[2]; while (scanf("%1[\n]", buf) == 0) { // loop until a blank line or EOF if (scanf("%lf %lf", &real, &img) == 2) // read two floats c[i++] = real + img * I; scanf("%*[^\n]"); // skip the rest of the line scanf("%*1[\n]"); // and the newline } c[i++] = 1 + 0*I; // most significant coefficient is assumed to be 1 return i; }
如果用户只在一行上输入1个浮点数,它将读取第二个值的下一行。 如果输入任何随机垃圾,它将跳到换行符并再次尝试下一行。 否则,它将继续读取浮点值对,直到用户输入空行或达到EOF。
重新PAXDIABLO解决方案:它无法正常使用用户输入的EMPTY行,因此该行应添加到您的getLine()函数中
if (strlen(buff) <= 1) return NO_INPUT;
行后:
if (fgets (buff, sz, stdin) == NULL) return NO_INPUT;
所以它将成为:
... if (strlen(buff) <= 1) return NO_INPUT; if (fgets (buff, sz, stdin) == NULL) return NO_INPUT; ....