【问题标题】:C programming: print only int from fgetsC 编程:仅从 fgets 打印 int
【发布时间】:2018-05-07 04:16:13
【问题描述】:

看到这个main

int main(void)
{
    int i;
    int ch;
    char str[512];
    fgets(str, sizeof str, stdin);

    for (i = 0; i <= (strlen(str)); i++)
    {
        if (str[i] != '\0' && str[i] != '\n')
        {
            int num = atoi(&str[i]);
            printf("%d\n", num);
        }
    }

    return 0;
}

我想从用户那里获取数字并获取所有没有任何spacestabs 的数字。

例如:

输入1 2 3。 但在这种情况下,这是输出:

1
2
2
3
3

那么为什么我收到了两次23

【问题讨论】:

  • 你如何开发你的代码?你只是在记事本中编辑它吗?为自己准备一个 IDE,例如 Eclipse CDT、NetBeans、MS Visual Studio 等。了解如何设置断点、逐行执行代码、检查变量。你刚刚被教导how to fish :-)
  • 您有一个for 循环,出于任何逻辑原因,它尝试处理输入中的每个字符并为其输出一些数字。很明显,对于“1 2 3”,将打印五个数字,因为该字符串中有五个字符不是 nul 或换行符。
  • @Mawg 钓到你不需要拖网渔船:在许多情况下,一根钓鱼竿就足够了(在这个类比中,一个简单的调试器而不是 IDE)。
  • 很好,但可视化调试器更简单。而是显示 GDB 的 IDE,只是从命令行运行 GDB
  • 你想得到没有空格或制表符的数字,但你没有检查空格或制表符。

标签: c string loops spaces atoi


【解决方案1】:

我会这样做:

char line[256];
if (fgets(line, sizeof line, stdin) != NULL)
{
    const char *ptr = line;
    while (*ptr != '\0')
    {
        char *eptr = NULL;
        const long value = strtol(ptr, &eptr, 10);
        if (eptr != ptr)
            printf("%ld\n", value);
        else
            break;
        ptr = eptr;
    }
}

这使用strtol(),所以它也可以处理负数;如果这是不正确的,您当然可以添加检查以将其过滤掉。我认为这比使用strtok() 的任何方法都要好。

【讨论】:

  • 或许提一下,atoi()除了不告诉你在哪里停止解析之外,还会在溢出的情况下触发UB……strto*()这里绝对是正确的选择。
【解决方案2】:

因为您还传递了以空格开头的字符串的位置。他们得到的第一个数字分别是 23 两次。这就是返回的内容。

for (i = 0; i <= (strlen(str)); i++)
{
    if (str[i] != '\0' && !isspace(str[i]) )
    {
        int num = atoi(&str[i]);
        printf("%d\n", num);
    }
}

打印:

1
2
3

为了标记化,您可以使用strtok 并将其转换为数字strtol 等。与atol/atoi 相比,这些可以更好地控制错误情况。

【讨论】:

  • 在这种情况下这是可行的,但如果我的输入是 12,则输出是 12 和 2
  • @user2908206.: 老实说,使用strtok...这与您期望的车辆相吻合。这里还指向121 一次又一次在2 中。
  • 没有 strtok 有没有机会修复它?
【解决方案3】:

当它到达输入中的空格字符时,它将调用 atoi()" 2 3"(导致 2),然后再调用 " 3"(导致 3),这会产生意想不到的数字。

【讨论】:

    【解决方案4】:

    来自atoi()ref

    该函数首先根据需要丢弃尽可能多的空白字符(如在 isspace 中),直到找到第一个非空白字符。 [...]

    这意味着如果您将“2”作为该函数的输入,它将返回 2。


    改变这个:

    if (str[i] != '\0' && str[i] != '\n')
    

    到这里:

    if (str[i] != ' ' && str[i] != '\0' && str[i] != '\n')
    

    你会得到:

    1
    2
    3
    

    以下是有关调试此代码的提示:在您的输出中,您得到了 2 和 3 两次,但不是 1。

    换句话说,您会得到两次空格之后的数字。 1 前面没有空格。

    这会让你觉得那里的空间有些诡异。

    确实,您将输入 if 语句的主体,即使 str[i] 是一个空格!

    通过添加条件来检查当前字符是否不是空格,进入 if 语句的 boby,实际上是跳过了空格。

    【讨论】:

    • 这不是将多位数字也变成多位数字吗? (如12 -> 12 和 2)
    • 是的@ilkkachu! ;)
    【解决方案5】:

    始终考虑错误处理是个好主意。如果用户错误地按空格和制表符怎么办。所以首先删除空格和制表符(如果存在):

    char *c = string;
    while ((*c == ' ') || (*c == '\t'))
        ++c;
    

    然后使用atoi()

    【讨论】:

      【解决方案6】:

      strtok 的解决方案也不是那么难:

      #include <stdio.h>
      #include <string.h>
      #include <stdlib.h>
      
      int main(void)
      {
          char s[128];
          fgets(s, sizeof s, stdin);
          const char *delim = " \t\n";
      
          char *p = strtok(s, delim);
          while(p) {
              int val = strtol(p, NULL, 10);
              printf("%d\n", val);
              p = strtok(NULL, delim);
          }
          return 0;
      }
      

      虽然请记住,它使用隐藏状态有点不确定(对多线程程序不利),当然它会修改输入字符串,所以它不能是常数(但你为什么要这样做那个)。

      【讨论】:

        【解决方案7】:

        您可以使用ctype.h 中提供的isdigitisalpha() 功能(根据您的使用情况)。以下是使用isdigit函数的代码sn-p:

        for (i = 0; i <= (strlen(str)); i++)
        {
            if (isdigit(str[i]))
            {
                int num = atoi(&str[i]);
                if(i && str[i-1]=='-') num *= -1;
                printf("%d\n", num);
                i += ( num==0 ) ? 1 : (int)log10(abs(num))+1;
            }
        }
        

        看到它在工作here
        检查here 例如isdigitisalpha() 函数。

        关于你的问题:

        那么为什么我两次收到 2 和 3?

        请参阅cplusplus.com 提供的以下说明,其中解释了atoi() 功能。

        该函数首先根据需要丢弃尽可能多的空白字符(如在 isspace 中),直到找到第一个非空白字符。然后,从这个字符开始,采用可选的初始加号或减号,后跟尽可能多的 base-10 数字,并将它们解释为数值。

        【讨论】:

        • 是的,但如果我的输入是 12,输出是 12,另一个是 2,我尝试了解如何解决它
        • while(num) 在做什么?
        • 在我看来,这真的很复杂而且过于复杂。
        • 无限循环,以防我的输入中有 0
        • 更新了代码 sn-p 以解决逻辑错误。希望它现在可以正常工作。
        猜你喜欢
        • 1970-01-01
        • 2012-03-15
        • 2015-06-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多