C语言 读取换行符时让 scanf 退出?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3723044/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Get scanf to quit when it reads a newline?
提问by Matt
If I input 5 5at the terminal, press enter, and press enter again, I want to exit out of the loop.
如果我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;
}
Obviously, that code isn't doing the job for me (and yes, I know there is a buffer overflow waiting to happen).
显然,该代码对我不起作用(是的,我知道有缓冲区溢出等待发生)。
scanfwon't quit unless I type in a letter (or some non-numeric, not whitespace string). How do I get scanf to quit after reading an empty line?
scanf除非我输入一个字母(或一些非数字,而不是空白字符串),否则不会退出。阅读空行后如何让 scanf 退出?
回答by paxdiablo
The specific problem you're having is that a scanfformat string of %fwill skip white space (includingnewlines) until it finds an actual character to scan. From the c99 standard:
您遇到的具体问题是scanf格式字符串%f将跳过空格(包括换行符),直到找到要扫描的实际字符。来自 c99 标准:
A conversion specification is executed in the following steps:
- Input white-space characters (as specified by theisspacefunction) are skipped, unless the specification includes a'[','c', or'n'specifier.
A转换规范在下面的步骤执行:
-输入的空白字符(由指定的isspace功能)被跳过,除非本说明书包括一个'[','c'或'n'说明符。
and, elsewhere, describing isspace():
并且,在其他地方,描述isspace():
The standard white-space characters are the following: space
' ', form feed'\f', new-line'\n', carriage return'\r', horizontal tab'\t', and vertical tab'\v'.
标准的空白字符如下:空格
' '、'\f'换页'\n'、换行、回车'\r'、水平制表符'\t'和垂直制表符'\v'。
Your best bet is to use fgetsto get the line (and this can be protected from buffer overflow very easily), then use sscanfon the resultant line.
最好的办法是使用fgets来获取行(这可以很容易地防止缓冲区溢出),然后sscanf在结果行上使用。
The scanffunction is one of those ones you should look at very warily. The following piece of code is one I often use to handle line input:
该scanf功能是您应该非常谨慎地查看的功能之一。下面这段代码是我经常用来处理行输入的代码:
#include <stdio.h>
#include <string.h>
#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] = '// 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;
}
';
return OK;
}
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]
Testing it with various combinations:
用各种组合测试它:
sscanf (buffer, "%f %f", &real, &img)
What I would do is to use this function to get a line safely, then simply use:
我要做的是使用这个函数来安全地获取一条线,然后简单地使用:
#include <stdio.h>
#include <string.h>
#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] = '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 == '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> _
') 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;
}
';
return OK;
}
to get the actual values (and check the count).
获取实际值(并检查计数)。
In fact, here's a complete program which is closer to what you want:
事实上,这是一个更接近您想要的完整程序:
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;
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;
}
along with a test run:
以及测试运行:
if (strlen(buff) <= 1) return NO_INPUT;
回答by Matthew Smith
Use fgets to read console input:
使用 fgets 读取控制台输入:
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
回答by Chris Dodd
There's a way to do what you want using just scanf:
有一种方法可以使用 scanf 来做你想做的事:
...
if (strlen(buff) <= 1) return NO_INPUT;
if (fgets (buff, sz, stdin) == NULL) return NO_INPUT;
....
If the user only enters 1 float on a line, it will read the next line for the second value. If any random garbage is entered, it will skip up to a newline and try again with the next line. Otherwise, it will just go on reading pairs of float values until the user enters a blank line or an EOF is reached.
如果用户只在一行中输入 1 个浮点数,它将读取下一行的第二个值。如果输入了任何随机垃圾,它将跳到换行符并在下一行重试。否则,它将继续读取浮点值对,直到用户输入空行或到达 EOF。
回答by Derlo
re PAXDIABLO solution: it does not work properly with EMPTY line entered by user, so this line shall be added in your getLine() function
重新 PAXDIABLO 解决方案:它不能与用户输入的 EMPTY 行正常工作,因此应在您的 getLine() 函数中添加此行
##代码##after the line:
行后:
##代码##So it will become :
所以它会变成:
##代码##
