【问题标题】:Input switching in CC中的输入切换
【发布时间】:2023-04-02 15:22:01
【问题描述】:

我正在尝试用 C 创建一个基本的绘图程序,我需要先输入图形,然后输入所述图形的坐标。我必须先输入图形,然后输入坐标,但是为了输入要传递给函数的特定图像的特定坐标,我必须做一个条件语句。我的代码是这样的

fgets(input,sizeof(input),stdin);
      if("\n"==input[strlen(input)-1]) // to remove '\n' from string
          input[strlen(input)-1]=='\0';
      if(strcmp(input,point)==0){
         scanf("%d %d",&x1,&y1);
         point(x1,y1); 
      }
      if(strcmp(input,rectangle)==0){
         scanf("%d %d",&x1,&y1,&x2,&y2);
         rectangle(x1,y1,x2,y2) // x1,y1 for top left coordinate x2,y2 for bottom right
      }

如果我运行代码并输入:

point // enter
12 13

它可以工作,但我必须像这样运行它:

point 12 13 // only one space in between those three inputs

我似乎不能那样运行它。输入图像应与输入坐标在同一行。我尝试使用 scanf() 然后 if{ scanf() } 但它不起作用。

有什么建议吗?

【问题讨论】:

  • char figure[1024] = {0}; int x, y; scanf("%s%d%d", figure, &x, &y);
  • 我将此作为答案发布,但随后被删除,因为看起来您需要数字的值来指示输入的数量(坐标)。我相信不可能。

标签: c function if-statement input scanf


【解决方案1】:

你不能用 == 比较字符串,你必须使用

strcmp(char *string1,char*string2)

你可以这样做:

char input[20];
int resul[4];
scanf("%s%d%d",input,&resul[0],&resul[1]);
if (input[0]=='r') scanf("%d%d",&resul[2],&resul[3]);

【讨论】:

  • 我将其编辑为 strcmp 但我仍然无法弄清楚如何使用
    而不是
    '\n' 的格式输入
【解决方案2】:

分析的代码开头是:

fgets(input,sizeof(input),stdin);
if("\n"==input[strlen(input)-1]) // to remove '\n' from string
    input[strlen(input)-1]=='\0';

您应该检查来自fgets() 的返回值,以便您知道input 中是否有任何数据需要分析。

if 应该是 if (input[strlen(input)-1] == '\n'),测试字符 '\n' 而不是字符串 "\n"*。您应该已经收到有关类型不匹配的编译器警告。如果您没有收到此类警告,请使用更好的编译器。如果您收到警告,请注意您的编译器;它比你更了解 C(并且不会仅仅为了好玩而生成警告)。

if 之后的赋值需要一个单一的= 而不是一个双重的==——您可能应该收到关于什么都不做的语句的警告。

* 我知道有些人推荐订单if ('\n' == input[strlen(input)-1]),但对我来说并不那么好。该机制旨在防止 === 条件中的错误。它是不完美的——例如,当 LHS 和 RHS 都是变量时(if (lhs = rhs))它不能保护你——如果你有一个伪装成条件的赋值,一个体面的编译器会警告你(就像它会警告你一样关于伪装成作业的条件)。

代码应该这样开始,因此:

if (fgets(input, sizeof(input), stdin) != 0)
{
    if (input[strlen(input)-1] == '\n')
        input[strlen(input)-1] = '\0';

我忽略了重复调用strlen() 的“低效率”;还有更大的问题需要担心。注意修改后的代码检查输入操作的结果;如果fgets() 检测到 EOF 或错误并且您没有测试fgets() 的结果,您就会遇到麻烦。

代码的原始版本然后继续:

if(input == "point"){
   scanf("%d %d",&x1,&y1);
   point(x1,y1); 
}
if(input == "rectangle"){
   scanf("%d %d",&x1,&y1,&x2,&y2);
   rectangle(x1,y1,x2,y2) // x1,y1 for top left coordinate x2,y2 for bottom right
}

正如jambono 在他的answer 中正确指出的那样,这不起作用;你不能像那样比较字符串。

不幸的是,重写是:

if(strcmp(input,point)==0){
   scanf("%d %d",&x1,&y1);
   point(x1,y1); 
}
if(strcmp(input,rectangle)==0){
   scanf("%d %d",&x1,&y1,&x2,&y2);
   rectangle(x1,y1,x2,y2) // x1,y1 for top left coordinate x2,y2 for bottom right
}

这也应该从编译器生成警告,因为字符串已更改为函数指针 - 编译器应该抱怨将函数指针转换为 const char * 或类似的位置。

正确的比较可能是:

if (strcmp(input, "point") == 0)
if (strcmp(input, "rectangle") == 0)

只要单词单独出现在一行上,这些数据就可以工作:

point
1 2
rectangle
2 3 4 5

问题前的答案已格式化以提高可读性

当然,第二个scanf() 需要修复格式字符串,您应该始终测试scanf() 是否按预期工作:

if (scanf("%d %d %d %d", &x1, &y1, &x2, &y2) != 4)
    ...deal with error...

请注意,scanf() 调用将把换行符留在后面,准备好被另一个调用 fgets() 作为行上唯一的字符(剩下的)读取。我认为第二次调用 fgets() 读取包含数据的行,然后使用 sscanf() 解析该行可能会更好。

组装所有更改(使用scanf()):

if (fgets(input, sizeof(input), stdin) != 0)
{
    if (input[strlen(input)-1] == '\n')
        input[strlen(input)-1] = '\0';
    if (strcmp(input, "point") == 0)
    {
        if (scanf("%d %d",&x1,&y1) != 2)
            ...report format error and return/exit...
        point(x1, y1); 
    }
    else if (strcmp(input, "rectangle") == 0)
    {
        if (scanf("%d %d %d %d", &x1, &y1, &x2, &y2) != 4)
            ...report format error and return/exit...
        rectangle(x1, y1, x2, y2);
    }
    else
        ...unexpected input (format error)...
}

使用fgets()sscanf()

if (fgets(input, sizeof(input), stdin) != 0)
{
    if (input[strlen(input)-1] == '\n')
        input[strlen(input)-1] = '\0';
    if (strcmp(input, "point") == 0)
    {
        if (fgets(input, sizeof(input), stdin) == 0)
            ...report unexpected EOF and return/exit...
        if (sscanf(input, "%d %d",&x1,&y1) != 2)
            ...report format error and return/exit...
        point(x1, y1); 
    }
    else if (strcmp(input, "rectangle") == 0)
    {
        if (fgets(input, sizeof(input), stdin) == 0)
            ...report unexpected EOF and return/exit...
        if (sscanf(input, "%d %d %d %d", &x1, &y1, &x2, &y2) != 4)
            ...report format error and return/exit...
        rectangle(x1, y1, x2, y2);
    }
}

请注意,在使用fgets() 的示例中,您拥有可以报告给用户的整行输入,这对于他们来说可能比在scanf() 阅读了该行之后找到剩下的内容更容易,并且拒绝转换其余的。例如,如果输入是:

rectangle
10 10 2O 22

O 上的转换将失败(应该是 0),但您可以从输入中收集到的唯一信息以向用户报告是 O 22,这可能不是就像能够显示整行一样有用。

问题后的答案已格式化以提高可读性

输入是单行:

point 1 1
rectangle 1 0 0 1

在这种情况下,您不能使用scanf() 来获取数字(因为fgets() 已经阅读了整行),因此您将需要使用sscanf() 并且不需要再次调用@ 987654368@。但是,您必须修改比较代码以及对sscanf() 的调用。我会创建一个小函数来检查给定字符串是否是另一个字符串的前缀:

int str_prefix(const char *haystack, const char *needle)
{
    return strncmp(haystack, needle, strlen(needle)) == 0;
}

如果needle 可以在haystack 的开头找到,则返回true。如果您有 C99 或更高版本的编译器,则可以使用 static inline 对其进行限定(并且可以明智地将返回类型更改为 bool_Bool)。

if (fgets(input, sizeof(input), stdin) != 0)
{
    if (input[strlen(input)-1] == '\n')
        input[strlen(input)-1] = '\0';
    if (str_prefix(input, "point "))
    {
        if (sscanf(input, "point %d %d",&x1,&y1) != 2)
            ...report format error and return/exit...
        point(x1, y1); 
    }
    else if (str_prefix(input, "rectangle "))
    {
        if (sscanf(input, "rectangle %d %d %d %d", &x1, &y1, &x2, &y2) != 4)
            ...report format error and return/exit...
        rectangle(x1, y1, x2, y2);
    }
}

注意“needle”字符串的尾随空格。这可以防止您将“指出的评论”误解为“点”线的开始。

您可以在关键字之后开始 sscanf() 搜索,而不是使用关键字开始格式字符串:

if (sscanf(&input[sizeof("rectangle")], "%d %d %d %d", &x1, &y1, &x2, &y2) != 4)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-14
    • 2021-04-30
    相关资源
    最近更新 更多