我一直在写一个小项目,只是为了扩展我对c ++的了解,我遇到了一个问题。当我接受用户名时,我想检查是否已经使用了。如果获得该特定用户名,我会将问题重新打印给用户。它在第一个循环中运行良好,但在此之后它将接受任何内容,即使它确实存在于用户Vector中。
bool verify(char * a, vector<User> b){
14 for(int i = 0; i < b.size(); i++){
15 if(strcmp(a, b[i].getUsername()) == 0){
16 return false;
17 }
18 }
19 return true;
20 }
21
22 int main(){
23
24 vector<User> users;
25
26 User us1((char *)"foo", (char *)"bar");
27 users.push_back(us1);
28
29
30 do{
31 cout << "Enter Username: ";
32 scanf(" %s", username);
33
34
35 } while(!verify(username, users));
36
37 return 0;
38 }
然而,如果我的功能验证反而采用了矢量&amp; b它工作正常。有人可以解释为什么会这样吗?
User.cpp
User:: User(char * userName, char * passWord){
9
10 this->userName = strdup(userName);
11 this->passWord = strdup(passWord);
12
13 }
14
15 User:: ~User(){
16
17 delete userName;
18 delete passWord;
19
20 }
21
22 void User::getMessage(){
23
24 cout << message << endl;
25 }
26
27 char * User:: getUsername(){
28
29 return userName;
30 }
31
32 char * User :: getPassword(){
33
34 return passWord;
35 }
36
37 void User:: printUser(){
38
39 cout << "User Information" << endl;
40 cout << "Username: "<< userName << endl;
41 cout << "Password: "<< passWord << endl;
42 cout << "Messages: "<< ((message == NULL) ? "User has no messages\n" : "User has 1 message\n");
43
44 }
答案 0 :(得分:2)
除了使用std::string
之外的所有讨论,OP代码中的基本问题是缺少User
类的用户定义的复制构造函数。默认值只会复制userName
和passWord
字段中的值,导致两个向量(main
中的一个和为verify
函数创建的一个)指向到相同的分配内存地址。当verify
返回时,该内存将被删除,将Users
保留在main
中的向量中,悬挂指针(指向已释放的内存)。
使用该引用可避免此删除并保持原始矢量不变。
这就是为什么你现在不应该在代码中使用原始指针的原因之一。
答案 1 :(得分:0)
我强烈建议尽可能使用C ++功能而不是C语言,它通常更具可读性且不易出错。
现在代码中存在多个问题,而@AlanStrokes' comment是正确的,你的主要问题是没有正确处理三条规则。
您的User
类执行动态分配,但未定义copyconstructor和赋值运算符。有关显示问题的简单代码段,请查看代码段here。它只复制地址,而不是指向的实际数据,因此一旦第一个副本被删除,其他所有数据都无效。
您还有其他问题,strdup
是不可移植的,它不是C标准的一部分。它是POSIX标准的一部分,因此很可能仅在实现该标准的系统上可用。它也是一个用malloc
分配内存的C函数,你应该删除它从C返回free
的指针,而不是C ++中的delete
。
还有一个原因是C ++中的字符串文字是const char[]
,事实上在C中它们是char[]
但是你不允许编辑它们所以它实际上也是常量。那是因为允许编译器将字符串文字放入可执行文件的只读位置。因此,不要将字符串文字投射到char *
,而是使您的函数正确地使用const char *
。
所有这些说处理那些指针的东西都很烦人,因为C ++使std::string
变得更容易,我推荐使用它:
class User {
private:
std::string userName;
std::string password;
User(const std::string &userName, const std::string & passWord);
std::string getUsername();
std::string getPassword();
void printUser();
};
User::User(const std::string & userName, const std::string & passWord) {
this->userName = userName;
this->passWord = passWord;
}
std::string User::getUsername() {
return userName;
}
std::string User::getPassword() {
return passWord;
}
// etc...
这里C ++自动处理所有复制和删除逻辑,你不必处理讨厌的指针。
答案 2 :(得分:0)
它做得很好,在我做了最小的改动之后它实际编译了。 我只是使用std :: string存储字符串而不是猜测你的User类。
#include <vector>
#include <string>
#include <iostream>
#include <cstdio>
#include <cstring>
struct User {
std::string name, game;
User(const char* nam, const char* gam) : name(nam), game(gam) {}
const char* getUsername() const {
return name.c_str();
}
};
bool verify(char * a, std::vector<User> b) {
for (int i = 0; i < b.size(); i++) {
if (std::strcmp(a, b[i].getUsername()) == 0) {
return false;
}
}
return true;
}
int main(){
std::vector<User> users;
User us1("foo", "bar");
users.push_back(us1);
char username[100];
do {
std::cout << "Enter Username: ";
std::scanf(" %50s", username);
} while(!verify(username, users));
return 0;
}
当我运行此on ideone,输入“foo”三次然后输入“Greg”时,它会在每个“foo”之后继续提示,然后接受“Greg”。
由于将另一个类替换为您看不见的“User”类使其工作,问题必须在该类中,可能在您处理传递给其构造函数的指针时。
一些注意事项:
不需要将字符串文字“foo”和“bar”强制转换为(char*)
;他们已经char*
了。如果您这样做是为了摆脱const
- ness,请不要:它们可能位于只读内存中。
如果你有C ++ 11,verify
中的循环可以替换为range-for:
for (auto u : b) {
if (strcmp(a, u.getUsername()) == 0)
return false;
}
实际上,您可以删除整个函数verify
并使用std::any_of(users.begin(), users.end(), [username](const User& u){ return strcmp(u.getUsername(), username) == 0; })
,如果true
已经在向量username
中,则返回users
}。
所以一个较短的,等效的完整程序
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
struct User {
std::string name, game;
User(const char* nam, const char* gam) : name(nam), game(gam) {}
const std::string& getUsername() const {
return name;
}
};
int main(){
std::vector<User> users;
users.push_back({"foo","bar"});
std::string username;
do {
std::cout << "Enter Username: ";
std::cin >> username;
} while(std::any_of(users.begin(), users.end(),
[username](const auto& u){ return u.getUsername() == username; }));
return 0;
}