问题
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);
}
}
回答1:
I would not use strtok for this job at all1. 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.
- 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 wishstrtokweren't so badly designed so I could use it. In this case, however, I don't even see much reason to use anything similar tostrtokat all.
回答2:
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.
回答3:
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!
回答4:
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*.
来源:https://stackoverflow.com/questions/13746863/using-strtok-in-c