我写了一个简化版本的代码,我正在努力说明我遇到的问题。我认为main()
中的某些内容错误导致showUsers()
方法为每个元素输出相同的登录/密码组合(始终是添加的最后一个)。
#include <iostream>
using namespace std;
//=============================================================================
class AccountInfo {
private:
char* _username;
char* _password;
public:
AccountInfo();
AccountInfo(char* username, char* password);
~AccountInfo();
void setUsername(char* username);
void setPassword(char* password);
char* getUsername();
char* getPassword();
friend ostream& operator<<(ostream& out, AccountInfo& x) {
out << "Login: " << x.getUsername() << endl
<< "Password: " << x.getPassword() << endl;
return out;
}
};
AccountInfo::AccountInfo() {
_username = "";
_password = "";
}
AccountInfo::AccountInfo(char* username, char* password) {
_username = username;
_password = password;
}
void AccountInfo::setUsername(char* username) {
_username = username;
}
void AccountInfo::setPassword(char* password) {
_password = password;
}
char* AccountInfo::getUsername() {
return _username;
}
char* AccountInfo::getPassword() {
return _password;
}
//=============================================================================
class UsersDB {
private:
int _size;
AccountInfo* _accounts[200];
public:
UsersDB();
~UsersDB();
int getSize();
void addUser(AccountInfo* newUser);
void showUsers();
};
UsersDB::UsersDB() {
_size = 0;
}
UsersDB::~UsersDB() {
delete[] _accounts;
}
int UsersDB::getSize() {
return _size;
}
void UsersDB::addUser(AccountInfo* newUser) {
_accounts[_size] = newUser;
_size++;
}
void UsersDB::showUsers() {
for (int i = 0; i < _size; i++) {
cout << *_accounts[i] << endl;
}
}
//---------------------------------------------------------emptyString function
void emptyString(char* token, int size) {
for (int i=0; i < size; i++) token[i] = '\0';
}
//----------------------------------------------------------copyString function
void copyString (char* from, char* to, int size) {
to = new char[size+1];
for (int i=0; i < size; i++) to[i] = from[i];
to[size] = '\0';
}
//--------------------------------------------------------getNextToken function
int getNextToken(char* buffer, char* token, int startPos,
int bufSize, int tokenSize, char delimeter) {
int i, j;
emptyString (token, tokenSize);
i = startPos;
j = 0;
while ((buffer[i] == ' ') && (i < bufSize)) i++; //skipblanks
if (i < 256) {
while ((buffer[i] != delimeter) && (i < 256) && (j < tokenSize))
token[j++] = buffer[i++];
}
return i;
}
//=============================================================================
int main() {
char buffer[256];
char userLoginName[9];
char password[17];
int i, j, k;
char flag[3];;
char command[11];
char blank = ' ';
UsersDB* users = new UsersDB();
AccountInfo* tempAccount;
while (!cin.eof()) { //while end of line is not reached
cin.getline(buffer, 256);
k = getNextToken(buffer, command, 0, 256, 10, blank);
if (command[0] == 'a') {
tempAccount = new AccountInfo();
k = getNextToken(buffer, userLoginName, k, 256, 8, blank);
(*tempAccount).setUsername(userLoginName);
k = getNextToken(buffer, flag, k, 256, 2, blank);
if (flag[1] == 'p') {
k = getNextToken(buffer, password, k, 256, 16, blank);
(*tempAccount).setPassword(password);
}
cout << *tempAccount << endl;
(*users).addUser(tempAccount);
}
else if (command[0] == 's') {
(*users).showUsers();
}
else cout << "Command not found." << endl;
}
return 0;
}
=============================================================================== >adduser bob -p password1 Login: bob Password: password1 >adduser jack -p mypassword Login: jack Password: mypassword >adduser jill -p pass1234 Login: jill Password: pass1234 >showusers Login: jill Password: pass1234 Login: jill Password: pass1234 Login: jill Password: pass1234 ===============================================================================
=============================================================================== >adduser bob -p password1 Login: bob Password: password1 >adduser jack -p mypassword Login: jack Password: mypassword >adduser jill -p pass1234 Login: jill Password: pass1234 >showusers Login: bob Password: password1 Login: jack Password: mypassword Login: jill Password: pass1234 ===============================================================================
注意:当我改变main()
时(通过直接传递信息而不是使用cin
从控制台获取信息)看起来像这样:
//============================================================================= int main() { UsersDB* users = new UsersDB(); AccountInfo* tempAccount; tempAccount = new AccountInfo("jack", "mypassword"); (*users).addUser(tempAccount); tempAccount = new AccountInfo("jill", "pass1234"); (*users).addUser(tempAccount); (*users).showUsers(); return 0; }
...我得到了所需的输出。
非常感谢。
答案 0 :(得分:2)
你在课堂上使用char *指针,它们不像“普通”字符串那样工作。当您将char *指针传递给方法并将其指定给成员变量时,您不会复制该字符串,而只是使成员变量指向与参数指向的字符串相同的字符串。由于传入的所有参数都是指向输入缓冲区的指针,因此缓冲区中的下一个输入将覆盖所有先前对象中的文本。
在C ++中,你应该使用std::string而不是传递char *来进行字符串操作,它会在这种情况下帮助你,并且会自动处理为新字符串复制和分配内存。
后一版本的常量有效的原因是你的对象最终指向不像缓冲区那样被覆盖的文本常量。
答案 1 :(得分:1)
您的问题是您的UserAccounts(所有这些)最终成为main()中(单个)用户和密码char数组的指针。 你可以通过每次使用这个main来创建一个新数组来修复它:
//=============================================================================
int main() {
char buffer[256];
char *userLoginName;
char *password;
int i, j, k;
char flag[3];;
char command[11];
char blank = ' ';
UsersDB* users = new UsersDB();
AccountInfo* tempAccount;
while (!cin.eof()) { //while end of line is not reached
cin.getline(buffer, 256);
k = getNextToken(buffer, command, 0, 256, 10, blank);
if (command[0] == 'a') {
userLoginName = new char[9];
password = new char[17];
tempAccount = new AccountInfo();
k = getNextToken(buffer, userLoginName, k, 256, 8, blank);
(*tempAccount).setUsername(userLoginName);
k = getNextToken(buffer, flag, k, 256, 2, blank);
if (flag[1] == 'p') {
k = getNextToken(buffer, password, k, 256, 16, blank);
(*tempAccount).setPassword(password);
}
cout << *tempAccount << endl;
(*users).addUser(tempAccount);
}
else if (command[0] == 's') {
(*users).showUsers();
}
else cout << "Command not found." << endl;
}
return 0;
}
请记住之后删除它们。这是修复它的最少代码行,我只是为了演示问题所在。一个更好的解决方案是在构建UserAccount中创建新数组(因为它似乎总是需要它们)并在dtor上删除它们,如下所示:
//At top of file:
#include <string.h>
AccountInfo::AccountInfo() {
_username = new char[9];
_password = new char[17];
}
AccountInfo::AccountInfo(char* username, char* password) {
strcpy(_username, username);
strcpy(_password, password);
}
AccountInfo::~AccountInfo() {
delete _username;
delete _password;
}
void AccountInfo::setUsername(char* username) {
strcpy(_username, username);
}
void AccountInfo::setPassword(char* password) {
strcpy(_password, password);
}
答案 2 :(得分:1)
您永远不会分配空间来存储AccountInfo
课程中的用户名和密码。您的setUserName
和setPassword
函数只是将原始指针复制到类中。因此,在您的第一个main
中,每个用户只需指向您在username
中声明的userLoginName
和main
缓冲区,因此它们都是相同的。在第二个main
中,它们指向用于构造它们的字符串文字。
我还要补充一点,这实际上是带有成员函数的C代码。如果你正在使用C ++,你应该使用像std::string
和std::vector
这样的C ++功能,这样会使这样的错误几乎不可能。
答案 3 :(得分:0)
在你的程序中,setPassword和setUsername存储指向传入缓冲区的指针,而不是复制字符串。
您应该使用copyString函数。