Reputation: 4141
I'm a Java/PHP programmer learning C++.
I've created a class called UserAccount
and a class called Database
.
I have an input file with five names:
Bob
Sam
Jane
Mark
Ann
I have the following (pseudo)code:
UserAccount *ua;
while (reading through the list of names, line by line) {
ua = new UserAccount(name); // Create a new user based on this name
Database->add(ua); // Add the user to the database
}
Database->listAllUsers();
The output should mirror the input file. Instead, I get:
Ann
Ann
Ann
Ann
Ann
I assume this has something to do with pointers, but I can't figure it out. I think I've provided enough information to identify the problem, but if the (pseudo)code above looks correct, I can provide more.
Upvotes: 0
Views: 162
Reputation: 11787
U need a useraccount class to store the details of an individual user and database class to store the details of all useraccount s.
use string, stl, algorithms for efficiency.
A sample menu driven program for your need:
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
class useraccount
{
string name;
//other details
public:
void get(string str)
{
name=str;
}
void display()
{
cout<<name<<endl;
}
};
void display_db(useraccount & e)
{
e.display();
}
void main()
{
vector<useraccount> database;
useraccount *ptr;
int choice;
string name;
do
{
cout<<"\n\n1.Insert \n2.Delete\n3.Display\n4.Exit \nEnter your choice: \n";
cin>>choice;
switch(choice)
{
case 1:
ptr=new useraccount;
cout<<"Enter name:\n";
cin>>name;
ptr->get(name);
database.push_back(*ptr);
break;
case 2:
database.pop_back();
break;
case 3:
for_each(database.begin(),database.end(),display_db);
break;
case 4:
cout<<"Quiting";
break;
default:
cout<<"wrong choice";
}
}while(choice!=4);
}
Upvotes: 1
Reputation: 5388
In C++, unlike other languages, you must explicitly think about where things are stored in memory. A pointer tells you where to look in memory to find something. An analogy would be to tell you to look at at the third letter in the 5th row on page 124 of a book. If my book is written in pencil, I could erase the words on that page and replace them with other words, and while the pointer would stay the same (that is, I look at the same location in the book), what is being pointed to would change.
This is what is happening in your code. Each time you read in a name, you are erasing the previous name and writing the new name in the same memory location. Thus, when you pass in a pointer in your constructor, you are in danger of the memory you are pointing to changing.
To fix this, you need to make a local copy of the name. This can be done by using the string class, as in the response by @Justin. But, for teaching purposes (this code is a bit more complicated), this is how you could allocate new memory internally (the string class just does it for you):
class UserAccount {
public:
UserAccount(const char *name)
{
m_name = new char[strlen(name)+1];
strcpy(m_name, name);
}
~UserAccount()
{
delete [] m_name;
}
private:
char * m_name;
};
Note that we are now using the destructor, because we've allocated memory and need to free it again when the class is deleted. Also note that I haven't checked to see if the name being passed in is null, which should be done. A final note is that strings are implicitly null terminated to tell you when you've hit the end of the string. This is why we must allocate a large size -- to hold the null at the end of the string.
As @Marc pointed out, you can also use strdup, but I thought a longer explanation and showing the explicit allocation of memory would be useful to give a better sense of what is going on.
Upvotes: 1
Reputation: 1376
To follow up from my comments. You are likely running afoul of pointers, the std::string
class will give you behaviour much more similar to that of Java.
The simplest solution will be to use the string strdup()
call.
#include <cstring> // provides C string interface
UserAccount::UserAccount(char *n) {
name = strdup(n);
}
UserAccount::~UserAcount() {
// This is older C style, cleanup. Need or the memory will "leak".
free(name);
// You could also use: delete[] name;
}
Alternatively you could use std::string
, but I'll leave that to your learning process. There is a lot of information on pointers out there, it will help your learning to understand pointers intimately.
// e.g.
char *str1 = "ann";
char *str2 = "bob";
str1 = str2;
// Both equal "bob".
str1 = "carol";
// Both equal "carol"!
Good luck.
Upvotes: 1
Reputation: 104698
Could you provide an example of the correct implementation?
This would be a start:
#include <string>
#include <vector>
class UserAccount {
public:
UserAccount(const std::string& name) : d_name(name) {}
...
private:
std::string d_name;
};
class Database {
public:
Database() : d_accounts() {}
void add(const UserAccount& account) {
this->d_accounts.push_back(account);
}
...
private:
std::vector<UserAccount> d_accounts;
};
void zb() {
Database db;
db.add(UserAccount("Bob"));
...
}
It's different from what you posted because the vector's storing values of UserAccounts. At any rate -- more code would help. I'll eventually delete this because it's not a real answer(well, maybe update once the problem's defined better).
Upvotes: 2