【问题标题】:why do I have to press enter twice for each string I enter?为什么我必须为每个输入的字符串按两次 enter?
【发布时间】:2021-01-07 18:43:30
【问题描述】:

这是代码:

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(),我不得不按两次回车。 但如果我删除它,我有无限循环。 我可以以某种方式修复它吗?我注意到它并不总是这样做,但这是一个非常烦人的问题

【问题讨论】:

  • @user3121023 问题可能是我在调用函数后仍在使用'svuotaBuffer()'
  • 请将scanf("%[^\n]s", i) 更改为scanf(" %[^\n]", i),其中有两个更改:添加空间,删除s。并删除 kludge svuotaBuffer(); 这是添加空间的工作。
  • 你不能像那样构建你的 scanf 循环。如果你写do { if( scanf(...) == 1 ) break; } while(1);,你会运行一个无限循环的非常真实的可能性,在这个循环中,scanf 反复尝试处理相同的数据并且永远不会在输入流上取得任何进展。
  • @WeatherVane 添加的空间仅从空间中清除缓冲区 svoutaBuffer() 清除缓冲区中的任何内容,直到遇到 \n。它们并不完全相同。
  • @Davide 空格过滤缓冲区中的所有前导空格,无论有多少,无论是否有。这使得%[]%c 的行为类似于自动执行此操作的其他格式规范。我称它为kludge是有原因的。如果可能需要清除不需要的非空白内容,最好使用 fgets() 而不是 scanf() 并完成它。

标签: c string buffer


【解决方案1】:

问题来自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 应该返回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] == '\0';  // 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: ");
    }
}

【讨论】:

    【解决方案2】:

    这个:

            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);
        }
    
    
        ....
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-14
      • 2012-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多