我有一个类似于/ etc / passwd(分号分隔值)的文件,需要将每行的所有三个值提取到变量中,然后将它们与程序中的值进行比较。这是我的代码:
typedef struct _UserModel UserModel;
struct _UserModel {
char username[50];
char email[55];
char pincode[30];
};
void get_user(char *username) {
ifstream io("test.txt");
string line;
while (io.good() && !io.eof()) {
getline(io, line);
if (line.length() > 0 && line.substr(0,line.find(":")).compare(username)==0) {
cout << "found user!\n";
UserModel tmp;
sscanf(line.c_str() "%s:%s:%s", tmp.username, tmp.pincode, tmp.email);
assert(0==strcmp(tmp.username, username));
}
}
}
我无法strcmp值,因为尾部'\ 0'表示字符串不同,因此断言失败。我只是想保留值的内存,而不是耗尽我不需要这些值的内存。我需要做些什么才能让它发挥作用..?
答案 0 :(得分:2)
struct UserModel {
string username;
string email;
string pincode;
};
void get_user(char *username) {
ifstream io("test.txt");
string line;
while (getline(io, line)) {
UserModel tmp;
istringstream str(line);
if (getline(str, tmp.username, ':') && getline(str, tmp.pincode, ':') && getline(str, tmp.email)) {
if (username == tmp.username)
cout << "found user!\n";
}
}
}
答案 1 :(得分:1)
如果你正在使用c ++,我会尝试使用std::string
,iostreams以及C ++附带的所有内容,但是再次......
我明白你的问题是其中一个C字符串是空终止的,而另一个不是,然后strcmp
在一个字符串上踩到'\0'
,但是另一个字符串另一个值...如果这是您想要更改的唯一内容,请使用strncpy
和已知字符串的长度。
答案 2 :(得分:1)
这是一个完整的例子,可以满足我的想法。
你没有要求的东西,但无论如何:
GetModelForUser()
可以简单地返回一个对象(而不是布尔值或类似的东西)。
/* Parses a file of user data.
* The data file is of this format:
* username:email-address:pincode
*
* The pincode field is actually one-way-encrypted with a secret salt
* in order to avoid catastrophic loss of customer data when the file
* or a backup tape is lost/leaked/compromised. However, this code
* simply treats it as an opaque value.
*
* Internationalisation: this code assumes that the data file is
* encoded in the execution character set, whatever that is. This
* means that updates to the file must first transcode the
* username/mail-address/pincode data into the execution character
* set.
*/
#include <string>
#include <vector>
#include <fstream>
#include <iostream>
#include <iterator>
#include <exception>
const char* MODEL_DATA_FILE_NAME = "test.txt";
// This stuff should really go in a header file.
class UserUnknown : public std::exception { };
class ModelDataIsMissing : public std::exception { };
class InvalidModelData : public std::exception { }; // base: don't throw this directly.
class ModelDataBlankLine : public InvalidModelData { };
class ModelDataEmptyUsername : public InvalidModelData { };
class ModelDataWrongNumberOfFields : public InvalidModelData { };
class UserModel {
std::string username_;
std::string email_address_;
std::string pincode_;
public:
UserModel(std::string username, std::string email_address, std::string pincode)
: username_(username), email_address_(email_address), pincode_(pincode) {
}
UserModel(const UserModel& other)
: username_(other.username_),
email_address_(other.email_address_),
pincode_(other.pincode_) {
}
std::string GetUsername() const { return username_; }
std::string GetEmailAddress() const { return email_address_; }
std::string GetPincode() const { return pincode_; }
};
UserModel GetUserModelForUser(const std::string& username)
throw (InvalidModelData, UserUnknown, ModelDataIsMissing);
// This stuff is the implementation.
namespace { // use empty namespace for modularity.
template void SplitStringOnSeparator(
std::string input, char separator, ForwardIterator output)
{
std::string::const_iterator field_start, pos;
bool in_field = false;
for (pos = input.begin(); pos != input.end(); ++pos) {
if (!in_field) {
field_start = pos;
in_field = true;
}
if (*pos == separator) {
*output++ = std::string(field_start, pos);
in_field = false;
}
}
if (field_start != input.begin()) {
*output++ = std::string(field_start, pos);
}
}
}
// Returns a UserModel instance for the specified user.
//
// Don't call this more than once per program invocation, because
// you'll end up with quadratic performance. Instead modify this code
// to return a map from username to model data.
UserModel GetUserModelForUser(const std::string& username)
throw (InvalidModelData, UserUnknown, ModelDataIsMissing)
{
std::string line;
std::ifstream in(MODEL_DATA_FILE_NAME);
if (!in) {
throw ModelDataIsMissing();
}
while (std::getline(in, line)) {
std::vector<std::string> fields;
SplitStringOnSeparator(line, ':', std::back_inserter(fields));
if (fields.size() == 0) {
throw ModelDataBlankLine();
} else if (fields.size() != 3) {
throw ModelDataWrongNumberOfFields();
} else if (fields[0].empty()) {
throw ModelDataEmptyUsername();
} else if (fields[0] == username) {
return UserModel(fields[0], fields[1], fields[2]);
}
// We don't diagnose duplicate usernames in the file.
}
throw UserUnknown();
}
namespace {
bool Example (const char *arg)
{
const std::string username(arg);
try
{
UserModel mod(GetUserModelForUser(username));
std::cout << "Model data for " << username << ": "
<< "username=" << mod.GetUsername()
<< ", email address=" << mod.GetEmailAddress()
<< ", encrypted pin code=" << mod.GetPincode()
<< std::endl;
return true;
}
catch (UserUnknown) {
std::cerr << "Unknown user " << username << std::endl;
return false;
}
}
}
int main (int argc, char *argv[])
{
int i, returnval=0;
for (i = 1; i < argc; ++i)
{
try
{
if (!Example(argv[i])) {
returnval = 1;
}
}
catch (InvalidModelData) {
std::cerr << "Data file " << MODEL_DATA_FILE_NAME << " is invalid." << std::endl;
return 1;
}
catch (ModelDataIsMissing) {
std::cerr << "Data file " << MODEL_DATA_FILE_NAME << " is missing." << std::endl;
return 1;
}
}
return returnval;
}
/* Local Variables: /
/ c-file-style: "stroustrup" /
/ End: */
std::string GetUsername() const { return username_; }
std::string GetEmailAddress() const { return email_address_; }
std::string GetPincode() const { return pincode_; }
答案 3 :(得分:0)
我没有看到strcmp
出现问题,但您的sscanf格式有问题。 %s
将读取第一个非白色字符,因此它将读取:
。您可能希望"%50[^:]:%55[^:]:%30s"
作为格式字符串。我已经添加了字段大小以防止缓冲区溢出,但我可能会在限制范围内关闭。