【问题标题】:Why does program crash after exiting do-while loop asking for input in C?为什么程序在退出 do-while 循环后会在 C 中要求输入时崩溃?
【发布时间】:2015-03-03 20:32:07
【问题描述】:

如果一个输入比您想要的长,我无法正确使用 do-while 循环来继续询问另一个字符串。输入一个太大的字符串后,程序需要另一个,但在我输入一个可接受的字符串后,程序崩溃而不是正常退出,这是为什么呢?这只是更大程序的一部分代码。另外,我对 C 比较陌生。

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

#define STRING_MAX 100

int main()
{
    //Declaration of variables
    char  temp_input[STRING_MAX];

    //Read input
    do
    {
        scanf("%s", temp_input);
    }while(strlen(temp_input)>STRING_MAX);

    return 0;
}

感谢大家的帮助!!

【问题讨论】:

  • 你明白strlen()是做什么的吗?
  • 是的,它返回字符串输入的长度,不是吗? @iharob
  • 没错,那怎么可能是&gt;STRING_MAX
  • 哦是的.. 但是当我输入一个比这更长的字符串时它是如何循环的?
  • scanf 不在乎。很高兴将 150 个字符写入 100 个字符的缓冲区,之后程序所做的任何事情 纯属偶然。一旦你覆盖了记忆,你就没有权利期待任何特定的行为。

标签: c string input do-while string-length


【解决方案1】:

根据 cmets,我认为这就是您真正想要的

#include <stdio.h>

#define STRING_MAX 10

int main (void)
{
    char         string[STRING_MAX];
    unsigned int count;
    unsigned int total;
    int          chr;

    do {
        count = 0;
        total = 0;
        while (((chr = getchar()) != EOF) && (chr != '\n'))
        {
            if (count < STRING_MAX - 1)
                string[count++] = chr;
            total += 1;
        }
        string[count] = '\0';
    } while (total > STRING_MAX - 1);
    printf("The input string was:\n\t%s\n", string);
    return 0;
}

【讨论】:

  • 检查 chr 不是 EOF 的目的是什么?我也尝试了以下条件,它似乎工作得一样好。 while ((chr = getchar()) != '\n') 是否适用于我们从文件中读取字符串的情况?
  • 如果你在 Linux 上按 Ctrl+D 或在 Windows 上按 Ctrl+Z,输入流将被关闭,getchar() 将返回 EOF
  • 哦,好吧,不知道..所以它对代码的工作来说并不重要吗?
  • 它也没有伤害它,但是没有,只要您将chr 与实际上刷新字符的'\n' 进行比较,代码就会起作用。
  • 我刚刚注意到 chr 被声明为 int,不应该是 char 吗?它有效,但为什么? @iharob
【解决方案2】:

代码失败,因为 scanf("%s", temp_input); 无法防止过长的输入过度填充 temp_input 导致未定义的行为 (UB)

fgets() 替代:

char buf[STRING_MAX];
while (fgets(buf, sizeof buf, stdin) != NULL) {
  // if input does not end with \n, assume additional char for this line.
  if (strchr(buf, '\n') == NULL) {
    int ch;
    // Get extra char and throw away.
    while ((ch = fgetc(stdin)) != '\n' && ch != EOF)
      ; 
  }

  // do something with buf - get rid of potential trailing \n, then print
  buf[strcspn(buf, "\n")] = 0;
  puts(buf);  // this also prints a \n

  // now get next line
}

【讨论】:

  • “获取多余的字符并扔掉”部分是多余的,不是吗?如果有换行符,fgets() 总是读到换行符……
  • @顺磁羊角面包。 fgets() 因各种原因提前停止,包括一个完整的缓冲区 - 即使额外的读取会发现 '\n'
  • @TheParamagneticCroissant fgets() 读取它被告知要读取的最大字符数,并将更多字符留在缓冲区中。
【解决方案3】:

使用getchar() 从标准输入读取。它一次获取一个字符,因此如果字符串太长,您可以中断。也许你想像

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

#define STRING_MAX 100

int main()
{
    //Declaration of variables
    char  temp_input[STRING_MAX];
    int ch;  // char just read
    int ins; // insert point

    //Read input
    ins = 0; // start at begining
    for(;;)
    {
        ch = getchar();
        if( ch == 13 ) // return char
        {
            temp_input[ins] = 0; // null terminate string
            break;
        }
        temp_input[ins] = ch;
        ins++; // move up next insert point
        if( ins == STRING_MAX )
        {
            temp_input[STRING_MAX-1] = 0; // null terminate;
            break;  // at end of string
        }
    }

    return 0;
}

【讨论】:

  • @Andrew 为什么在代码应该使用'\n'(通常值为10)时使用13?此代码在ch == EOF 时也有问题。
  • 但这不允许其他输入,对吗?它只是在 99 处中断?
  • @Yiannis 很抱歉,但是如何在不溢出缓冲区的情况下获取输入与再次执行此操作无关,只需编写一个函数并按您希望的次数调用它。
  • @Yian 是你想继续阅读直到用户输入更少或精确到该数量的字符吗?
  • @iharob 是的,这就是我想要的 :)
【解决方案4】:

您正在导致缓冲区溢出,请勿将scanf 用于此目的。

【讨论】:

  • 有什么办法可以处理缓冲区溢出并仍然使用scanf?如果不是我应该使用什么?得到?获取字符?
  • @Yiannis 为了防止scanf() 的缓冲区溢出,您需要告诉scanf() 要读取多少个字符,例如在您的情况下scanf("%99s", temp_input)。但是您需要知道scanf() 将在带有"%s" 说明符的流中找到空格字符时停止读取,因此它可能不是您想要的。
  • 是的,但不允许其他输入.. 所以它不可能使用 scanf 吗?
  • @Yiannis 为什么不允许其他输入?你在尝试什么?
  • 如果我使用 scanf("%99s", temp_input) 那么 while 循环中的条件是什么?因为 scanf 只会读取 99 + 终止字符?
猜你喜欢
  • 1970-01-01
  • 2021-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-14
  • 2016-05-26
  • 1970-01-01
相关资源
最近更新 更多