views:

104

answers:

2

I've created a program to get a string input from a user and parse it into tokens and move a robot according to the input. The program is supposed to recognize these inputs(where x is an integer): "forward x" "back x" "turn left x" "turn right x" and "stop". The program does what it's supposed to for all commands except for "stop". When I type "stop" the program prints out "whats happening?" because I've written a line which states:

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

Why does token get NULL, and how can I fix this so it will read "stop" properly?
here is the code:

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();
}

I need this to break out of the while loop and end manualDrive because in my driver program the next function called is autoDrive.
the autodrive.txt file looks like:

forward 2
turn right 30
back 3
turn left 50
stop

Also I left out an important limitation on my program I'm not allowed to use string from the standard library

A: 

Try running under a debugger and seeing what the value of uinput is when you get the error.

Also check the stack traceback at that point: when you get the error, is the input coming from manualDrive or autoDrive?

David Gelhar
+1  A: 

The line of code:

token=strtok(uinput, delim);

will set token to NULL if uinput is empty or consists only of characters in the delim string.

Changing the code around your NULL check a little might help you figure out what's going on:

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;
}

In any case, NULL is a normal return from strtok() and your code needs to be prepared to handle it.

Michael Burr
Just as a comment to your edit about not being allowed to use `std::string`: I wasn't suggesting using `std::string` as a fix, only as something you could put in the code to help see why you might be getting a `NULL` return from `strtok()`. How you might want to handle an empty (or all space) line from `cin` or `autodrive.txt` is up to you - you might want to simply return so you'll get another line or you might want to act as though a `stop` command had been issued. That's beside the point, which is that a `NULL` return from `strtok()` needs to be handled appropriately.
Michael Burr