【问题标题】:Infinite Loop in Tokenizing Input标记化输入中的无限循环
【发布时间】:2021-07-09 20:18:43
【问题描述】:

大家下午好,我正在为一个虚拟 shell 程序在 C 中标记输入,我遇到了无限循环的问题。在我的示例代码中,workwithtokenstuff() 正在无限执行。我之前形成了类似的循环,我不确定为什么底部的 scanf 被跳过了。示例输入是“cd /dummydir”。我有另一个strtok() 调用将目录拆分为另一个字符数组。

char inStr[255];
char *token;

scanf("%[^\n\r]", inStr);
token = strtok(inStr, " ");
while (strcmp(token, "exitcom") != 0) {
    workwithtokenstuff();

    scanf("%[^\n\r]", inStr);
    token = strtok(inStr, " ");
}

【问题讨论】:

  • workwithtokenstuff() 在做什么?知道这一点可能很重要。
  • scanf(" %[^\n\r]", inStr);(注意' ''[' 之前) 为什么? "%[..]" 不会丢弃前导空格。您应该验证每个输入,例如if (scanf(" %[^\n\r]", inStr) != 1) { /* handle EOF */ }

标签: c scanf infinite-loop strtok strcmp


【解决方案1】:

第二个scanf 并没有真正跳过,它捕获了前一个scanf 在输入缓冲区中留下的换行符,说明符之前的一个空格是通常的修复,它消耗缓冲区中存在的空白字符。

char inStr[255];
char *token;

scanf("%254[^\n\r]", inStr);  // note the width limit, avoids buffer overflow

token = strtok(inStr, " ");
while (strcmp(token, "exitcom") != 0)
{
    workwithtokenstuff(); // assuming this does not consume any more tokens
    scanf(" %254[^\n\r]", inStr);
    //     ^ space here
    token = strtok(inStr, " ");
}

脚注:

  • 对于更健壮的代码,建议检查scanf 的返回值。

  • 也许您知道这一点,但我会提到strtok 会更改原始字符串。如果您需要更多详细信息,请查看How does the strtok function in C work?

【讨论】:

  • 我确实在worksithtokensandstuff() 中使用了额外的令牌。我不知道换行符会被第二个scanf 捕获。根据同行的建议,我最终实施了fgets() 而不是scanf,但我尝试了你的答案,它也实现了我所追求的。非常感谢您的宝贵时间!
  • @user2337438 很乐意提供帮助,我同意fgets 更好,只要输入小于目标缓冲区,它就会消耗\n,唯一需要注意的是它会存在在目标缓冲区中,但如果需要,它可以很容易地删除。
【解决方案2】:

尽管您对读取的数据做了什么,如果您在两个 scanf 调用之间没有消耗来自标准输入的任何数据,那么是的,预计第二个不会消耗或转换任何额外的输入。那是因为在第一...

scanf("%[^\n\r]", inStr);

...,如果标准输入中还有更多可用的字符,那么下一个是换行符或回车符(当然,假设行为不会因为超出界限而最终未定义) inStr)。与大多数 scanf 字段指令不同,%[ 不会跳过前导空格,因此如果此时您执行...

scanf("%[^\n\r]", inStr);

... 再次遇到的第一个字符(如果有)是相同的回车符或换行符,它(再次)从扫描集中排除。因此,scanf 调用在不消耗或转换任何字符的情况下终止。它将返回 0 或 EOF,具体取决于实际上是否有任何字符可供读取。

抛开缓冲区溢出的严重风险不谈,您需要在两次scanf 调用之间至少消耗一个字符,以使第二次和后续调用有机会读取任何内容,或者在其中插入前导空格字符您的scanf 格式以跳过%[ 不会自动执行的前导空格。此外,您需要检查每个 scanf 调用的返回值,以确定它是否成功转换了任何数据,以及通过后续调用尝试消耗更多是否有任何意义。

【讨论】:

    猜你喜欢
    • 2012-10-18
    • 2012-09-27
    • 2021-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多