【问题标题】:fgets prints out 'à' instead of an actual inputfgets 打印出 'à' 而不是实际输入
【发布时间】:2018-03-05 16:45:56
【问题描述】:

我正在尝试用 C 编写一个程序,以便它从用户那里获取只能是 'Q' 'q' 'N' 'n' '1' 或 '2' 的输入,其他一切都应该是无效的。我是 C 新手,因此我仍然无法弄清楚 fgets 应该如何工作。我作为输入输入的任何内容都以“à”的形式出现。

char C=' ';
int N=0;

int flag=1;
char buffer[20];
char input[20];
printMenu();
printf("\n\nPlease choose something: ");

fgets(buffer, sizeof(buffer), stdin);
sscanf(buffer, "$s",&input);
//checking the input, shows à instead of an actual input
printf("Input is %c\n", input);

if(*input=='C'||*input=='c')
                C=userInputChar();
        else
                if(*input=='N'||*input=='n')
                        N=userInputInt();
                else
                        if(*input=='1')
                                printTriangleLeft(C,N);
                        else
                                if(*input=='2')
                                        printTriangleRight(C,N);
                                else
                                        if(input[0]=='Q'||input[0]=='q'){
                                                printf("Exiting the program...");
                                                return 0;
                                        }
                                        else
                                                printf("Invalid input");

【问题讨论】:

  • 为什么嵌套的 if 语句中没有大括号...?
  • 也许是switch 声明
  • sscanf(buffer, "$s",&input); --> sscanf(buffer, "%s",input);(但这只会得到第一个单词)并且不要忘记验证转换if (sscanf(buffer, "%s",input) != 1) { /* handle error */ }
  • sscanf(buffer, "$s",&input);printf("Input is %c\n", input); --> sscanf(buffer, "%19s", input);printf("Input is %c\n", *input);
  • 我认为你不需要那些,除非你有超过 1 个声明

标签: c unix input user-input fgets


【解决方案1】:

继续我的评论,除了代码中的各种语法错误之外,您只是让自己变得比需要的更难。在这里,如果我正确理解您的问题,您希望输入并验证它是否仅由字符 "Qqn12" 组成。

要验证您的输入完全由"Qqn12" 组成,您需要遍历输入缓冲区中的每个字符并检查它是否是"Qqn12" 之一。如果不是,则输入无效。

在我们到达那里之前,让我们谈谈验证和删除包含在由fgets 填充的缓冲区中的'\n' 的正确方法(POSIX getline 还包括它缓冲区中的尾随'\n') .要删除尾随换行符,您可以使用strrchr 来定位它,或者您可以只使用strlen 来获取缓冲区的长度并检查buffer[len - 1] == '\n'。如果buffer[len - 1] 不等于'\n',那么您知道字符在stdin 中仍未读取(因为stdin 中的字符数等于或超过缓冲区大小)并且您需要处理该错误。例如,您可以使用以下内容:

    char buf[MAXC] = "";
    size_t len;

    printf ("enter string: ");  /* prompt, read and validate */
    if (!fgets (buf, MAXC, stdin)) {
        fprintf (stderr, "error: invalid input or user canceled.\n");
        return 1;
    }

    len = strlen (buf);                 /* get buf length */
    if (len && buf[len-1] == '\n')      /* check for '\n' */
        buf[--len] = 0;                 /* overwrite with '\0' */
    else {  /* input equals or exceeds buffer size, '\n' not read  */
        fprintf (stderr, "error: input exceed %d chars.\n", MAXC-2);
        return 1;
    }

(注意测试条件len && buf[len-1] == '\n',你必须在测试buf[len-1] == '\n'之前检查len > 0,或者Undefined Behavior通过尝试读取一个负数组索引。)

接下来,您希望将输入限制为仅选择的字符,因此创建一个包含您将接受的字符的 字符串文字,例如char *accept = "Qqn12";string.h 提供了 strchr 函数,该函数将定位并返回指向字符串 s 中给定字符 c 的第一次出现的指针。声明是:

char *strchr(const char *s, int c);

显然,在缓冲区中查找字符之一 "Qqn12" 是没有好处的,因为那里可能还有其他字符不是 "Qqn12"。但是,如果我们转过头来询问accept 中的每个字符是否在缓冲区中(例如"Qqn12" 中的一个)”,那么您就可以进行测试了您正在寻找——strchr 会为您扫描accept 中的每个字符。例如,您可以执行以下操作:

    ...
    char *accept = "Qqn12";
    ...
    for (char *p = buf; *p; p++)        /* for each char in buf */
        if (!strchr (accept, *p)) {     /* if not in 'accept', error */
            fprintf (stderr, "error: invalid input '%c'.\n", *p);
            return 1;
        }

如果您对 数组索引 比指针更满意,您可以简单地使用数组索引来遍历缓冲区中的每个字符,例如以下内容完全相同:

    for (int i = 0; buf[i]; i++)        /* for each char in buf */
        if (!strchr (accept, buf[i])) { /* if not in 'accept', error */
            fprintf (stderr, "error: invalid input '%c'.\n", buf[i]);
            return 1;
        }

(如果你愿意,你甚至可以使用i < len 而不是buf[i] 作为退出条件)

将所有部分放在一起,您可以验证由"Qqn12" 组成的条目是否输入如下:

#include <stdio.h>
#include <string.h>

#define MAXC 512

int main (void) {

    char buf[MAXC] = "",
        *accept = "Qqn12";
    size_t len;

    printf ("enter string: ");  /* prompt, read and validate */
    if (!fgets (buf, MAXC, stdin)) {
        fprintf (stderr, "error: invalid input or user canceled.\n");
        return 1;
    }

    len = strlen (buf);                 /* get buf length */
    if (len && buf[len-1] == '\n')      /* check for '\n' */
        buf[--len] = 0;                 /* overwrite with '\0' */
    else {  /* input equals or exceeds buffer size, '\n' not read  */
        fprintf (stderr, "error: input exceed %d chars.\n", MAXC-2);
        return 1;
    }

    for (char *p = buf; *p; p++)        /* for each char in buf */
        if (!strchr (accept, *p)) {     /* if not in 'accept', error */
            fprintf (stderr, "error: invalid input '%c'.\n", *p);
            return 1;
        }

    printf ("valid input : %s\n", buf);

    return 0;
}

使用/输出示例

$ ./bin/validinput
enter string: Qqn12n21Qq
valid input : Qqn12n21Qq

$ ./bin/validinput
enter string: Qqn12n21Qbq
error: invalid input 'b'.

查看一下,如果您有任何其他问题,请告诉我。

【讨论】:

    【解决方案2】:

    更改了以下内容: 字符缓冲区[20]; 字符输入[20];

    printf("\n\nPlease choose something: ");
    
    fgets(buffer, sizeof(buffer), stdin);
    sscanf(buffer, "$s",&input);
    
    printf("Input is %c\n", input);
    

    char buffer[20];
    char input;
    fgets(buffer, sizeof(buffer), stdin);
    sscanf(buffer, "%c",&input);
    printf("Input is %c\n", input);
    

    似乎至少对一个角色有效

    【讨论】:

      【解决方案3】:

      您不应该将数组指针传递给 sscanf。 数组本身就足够了, $s 也不正确。 '%s' 你应该用来获取字符串 正确如下:

      sscanf(缓冲区, "%s", 输入);

      【讨论】:

      • 改变了它,现在产生一个空白输出
      【解决方案4】:

      你没有检查sscanf的返回值,所以你不知道它是否成功解析了任何东西。

      您的sscanf 格式字符串是$s,它不会提取任何值。 &amp;input 参数被忽略。此外,没有scanf 格式可以接受char (*)[20] 类型的参数。

      printf %c 接受int。您将其传递给char *。这就是你得到垃圾输出的原因。

      *input=='C' 也不起作用,因为此时 *input 未初始化。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-02-09
        • 1970-01-01
        • 1970-01-01
        • 2014-04-27
        • 2014-08-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多