为什么我必须为输入的每个字符串按两次回车键?

why do I have to press enter twice for each string I enter?

这是代码:

void inserisciStringa(int dim, char *i) {
    int men = 1;
    do {
        if (scanf("%[^\n]s", i) == 1) {
            svuotaBuffer();               // I think this is the problem
            int len = checkStrLen(men, dim, i);
            int num = checkNumbers(len, i);
            if (len && num)
                break;
        }
        printf("\nError");
        printf("\nTry again: ");
    } while (1);
}

int checkStrLen(int min, int max, char *s) {
    int len = strlen(s);
    if (len >= min && len <= max)
        return len;
    else
        return 0;
}

int checkNumbers(int len, char *s) {
    int i;
    for (i = 0; i < len; i++) {
        if (s[i] >= '0' && s[i] <= '9') {
            printf("\nNot Numbers");
            return 0;
        }
    }
}

void svuotaBuffer() {
    char c;
    do {
        c = getchar();
    } while(c != '\n');
}

每次我必须插入一个字符串时,由于svuotaBuffer(),我不得不按两次回车键。 但是如果我删除它,我就会有无限循环。 我能以某种方式修复它吗?我注意到它并不总是这样做,但这是一个非常烦人的问题

这个:

        int men=1;
        do {
            if (scanf("%[^\n]s", i) == 1) {
                svuotaBuffer();                        //I think this is the problem
                int len = checkStrLen(men, dim, i);
                int num = checkNumbers(len,i);
                if (len && num) break;
            }
            printf("\nError");
            printf("\nTry again: ");
        } while(1);

可以用更简单的方式实现,例如,允许您消除 svuotaBuffer,等等。其他:

   ....
    char line[80] = {0};
    int num = 0, len = 0;

    fgets(line, sizeof(line), stdin);
    while(line[0] != '\n'))
    {
        line[strcspn(line, "\n")] = 0;//eliminate newline
        len = strlen(line);//check line length
        num = checkNumbers(len,i); 
        //do other things, i.e. parse and/or store line in output file, ...?
        fgets(line, sizeof(line), stdin);
    }


    ....

问题来自scanf(),一个非常棘手的函数:

  • 首先格式字符串 "%[^\n]s" 不正确,它应该只是 "%[^\n]" 因为尾随 s%s 不同,这意味着匹配一个 s 在输入流中,这不会在那里发生,因为上一次转换后唯一的未决字符是 \n 或文件结尾。
  • 您的转换是有风险的,因为您无法告诉 scanf() 要将多少字符存储到目标数组中。任何足够长的输入行都会导致未定义的行为。
  • 转换成功后,换行符将保留在输入流中。在尝试使用 scanf() 读取下一行之前,必须读取此换行符。否则 scanf() 将失败,因为 %[^\n] 无法转换空字符串。
  • 在转换失败后,即第二次发生的情况,还必须调用 svuotaBuffer() 以删除挂起的换行符。

还要注意这些问题:

  • svuotaBuffer() 也有一个问题:c 应该有类型 int 并且你必须检查 EOF 以避免最后的无限循环的文件。这是更正后的版本:

    int svuotaBuffer(void) {
       int c;
       while ((c = getchar()) != EOF && c != '\n')
           continue;
       return c;    // allow the caller to test for end-of-file.
    }
    
  • 如果循环完成,函数 checkNumbers 应该 return 1

  • 给一个 char * i.

    命名 非常混乱

这是修改后的版本:

int checkStrLen(int min, int max, char *s) {
    int len = strlen(s);
    if (len >= min && len <= max)
        return len;
    else
        return 0;
}

int checkNumbers(int len, char *s) {
    int i;
    for (i = 0; i < len; i++) {
        if (s[i] >= '0' && s[i] <= '9') {
            printf("\nNot Numbers");
            return 0;
        }
    }
    return 1;
}

int svuotaBuffer(void) {
   int c;
   while ((c = getchar()) != EOF && c != '\n')
       continue;
   return c;    // allow the caller to test for end-of-file.
}

int inserisciStringa(int dim, char *dest) {
    int men = 1;
    for (;;) {
        if (scanf("%[^\n]", dest) == 1) {
            svuotaBuffer();  // read the ending newline if any
            if (checkStrLen(men, dim, dest) && checkNumbers(len, dest))
                return 0;
        }
        if (svuotaBuffer() == EOF) {
            printf("\nUnexpected end of file\n");
            return -1;  // report failure to the caller.
        }
        printf("\nError");
        printf("\nTry again: ");
    }
}

你真的应该使用 fgets() 来完成这个任务。这是修改后的版本:

int inserisciStringa(int dim, char *dest) {
    int men = 1;
    int len;
    for (;;) {
        if (!fgets(dest, dim, stdin)) {
            printf("\nUnexpected end of file\n");
            return -1;  // report end of file failure to the caller.
        }
        len = strlen(dest);
        if (len > 0 && dest[len - 1] == '\n')
            dest[--len] == '[=12=]';  // strip the trailing newline
        if (len < men) {
            printf("\nError: line too short");
        } else
        if (len < dim - 1) {
            if (checkNumbers(len, dest))
                return 0;
            printf("\nError: string has digits");
        } else {
            printf("\nError: line too long");
            svuotaBuffer();
        }
        printf("\nTry again: ");
    }
}