读取空格会使解析器崩溃.为什么?

Reading white spaces crashes Parser. Why?

本文关键字:崩溃 为什么 空格 读取      更新时间:2023-10-16

我最终要尝试编写一个shell,所以我需要能够解析命令。我正在尝试将每个单词和特殊符号转换为标记,同时忽略空格。当分隔标记的字符是 |<>但是,一旦我使用单个空格字符,程序就会崩溃。为什么?

我是一名学生,我意识到我想出的分离令牌的方式相当粗糙。我道歉。

#include <iostream>
#include <stdio.h>
#include <string>
#include <cctype>
using namespace std;
#define MAX_TOKENS 10
int main()
{
//input command for shell
string str;
string tokens[MAX_TOKENS] = { "0", "0", "0", "0", "0", "0", "0", "0", "0", "0" };
int token_index = 0;
int start_token = 0;
cout << "Welcome to the Shell: Please enter valid command: " << endl << endl;
cin >> str;

for (unsigned int index = 0; index < str.length(); index++)
{
//if were at end of the string, store the last token
if (index == (str.length() - 1)) tokens[token_index++] = str.substr(start_token, index - start_token + 1);
//if char is a whitespace store the token
else if (isspace(str.at(index)) && (index - start_token > 0))
{
tokens[token_index++] = str.substr(start_token, index - start_token);
start_token = index + 1;
}
//if next char is a special char - store the existing token, and save the special char
else if (str[index] == '|' || str[index] == '<' || str[index] == '>' || str[index] == '&')
{
//stores the token before our special character
if ((index - start_token != 0)) //this if stops special character from storing twice
{
//stores word before Special character
tokens[token_index++] = str.substr(start_token, index - start_token);
}
//stores the current special character
tokens[token_index++] = str[index];
if (isspace(str.at(index + 1))) start_token = index + 2;
else start_token = index + 1;
}
}
cout << endl << "Your tokens are: " << endl;
for (int i = 0; i < token_index; i++)
{
cout << i << " = " << tokens[i] << endl;
}

return 0;
}

几件事:

  • 检查token_index是否小于MAX_TOKENS,然后在每次增量后再次使用它,否则会出现缓冲区溢出。如果将tokens更改为std::vector则可以使用at()语法作为安全网。
  • 表达式index - start_token的类型为unsigned int,因此它永远不会小于0。相反,你应该把index > start_token作为你的测试。
  • 如果超出范围indexstr.at(index)会引发异常。但是,您永远不会发现异常;根据您的编译器,这可能看起来像程序崩溃。将main()的代码包装在try...catch(std::exception &)块中。

最后,这是一个很长的镜头,但为了完整起见,我会提到它。最初在C89中,isspace和其他is函数必须采用非否定参数。它们的设计使编译器可以通过数组查找来实现它们,因此传入具有负值的带符号字符会导致未定义的行为。 我不完全确定这是否在各种更高版本的 C 和 C++ 中被"修复",但即使标准要求这样做,也可能有一个编译器仍然不喜欢接收负字符。 若要从代码中消除这种情况,请使用isspace( (unsigned char)str.at(index) ),甚至更好的是,使用 C++ 语言环境接口。