获取scanf在读取换行符时退出?

时间:2010-09-16 01:16:12

标签: c 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退出?

5 个答案:

答案 0 :(得分:10)

使用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;

答案 1 :(得分:10)

您遇到的具体问题是scanf格式字符串%f将跳过空格(包括换行符),直到找到要扫描的实际字符为止。从c99标准:

  

转换规范按以下步骤执行:
   - 跳过输入空白字符(由isspace函数指定),除非规范包含'[''c''n'说明符。

和其他地方,描述isspace()

  

标准空格字符如下:空格' ',换页'\f',换行'\n',回车'\r',水平标签{{1 }和垂直标签'\t'

最好的办法是使用'\v'来获取该行(这可以很容易地防止缓冲区溢出),然后在结果行上使用fgets

sscanf函数是您应该非常谨慎地查看的函数之一。以下代码是我经常用来处理行输入的代码:

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] = '\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 <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] = '\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;
}

答案 2 :(得分:2)

有一种方法可以使用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。

答案 3 :(得分:0)

重新考虑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;
....

答案 4 :(得分:0)

代替

df.index = pd.to_datetime(df.index)

尝试

while(scanf("%f %f", &real, &img) == 2)