简体   繁体   中英

Using strtok in C++

I'm trying to read a file which has input(time and price) as: 12:23:31 67 12:31:23 78 [...] I created a struct which holds values of hour, minutes and seconds. I used strtok to tokenize the individual values and use atof to store them. However, I'm getting an error when I try to tokenize the time: cannot convert std::string' to 'char*' for argument 1 to 'char*'

struct time
{
    int hours;
    int minutes;
    int seconds;
    double price;
};

int main()
{
    string file, input;
    time* time_array;
    char* tok;

    cout << "Enter a file name to read input: ";
    cin >> file;

    ifstream file_name(file.c_str());

    file_name >> input;
    file_name >> input;

    //while(!file_name.eof())
    for(int i = 0; i < 4; i++)
    {
        time_array = new time;
        file_name >> input;
        tok = strtok(input, ":"); //ERROR HERE
        while(tok != NULL)
        {
            *time_array.hours = atof(tok[0]);
            *time_array.minutes = atof(tok[1]);
            *time_array.seconds = atof(tok[2]);
        }
        file_name >> input;
        *time_array.prine = atof(input);
    }
}

I would not use strtok for this job at all 1 . If you want to use C-like tools, then read the data with fscanf:

// note there here `file_name` needs to be a FILE * instead of an ifstream.
fscanf(file_name, "%f:%f:%f %f", &hours, &minutes, &seconds, &price);

Most people writing C++ would prefer something more typesafe though. One possibility would be to use essentially the same format string to read the data using Boost.format .

Another possibility would be to use stream extractors:

char ignore1, ignore2;
file >> hours >> ignore1 >> minutes >> ignore2 >> seconds >> price;

As to what this does/how it works: each extractor reads one item from the input stream. the extractors for float each read a number. The extractors for char each read one character. In this case, we expect to see: 99:99:99 99 , where 9 means "a digit". So, we read a number, a colon, a number, a colon, a number and another number (the extractor skips whitespace automatically). The two colons are read into char variables, and can either be ignored, or you can check that they really are colons to verify that the input data was in the correct format.

Here's a complete, compileable demo of that technique:

#include <iostream>


int main() {
    float hours, minutes, seconds, price;
    char ignore1, ignore2;

    std::cin >> hours >> ignore1 >> minutes >> ignore2 >> seconds >> price;

    std::cout << "H:" << hours 
              << " M:" << minutes 
              << " S:" << seconds 
              << " P:" << price << "\n";
    return 0;
}

There are certainly a lot more possibilities, but at least those are a few reasonable ones.


  1. To be honest, I'm not sure there's any job for which I'd use strtok , but there are some where I might be at least a little tempted, or wish strtok weren't so badly designed so I could use it. In this case, however, I don't even see much reason to use anything similar to strtok at all.

strtok doesn't take a string as its argument - it takes a char* . Like all functions in the cstring header it's a C function that works with C strings - not C++ strings - and should generally not be used in C++.

Use the methods of the string class instead.

The short answer is that you cannot directly use a std::string with strtok , as strtok wants a string it can modify. Even if you use c_str() to get a C-style string from a std::string , it is still read only.

If you really want to use strtok , you need to duplicate the string into a modifiable buffer, for example by:

char* str = strdup(input.c_str()) ;

If you do this, make sure you call free(str) at the end of the function, else you will get a memory leak!

Your simple case can easily be built using the string::find method. However, take a look at Boost.Tokenizer .

strtok will not work with std::string.c_str() because it returns const char* . strtok does not take a string as an argument, but rather a char* .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM