Почему мой токен возвращает NULL и как это исправить? (С++)

Я создал программу, которая получает ввод строки от пользователя, анализирует ее на токены и перемещает робота в соответствии с вводом. Предполагается, что программа распознает следующие входные данные (где x — целое число): «вперед x», «назад x», «повернуть налево x», «повернуть направо x» и «стоп». Программа делает то, что должна делать со всеми командами, кроме "стоп". Когда я набираю «стоп», программа выводит «что происходит?» потому что я написал строку, в которой говорится:

if(token == NULL)
{
    cout << "whats happening?" << endl;
}  

Почему токен получает значение NULL и как это исправить, чтобы он правильно читал "стоп"?
вот код:

bool stopper = 0;
void Navigator::manualDrive()
{
    VideoStream video(&myRobot, 0);//allows user to see what robot sees
    video.startStream();
    const int bufSize = 42;
    char uinput[bufSize];
    char delim[] = " ";
    char *token;

    while(stopper == 0)
    {
    cout << "Enter your directions below: " << endl;
    cin.getline(uinput,bufSize);
    Navigator::parseInstruction(uinput);
    }
}
/* parseInstruction(char *c) -- parses cstring instructions received
 * and moves robot accordingly
 */


void Navigator::parseInstruction(char * uinput)
{

    char delim[] = " ";
    char *token;


//  cout << "Enter your directions below: " << endl; 
//  cin.getline (uinput, bufSize);

    token=strtok(uinput, delim);
    if(token == NULL)
    {
        cout << "whats happening?" << endl;
    }
    if(strcmp("forward", token) == 0)
    {
        int inches;
        token = strtok(NULL, delim);
        inches = atoi (token);
        double value = fabs(0.0735 * fabs(inches) - 0.0550);
        myRobot.forward(1, value);
    }
    else if(strcmp("back",token) == 0)
    {
        int inches;
        token = strtok(NULL, delim);
        inches = atoi (token);
        double value = fabs(0.0735 * fabs(inches) - 0.0550);
        myRobot.backward(1/*speed*/, value/*time*/);
    }
    else if(strcmp("turn",token) == 0)
    {
        int degrees;
        token = strtok(NULL, delim);
        if(strcmp("left",token) == 0)
        {
            token = strtok(uinput, delim);
            degrees = atoi (token);
            double value = fabs(0.00467 * degrees - 0.04);
            myRobot.turnLeft(1/*speed*/, value/*time*/);
        }


        else if(strcmp("right",token) == 0)
        {
            token = strtok(uinput, delim);
            degrees = atoi (token);
            double value = fabs(0.00467 * degrees - 0.04);
            myRobot.turnRight(1/*speed*/, value/*time*/);
        }
    }
    else if(strcmp("stop",token) == 0)
    {
        stopper = 1;
    }
    else
    {
        std::cerr << "Unknown command '" << token << "'\n";
    }
}
/* autoDrive() -- reads in file from ifstream, parses
 * and moves robot according to instructions in file
 */
void Navigator::autoDrive(string filename)
{
    const int bufSize = 42;
    char fLine[bufSize];
    ifstream infile;
    infile.open("autodrive.txt", fstream::in);

    while (!infile.eof())
    {
        infile.getline(fLine, bufSize);
        Navigator::parseInstruction(fLine);
    }

    infile.close();
}

Мне нужно это, чтобы вырваться из цикла while и завершить manualDrive, потому что в моей программе драйвера следующая вызываемая функция — autoDrive.
Файл autodrive.txt выглядит так:

вперед 2
повернуть направо 30
назад 3
повернуть налево 50
стоп

Кроме того, я упустил важное ограничение в своей программе: мне не разрешено использовать строку из стандартной библиотеки


person Van    schedule 14.04.2010    source источник
comment
опубликуйте образец того, что в autodrive.txt дает плохое поведение   -  person Gordon Gustafson    schedule 14.04.2010
comment
Я предполагаю, что программа segfaults сразу после печати, что происходит? потому что он передает NULL в strcmp? Если нет, поищите какую-нибудь строку где-нибудь в программе, которая также печатает то, что происходит?. Возможно ли, что он переходит в режим автодрайва и где-то в файле есть пустая строка?   -  person Ben Voigt    schedule 14.04.2010
comment
Извините за неточность. Нет, в автодрайв не заходит. Он печатает, что происходит? zsh: ошибка сегментации (сброс ядра) ./driver Я запустил autoDrive отдельно, и я получаю ошибку сегментации в последней строке текста, которая читается как стоп. Я собираюсь отредактировать свой пост с примером того, как выглядит текстовый файл.   -  person Van    schedule 14.04.2010
comment
Я не могу воспроизвести ошибку с кодом, который вы дали. Мое предложение состоит в том, чтобы написать минимальную программу, которая использует эту ошибку, чтобы другие люди могли проверить, что на самом деле является дефектом (что означает модуль компиляции, который проходит компилятор без какой-либо внешней зависимости). Также иногда по пути создания такой программы сама ошибка выскакивает очень явно.   -  person Rudi    schedule 14.04.2010
comment
Я не думаю, что есть какая-то загадка в том, что происходит — входные данные для strtok() — это пустая строка или строка пробелов.   -  person Michael Burr    schedule 14.04.2010


Ответы (2)


Строка кода:

token=strtok(uinput, delim);

установит token в NULL, если uinput пусто или состоит только из символов в строке delim.

Небольшое изменение кода вокруг проверки NULL может помочь вам понять, что происходит:

std::string original_uinput( uinput);  // save input string for debugging

token=strtok(uinput, delim);
if(token == NULL)
{
    cout << "whats happening? uinput was: " << original_uinput << endl;
}

В любом случае NULL — это нормальный возврат из strtok(), и ваш код должен быть готов к его обработке.

person Michael Burr    schedule 14.04.2010
comment
Так же, как комментарий к вашему редактированию о том, что вам не разрешено использовать std::string: я не предлагал использовать std::string в качестве исправления, только как что-то, что вы могли бы добавить в код, чтобы понять, почему вы можете получить возврат NULL от strtok(). Как вы можете обрабатывать пустую (или все пространство) строку из cin или autodrive.txt зависит от вас - вы можете просто вернуться, чтобы получить другую строку, или вы можете действовать так, как если бы была введена команда stop . Дело не в этом, а именно в том, что NULL возврат из strtok() должен обрабатываться соответствующим образом. - person Michael Burr; 14.04.2010

Попробуйте запустить под отладчиком и посмотрите, какое значение имеет uinput, когда вы получаете сообщение об ошибке.

Также проверьте трассировку стека в этот момент: когда вы получаете сообщение об ошибке, поступает ли ввод из manualDrive или autoDrive?

person David Gelhar    schedule 14.04.2010