分词输入中的无限循环

Infinite Loop in Tokenizing Input

大家下午好,我正在为虚拟 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, " ");
}

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

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 的 return 值。

  • 也许您已经意识到这一点,但我还是要提一下 strtok,除此之外,它还更改了原始字符串。如果您需要更多详细信息,请查看 How does the strtok function in C work?.

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

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

...,如果标准输入中还有可用的字符,那么下一个字符要么是换行符,要么是回车符 return(当然,假设行为最终没有被定义由于超出 inStr 的范围)。与大多数 scanf 字段指令不同,%[ 不会跳过前导白色 space,因此如果此时您执行 ...

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

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

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