阅读白色空间会导致Parser崩溃。为什么?

时间:2014-03-07 07:57:49

标签: c++ parsing debugging whitespace

我最终尝试编写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;
}

1 个答案:

答案 0 :(得分:1)

一些事情:

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

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