无法理解strtok()

时间:2018-09-23 19:12:23

标签: c++

代码如下:

#include <string>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <vector>

using namespace std;

const string PROMPT = "prompt> ";
const char PIPE_DEL[3] = "||";

bool checkInput(char []);


bool checkInput(char cmd[]){
    string command = cmd;
    transform(command.begin(), command.end(), command.begin(), ::tolower);
    if (command == "q" || command == "quit")
        return true;
    else
        return false;   
}




int main(){
    int iteration = 0;
    while (true){
        char command[1024];
        pid_t pid;

        cout << '\n' << iteration << '\n';
        cout << PROMPT;
        cin >> command;

        if ( checkInput(command) )
            break;

        char* token = strtok(command, PIPE_DEL);
        vector<string> commands;
        commands.push_back(token);


        cout << "command 1: " << commands[0] << "\n";
        iteration ++;

    }
    return 0;
}

1)“”被视为定界符! 如果我错了,请纠正我,但唯一被视为定界符的是第二个参数中字符串中的内容。此处不是这种情况,因为我的定界符字符串中没有“”,但实际上是这样。

2)为什么执行命令全都乱七八糟? 如果有两个标记,程序将跳过一些代码。

以下是一些输出:

  

提示>你好
  命令1:你好

     

1

这是预期的。没有与分隔符匹配的字符,然后打印出整个字符串。

  

提示>你好,世界

     

命令1:您好

     

1

     

提示>命令1:世界

     

2

这完全是意外的。首先,“”不是分隔符。第二,为什么会跳过cin?为什么打印出第一个分隔符的cout语句在cin之前运行?为什么输入第二个令牌?例如运行以下命令:

  

提示>你好退出

     

命令1:您好

     

1

终止程序(如果cin读取“ q”或“ quit”,则程序终止)。这有点证明cin被忽略了,或者至少没有按我期望的那样工作。 cin应该停止,从控制台读取并将其放入array命令。但是,命令保留了“ quit”,这是预期的,因为strtok()修改了输入字符串,但是应该使用它覆盖。

  

char命令[1024];

3)最后输出

  

提示>您好||世界

     

命令1:您好

     

1

     

提示>在抛出

的实例后终止调用      

'std :: logic_error'what():basic_string :: _ M_construct为null

     

有效中止

再次“”不是定界符。令牌1应该是“ hello”,令牌2(如果我决定解析它)应该是“世界”。该错误不应该存在。

2 个答案:

答案 0 :(得分:2)

有几个问题。

首先,提取器cin>>command;将在收到的第一个空格处停止。如果您想获得完整的路线,则需要执行以下操作:

    cin.getline(command,1024);

然后,如果没有更多输入或出现错误,您可能仍然会遇到问题,因为即使没有收到任何输入,您也将始终执行以下操作。最好的方法是重写循环逻辑,以便循环:

    while (cin.getline(command,1024)) { 
    ...
    }

然后strtok()不能按预期使用多个字符。实际上,它期望使用不同的定界符,每个定界符都可以使令牌结尾。但是,输入中令牌的结尾将仅是列表之一。

最后,您只将第一个令牌推入commands向量中。

备注:使用strtok()并不是最好的主意。更好的选择是在整个代码中使用字符串,并使用算法来查找分隔符,例如like this

答案 1 :(得分:1)

多亏了我的回答,我才得以解决我遇到的问题。这是我所做的:

const string PROMPT = "prompt> ";
const string PIPE_DEL = "||";

bool checkInput(string);


bool checkInput(string command){
    transform(command.begin(), command.end(), command.begin(), ::tolower);
    if (command == "q" || command == "quit")
        return true;
    else
        return false;   
}


vector<string> getCommands(string command){
    vector<string> commands;

    size_t tokenStart = 0, tokenEnd;
    while ( (tokenEnd = command.find(PIPE_DEL, tokenStart)) != string::npos ){
        commands.push_back(command.substr(tokenStart, tokenEnd - tokenStart));
        tokenStart = tokenEnd + PIPE_DEL.length();
    }
    commands.push_back(command.substr(tokenStart, command.length()));

    return commands;
}




int main(){
    int iteration = 0;
    while (true){
        string command;
        pid_t pid;

        cout << '\n' << iteration << endl;
        cout << PROMPT;
        getline(cin, command);

        if ( checkInput(command) )
            break;

        vector<string> commands = getCommands(command);

        iteration ++;

    }
    return 0;
}

与以前一样,我严格使用字符串对象。我还使用字符串类中的find函数来解析定界符,而不是strtok()。最后,cin无法正确解析空间。我将其替换为:

getline(cin, command);

不过,正如@Christophe指出的那样,您也可以使用:

cin.getline(command,1024);

在这种情况下,命令是一个字符数组,而1024是要读取的字符数。