由于您使用的是 C++ STL 容器 ( vector
),因此您确实应该使用 C++ I/O ( iostream
) 而不是 CI/O ( stdio
)。它更安全、更灵活,并且最终可以为您节省一些胃灼热。
这是一个 quick-n-dirty 示例,展示了如何将该数据读入向量:
#include <iostream>
#include <iomanip>
#include <vector>
#include <iterator>
#include <sstream>
#include <string>
/**
* Create a struct type to represent each record,
* with one char member (which I'm calling "gender"
* based on the 'M' and 'F', but that's just a guess),
* 7 doubles (which I've gathered into a fixed-size
* array), and one integer.
*
* I've also overloaded the stream << and >> operators
* to read and write the struct as a single entity.
*/
struct record {
char gender;
double dvar[7];
int ivar;
record() { }
virtual ~record() { }
std::ostream& operator<<(std::ostream& s)
{
s << gender << " ";
for (int i = 0; i < 7; i++)
s << std::fixed << std::setw(8) << std::setprecision(4) << dvar[i] << " ";
s << std::setw(3) << ivar;
return s;
}
std::istream& operator>>(std::istream& s)
{
char delim;
s >> gender >> delim;
for (int i = 0; i < 7; i++)
s >> dvar[i] >> delim;
s >> ivar;
return s;
}
};
/**
* Overload the << and >> operators outside of the struct
* definition; this is necessary for the istream and ostream
* iterators to function properly. Each operator simply
* calls the overloaded operator in the struct definition
*/
std::ostream& operator<<(std::ostream& s, const record& r)
{
const_cast<record&>(r).operator<<(s);
return s;
}
std::istream& operator>>(std::istream& s, record& r)
{
r.operator>>(s);
return s;
}
/**
* For the purpose of this example I'm reading from a string
* stream local to main; however, you can swap out the string
* stream with a C++ file stream (ifstream) and use it in the
* copy method *exactly* as you use the string stream:
*
* std::ifstream infile(filename);
* ...
* std::copy(std::istream_iterator<record>(infile),
* std::istream_iterator<record>(),
* std::back_inserter(myRec));
*/
int main(void)
{
std::vector<record> myRec;
/**
* We're using a local string and string stream for the purpose of
* this example, but the handling of a string stream and a file
* stream would be exactly the same.
*/
std::string data = "M,0.455,0.365,0.095,0.514,0.2245,0.101,0.15,15"
"M,0.35,0.265,0.09,0.2255,0.0995,0.0485,0.07,7"
"F,0.53,0.42,0.135,0.677,0.2565,0.1415,0.21,9"
"M,0.44,0.365,0.125,0.516,0.2155,0.114,0.155,10"
"I,0.33,0.255,0.08,0.205,0.0895,0.0395,0.055,7"
"I,0.425,0.3,0.095,0.3515,0.141,0.0775,0.12,8"
"F,0.53,0.415,0.15,0.7775,0.237,0.1415,0.33,20"
"F,0.545,0.425,0.125,0.768,0.294,0.1495,0.26,16"
"M,0.475,0.37,0.125,0.5095,0.2165,0.1125,0.165,9"
"F,0.55,0.44,0.15,0.8945,0.3145,0.151,0.32,19";
std::stringstream dataStream;
/**
* Write the contents of the string to the string stream
*/
dataStream << data;
/**
* Read the contents of the string stream into the vector
*/
std::copy(std::istream_iterator<record>(dataStream),
std::istream_iterator<record>(),
std::back_inserter(myRec));
std::cout << "Read " << myRec.size() << " records" << std::endl;
/**
* Write the contents of the vector to standard output.
*/
std::copy(myRec.begin(),
myRec.end(),
std::ostream_iterator<record>(std::cout, "\n"));
return 0;
}
这非常简单;没有任何类型的错误处理或处理格式错误的输入的方法。但是,我认为它很好地说明了 C++ I/O 例程的强大功能。
但是,如果您卡在 CI/O 上,您可以执行以下操作:
struct record {
char gender;
double dvar[7];
int ivar;
};
int getRecord(FILE *stream, struct record *r)
{
char line[80]; // assuming each line is less than 80 characters long
if (fgets(line, sizeof line, stream))
{
int count = sscanf(line, "%c,%f,%f,%f,%f,%f,%f,%f,%d",
&r->gender,
&r->dvar[0],
&r->dvar[1],
&r->dvar[2],
&r->dvar[3],
&r->dvar[4],
&r->dvar[5],
&r->dvar[6],
&r->ivar);
if (count < 8)
{
fprintf(stderr, "Input line \"%s\" is malformed\n", line);
return 0;
}
}
else
{
if (feof(stream))
{
fprintf(stderr, "Reached end of file\n");
}
else
{
perror("Error on read");
}
return 0;
}
return 1;
}
int main(void)
{
std::vector<record> myRec;
FILE *input = fopen("myfile.dat", "r");
record r;
while(getRecord(input, &r))
myRec.push_back(r);
...
}
我强烈建议为此使用 C++ I/O 例程;将 CI/O 与 C++ 混合使用会导致胃灼热。