"Ambiguous Overload" issues in loop, and malfunctioning cin - c++

I'm building a menu creation class with a member function that should display the menu, get a selection from the user, test if it's a valid menu item, and return the number of the item. For some reason, the compiler is giving me an "ambiguous overload for operator '>>'" error on a simple cin statement in the run() member function below. When run, the function catches invalid input properly, but then considers all input after that invalid. If the first input is correct, the program terminates outright. Here's my code:
#include <iostream>
#include <vector>
using namespace std;
class NumericalMenu {
private:
string prompt;
vector<string> options;
string canceltext;
string errortext;
bool repeatprompt;
int sel;
public:
NumericalMenu() {
prompt = "Choose an option:";
canceltext = "Cancel";
errortext = "Error!";
repeatprompt = true;
sel = 0;
};
void setPrompt(string text) {
prompt = text;
};
int size() const {
int size = options.size() + 1;
return size;
};
int addOption(string text) {
options.push_back(text);
int position = options.size() - 1;
return position;
};
void setCancelText(string text) {
canceltext = text;
};
void setRepeatPromptOnError(bool repeat) {
repeatprompt = repeat;
};
void setErrorText(string text) {
errortext = text;
};
int run() const{
cout << prompt << "\n\n";
for (unsigned i=0; i<options.size(); i++) {
cout << i+1 << " - " << options[i] << "\n";
}
int errorpos = this->size();
cout << errorpos << " - " << canceltext << "\n\n";
cin.clear();
cin.ignore();
cin >> sel;
if(cin.fail() || sel<=0 || sel>errorpos) {
cout << "\n" << errortext << "\n\n";
if(repeatprompt == true) {
cin.clear();
cin.ignore();
this->run();
}
}
if (sel == errorpos) {
return -1;
} else {
return sel;
}
};
};
int main() {
NumericalMenu menu;
menu.setPrompt("Choose an option:");
menu.addOption("Enter new values");
menu.addOption("Help");
menu.addOption("Save");
menu.setCancelText("Exit");
menu.run();
}
Edit: Got it! Thanks everyone. The working header:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class NumericalMenu {
private:
string prompt;
vector<string> options;
string canceltext;
string errortext;
bool repeatprompt;
public:
NumericalMenu() {
prompt = "Choose an option:";
canceltext = "Cancel";
errortext = "Error!";
repeatprompt = true;
};
void setPrompt(string text) {
prompt = text;
};
int size() const{
int size = options.size() + 1;
return size;
};
int addOption(string text) {
options.push_back(text);
int position = options.size() - 1;
return position;
};
void setCancelText(string text) {
canceltext = text;
};
void setRepeatPromptOnError(bool repeat) {
repeatprompt = repeat;
};
void setErrorText(string text) {
errortext = text;
};
int run() const{
cout << prompt << "\n\n";
for (unsigned i=0; i<options.size(); i++) {
cout << i+1 << " - " << options[i] << "\n";
}
int errorpos = this->size();
cout << errorpos << " - " << canceltext << "\n\n";
int sel;
cin.clear();
cin >> sel;
if(cin.fail() || sel<=0 || sel>errorpos) {
cout << "\n" << errortext << "\n\n";
if(repeatprompt == true) {
cin.clear();
cin.ignore(1000, '\n');
int sele = this->run();
return sele;
}
}
if (sel == this->size()) {
return -1;
}
else {
return sel;
}
};
};

You declared your run() function as const and preventing modifications to member variables is being enforced by the compiler.
class NumericalMenu {
private:
int sel;
...
int run() const {
cin >> sel; // Not allowed
If you need to modify member variables, remove the const in your inline run() function definition.
Furthermore as a good practice try to include all the headers you directly use in your code (i.e. <string>).

Related

Is it possible to change a generic variable into a specific one, or initialize a variable of a specific type with the value of a generic variable?

#include <iostream>
#include <typeinfo>
#include <string>
#include <cstdlib>
using namespace std;
template <typename First>
class VerifyIfTrue{
protected:
First AG;
int tries = 0;
int vaalue;
int RT;
string whatis;
string lie1;
string lie2;
VerifyIfTrue(string twhatis, string tlie1, string tlie2) : whatis(twhatis), lie1(tlie1), lie2(tlie2)
{input();}
void input(){
if(tries == 0){
cout << "Tell me your " << whatis << "\n";}else{
cout << "Come on, what's your " << whatis << "\n";}
cin >> AG;
if(typeid(AG).name() != typeid(int).name())
{
int x = 0;
AG = x;
cout << "Wrong type" << endl;
++tries;
input();
}else{
int a = AG;
positivetest(a);
}
void positivetest(int RT){
if(RT <=0)
{
cout << lie1 << "\n";
if(tries == 0)
{
++tries;
cout << lie2 << "\n";
}
int y = 0;
AG = y;
++tries;
input();
}else{
vaalue = AG;
}
}
}
...
I get the following error:
cannot convert 'std::__cxx11::basic_string' to 'int' in initialization|
Is there a way around this? I want to either be able to change AG into an int, so it can be passed into int parameters or tested if it's an int; or be able to assign its' value to an int
You might use if constexpr (c++17) with std::is_same:
if constexpr (!std::is_same_v<int, First>) {
int x = 0;
AG = x;
cout << "Wrong type" << endl;
++tries;
input();
} else {
int a = AG;
positivetest(a);
}

C++ Read Value from a pointer to struct including the target struct in an array

I am new to c++ and trying to make an atm. It consits of one file reading user data from files and a main file. Everytime I try to read the output of the returned pointer to the array of structs, where the data is stored, I get strange data. I think there is a problem when assigning strings to the first struct, because when I tried with test values (third file) it worked.
Edit:
I can read out integeres from the strcut, but I have problems with strings.
Here is the code
users.cpp (Creates the struct, included in main.cpp)
#include <fstream>
#include <string>
#include <iostream>
#define STRING_ERROR 4294967295
#define MAX_USERS 100000
using namespace std;
struct user
{
int id;
string firstname;
string name;
int age;
int pin;
};
struct user_container{
int size;
user users [MAX_USERS];
};
typedef struct user User;
typedef struct user_container container;
void print_user_vars(User *user){
cout << "Id: " << user->id << "\nFirstname: " << user->firstname << "\nName: " << user->name << "\nAge: " << user->age << "\nPIN: " << user->pin << endl;
}
int get_usercount(string path){
int usercount = 0;
ifstream file;
string line;
file.open(path, ios::binary | ios::in);
while(true){
getline(file , line);
if(file.fail())
break;
if(line.find("}") != STRING_ERROR){
usercount++;
}
}
file.close();
return usercount;
}
container * get_users(string path){
const int usercount = get_usercount(path);
ifstream file;
string line;
User users[usercount];
const char *values[5] = {"id", "firstname", "name", "age", "pin"};
file.open(path, ios::binary | ios::in);
User proto_user;
int user_num = 0;
while(true){
getline(file , line);
if(file.fail())
break;
if(line.find(":") != STRING_ERROR){
for(int i = 0; i < 5; i++){
if(line.find(values[i]) != STRING_ERROR){
string value;
for(int v = 0; v < line.length(); v++){
if(v > line.find_first_of(":")){
value += line[v];
}
}
if(values[i] == "id"){
proto_user.id = stoi(value);
}
else if(values[i] == "firstname"){
proto_user.firstname = value;
}
else if(values[i] == "name"){
proto_user.name = value;
}
else if(values[i] == "age"){
proto_user.age = stoi(value);
}
else if(values[i] == "pin"){
proto_user.pin = stoi(value);
}
break;
}
}
}
else if(line.find("}") != STRING_ERROR){
//print_user_vars(&proto_user);
users[user_num++] = proto_user;
//cout << "Added user at " << user_num << endl;
}
//cout << line << endl;
}
for(int i = 0; i < user_num; i++){
//cout << "\nUSER: " << i + 1 << endl;
//print_user_vars(&users[i]);
}
static container con;
con.size = usercount;
for(int i = 0; i < usercount; i++){
if(i <= MAX_USERS){
// con.users[i] = users[i] didnt work, but this does
con.users[i].firstname = users[i].firstname;
con.users[i].age = users[i].age;
con.users[i].name = users[i].name;
con.users[i].pin = users[i].pin;
con.users[i].id = users[i].id;
}
}
print_user_vars(&con.users[0]);
return &con;
}
main.cpp (Calls the function)
#include <iostream>
#include "includes/users.h"
using namespace std;
int main(void){
string wasd = "w";
int id;
int pin;
cout << "\n Welcome\n\n ID\n>>> ";
cin >> id;
cout << " PIN\n>>> ";
cin >> pin;
container *con = get_users("users");
int size = con->size;
cout << "Age: " << con->users[0].age << ", PIN: " << con->users[0].pin << ", Firstname: " << con->users[0].firstname << ", Name: "
<< con->users[0].name << ", ID: " << con->users[0].id << endl;
//Functionality
return 0;
}
Simpler.cpp (Just like users.cpp, but with test values, included in main.cpp)
#include <fstream>
#include <string>
#include <iostream>
#define STRING_ERROR 4294967295
#define MAX_USERS 100000
using namespace std;
struct user
{
int id;
string firstname;
string name;
int age;
int pin;
};
struct user_container{
int size;
user users [MAX_USERS];
};
typedef struct user User;
typedef struct user_container container;
container * get_users(string path){
const int usercount = 2;
User users[usercount];
users[0].age = 59;
users[0].firstname = "Peter";
users[0].name = "Bremer";
users[0].id = 456878;
users[0].pin = 1234;
users[1].age = 8;
users[1].firstname = "a";
users[1].name = "b";
users[1].id = 456;
users[1].pin = 1111;
static container con;
con.size = usercount;
for(int i = 0; i < usercount; i++){
if(i <= MAX_USERS){
// con.users[i] = users[i] didnt work, but this does
con.users[i].firstname = users[i].firstname;
con.users[i].age = users[i].age;
con.users[i].name = users[i].name;
con.users[i].pin = users[i].pin;
con.users[i].id = users[i].id;
}
}
cout << "Usercount " << usercount << endl;
return &con;
}
int main(void){
container *con = get_users("users");
int size = con->size;
cout << "Age: " << con->users[0].age << ", PIN: " << con->users[0].pin << ", Firstname: " << con->users[0].firstname << ", Name: "
<< con->users[0].name << ", ID: " << con->users[0].id << endl;
return 0;
}
Not really the answer you are looking for:
Avoid using typedef when you don't need it. Just name your struct User, it will be available under that name without writing struct User.
And for your container, just use one of the STL containers. std::vector<User> would be a good start. This also removes the need for MAX_USERS.
struct User
{
int id;
std::string firstname;
std::string name;
int age;
int pin;
};
typedef std::vector<User> container;
With the three interfaces in user.cpp you can now just use
void print_user_vars(const User& user);
int get_usercount(const std::string& path);
container get_users(const std::string& path);
and thus get rid of the static container con; in get_users.
With a std::vector I no longer see a need for the get_usercount function.
And instead of macros go for constants (and remove magic numbers):
auto const STRING_ERROR = std::string::npos;
(Though I don't agree with the name STRING_ERROR. It's more a STRING_NOT_FOUND.)
Cleanup of print_user_vars after signature change:
void print_user_vars(const User& user)
{
std::cout << "Id: " << user.id << "\nFirstname: " << user.firstname
<< "\nName: " << user.name << "\nAge: " << user.age
<< "\nPIN: " << user.pin << std::endl;
}
And getting some inspiration from get_usercount (a method I don't believe you need):
int get_usercount(const std::string& path)
{
int usercount = 0;
std::ifstream file(path, std::ios_base::binary);
std::string line;
while(std::getline(file, line))
{
if(line.find("}") != STRING_ERROR)
{
usercount++;
}
}
return usercount;
}
This line in get_users is NOT C++. (It's part of the C99 standard):
User users[usercount];
And as #bruno points out:
else if(values[i] == "name"){
does not work. Consider
else if(std::strcmp(values[i], "name") == 0){

'View v' has incomplete type and cannot be defined C++

#include <iostream>
#include <string>
#include <vector>
class Contact;
class Controller;
class View;
class Contact {
private:
std::string name;
std::string phone;
public:
std::string get_name() {
return name;
}
std::string get_phone() {
return phone;
}
void set_name(std::string name) {
this->name = name;
}
void set_phone(std::string phone) {
this->phone = phone;
}
};
class Controller {
public:
void delete_contact(std::vector<Contact> &data) {
std::cout << "Choose a number from 1 to 3.\n";
std::cout << "1. Delete by id\n";
std::cout << "2. Delete by name\n";
std::cout << "3. Delte by phone\n";
int choice;
std::cin >> choice;
enum { ID = 1, NAME = 2, PHONE = 3 };
if (choice == ID) {
int id;
std::cout << "Enter id: \n";
std::cin >> id;
delete_by_id(data, id);
}
else if (choice == NAME) {
std::string name;
std::cout << "Enter name: \n";
std::cin >> name;
delete_by_name(data, name);
}
else if (choice == PHONE) {
std::string phone;
std::cout << "Enter phone: \n";
std::cin >> phone;
delete_by_phone(data, phone);
}
else {
std::cerr << "Wrong choice.\n";
}
}
void delete_by_id(std::vector<Contact> &data, const int id) {
// valid ids are in range [1 .. data.size()]
if (id < data.size() || id > data.size()) {
std::cerr << "id not found\n";
return;
}
std::cout << "Contact " << id << " deleted successfully\n";
}
void delete_by_name(std::vector<Contact> &data, const std::string name) {
int id = -1;
// assuming unique names
for (int i = 0; i < data.size(); i++) {
if (data[i].get_name() == name) {
id = i;
break;
}
}
if (id == -1) {
std::cerr << "Contact with " << name << " is not found\n";
return;
}
data.erase(data.begin() + id);
}
void delete_by_phone(std::vector<Contact> &data, const std::string phone) {
int id = -1;
for (int i = 0; i < data.size(); i++) {
if (data[i].get_name() == phone) {
id = i;
break;
}
}
if (id == -1) {
std::cerr << "Contact with " << phone << " is not found\n";
return;
}
data.erase(data.begin() + id);
}
void add_contact(Contact new_contact, std::vector<Contact> &data) {
data.push_back(new_contact);
}
void search_contact(std::vector<Contact> &data) {
std::cout << "1. Search by id.\n";
std::cout << "2. Search by name.\n";
std::cout << "3. Search by phone.\n";
enum { ID = 1, NAME = 2, PHONE = 3 };
int choice;
std::cin >> choice;
if (choice == ID) {
int id;
std::cout << "Enter id: \n";
std::cin >> id;
search_by_id(data, id);
}
else if (choice == NAME) {
std::string name;
std::cout << "Enter name: \n";
std::cin >> name;
search_by_name(data, name);
}
else if (choice == PHONE) {
std::string phone;
std::cout << "Enter phone: \n";
std::cin >> phone;
search_by_phone(data, phone);
}
else {
std::cerr << "Wrong choice.\n";
}
}
void search_by_id(std::vector<Contact> &data, int id) {
if (id < data.size() || id > data.size()) {
std::cerr << "Contact not found\n";
return;
}
View v;
v.print_contact_data(data[id]);
}
void search_by_name(std::vector<Contact> &data, const std::string name) {
int id = -1;
for (int i = 0; i < data.size(); i++) {
if (data[i].get_name() == name) {
id = i;
break;
}
}
if (id == -1) {
std::cerr << "Contact not found\n";
return;
}
View v;
v.print_contact_data(data[id]);
}
void search_by_phone(std::vector<Contact> &data, const std::string phone) {
int id = -1;
for (int i = 0; i < data.size(); i++) {
if (data[i].get_phone() == phone) {
id = i;
break;
}
}
if (id == -1) {
std::cerr << "Contact not found\n";
return;
}
View v;
v.print_contact_data(data[id]);
}
void edit_contact(std::vector<Contact> &data) {
std::cout << "Enter contact id\n";
int id;
std::cin >> id;
if (id < data.size() || id > data.size()) {
std::cerr << "Sorry, wrong id\n";
}
std::cout << "Do you want to edit this contact? [Y, N]\n";
View v;
v.print_contact_data(data[id]);
std::string choice;
std::cin >> choice;
if (choice.front() == 'Y') {
std::cout << "Enter new name:\n";
std::string name;
std::cin >> name;
data[id].set_name(name);
std::cout << "Enter new phone:\n";
std::string phone;
std::cin >> phone;
data[id].set_phone(phone);
std::cout << "Done\n";
}
else {
std::cerr << "Wrong choice.\n";
}
}
};
class View {
public:
std::vector<Contact> data;
void print_contact_data(Contact data) {
std::cout << data.get_name() << ' ' << data.get_phone() << '\n';
}
void print_all_contacts() {
int curr = 1;
for (auto x : data)
std::cout << curr++ << ". " << x.get_name()
<< ' ' << x.get_phone() << '\n';
}
Contact get_contact_data() {
Contact data;
std::cout << "Enter contact name:\n";
std::string name;
std::cin >> name;
std::cout << "Enter contact phone:\n";
std::string phone;
std::cin >> phone;
data.set_name(name);
data.set_phone(phone);
return data;
}
void main_menu() {
enum { ADD = 1, DELETE = 2, EDIT = 3,
SEARCH = 4, PRINT = 5, EXIT = 6 };
std::cout << "1. Add contact\n";
std::cout << "2. Delete contact\n";
std::cout << "3. Edit contact\n";
std::cout << "4. Search contact\n";
std::cout << "5. Print all contacts\n";
std::cout << "6. Exit\n";
int choice;
std::cin >> choice;
Controller temp;
if (choice == ADD) {
temp.add_contact(get_contact_data(), data);
} else if (choice == DELETE) {
temp.delete_contact(data);
} else if (choice == EDIT) {
temp.edit_contact(data);
} else if (choice == SEARCH) {
temp.search_contact(data);
} else if (choice == PRINT) {
print_all_contacts();
} else if (choice == EXIT) {
exit(0);
} else {
std::cout << "Wrong choice\n";
}
}
};
int main() {
View v;
v.main_menu();
return 0;
}
I've tried to implement MVC design pattern. Basically, this is a basic contact management system. One can add, delete, edit, search contacts. View class is responsible for user manipulation and interacts with the user. The contact class is just the model. I'm getting this error message "'View v' has incomplete type and cannot be defined". I've searched for some solutions but couldn't find what my error is.
You have the following code structure:
class Contact;
class Controller;
class View;
class Controller {
public:
// ...
void search_by_id(std::vector<Contact> &data, int id) {
// ...
View v;
// ...
}
// ...
};
class View {
public:
// ...
void main_menu() {
// ...
Controller temp;
// ...
}
// ...
};
This gives an error because View v; requires View to be defined. Moving the definition of View to before Controller won't solve the issue because Controller temp; would have the same issue.
The simple fix is to move all the function definitions outside the class, and after the other classes have been defined:
class Controller {
public:
// ...
void search_by_id(std::vector<Contact> &data, int id);
// ...
};
class View {
public:
// ...
void main_menu();
// ...
};
void View::main_menu() {
// ...
Controller temp;
// ...
}
void Controller::search_by_id(std::vector<Contact> &data, int id) {
// ...
View v;
// ...
}

How can I implement a linked list and allow users to choose a specific node to remove with C++?

I've spent pretty much all day trying to do this, I understand pointers and what a linked list does, but I don't know how to actually code it and all I've found are Java and C examples which don't help because I'm using C++.
Thanks in advance for taking a look at my code and helping me, I really appreciate it considering how many days I've spent stressed out and confused about this. I'm not going to lie so far most of my deleteNode function is probably trash. But like I've said I'm just lost I don't even know where to start or how to progress because I only understand the concepts.
This is my data file.
John Doe 80
Jane Smith 70
Bill Jones 50
Pat Hughes 90
Sam Sosa 40
This is my Header file
#include<string>
using namespace std;
class student {
public:
student(); // constructor method
void st_fn(string fn);
string st_fn();
void st_ln(string ln);
string st_ln();
void st_score(float s);
float st_score();
string st_pass_or_fail();
// need a pointer to the next object
student *nxt_ptr;
protected: // protected can be inherited
float m_score;
string m_ln;
string m_fn;
string m_pf_msg;
};
student::student() //constructor
{
nxt_ptr = NULL;
m_score = 0;
}
void student::st_fn(string fn)
{
m_fn = fn;
}
string student::st_fn()
{
return m_fn;
}
void student::st_ln(string ln)
{
m_ln = ln;
}
string student::st_ln()
{
return m_ln;
}
void student::st_score(float s)
{
m_score = s;
}
float student::st_score()
{
return m_score;
}
string student::st_pass_or_fail()
{
if (m_score >= 60)
m_pf_msg = "PASSED";
else
m_pf_msg = "FAILED";
return m_pf_msg;
}
This is my .cpp file.
#include<iostream>
#include<string>
#include<fstream>
#include "Header.h"
using namespace std;
int display_menu()
{
int option;
cout << endl << endl;
cout << "1. Display List" << endl;
cout << "2. Add a student" << endl;
cout << "3. Delete first student" << endl;
cout << "4. Search by Last Name" << endl;
cout << "5. Exit" << endl;
cin >> option;
return option;
}
student * search_last_name(student *h)
{
student *f = NULL;
student *t = NULL;
string s_ln;
// prompt for last name to search for
cout << "Enter Last Name of the Student";
cin >> s_ln;
if (h != NULL)
{
t = h;
while (t != NULL)
{
if (t->st_ln() == s_ln)
f = t; // found the last name so save t
t = t->nxt_ptr;
}
}
else
cout << "List is empty" << endl;
return f;
}
void add_student(student *&head) // h is the head of the list
{
student *new_st, *r;
string fn, ln;
float s;
cout << "Enter new students first name, last name and score";
cin >> fn >> ln >> s;
// instantiate a new node, use new_st
new_st = new student;
new_st->st_fn(fn);
new_st->st_ln(ln);
new_st->st_score(s);
if (head == NULL)
head = new_st;
else
{
// find the last node, use r for this
// write code
r = head;
while (r->nxt_ptr != nullptr)
r = r->nxt_ptr;
// add to the back of the list
// write code
r->nxt_ptr = new_st;
} // end of else
} // end of add student
student * delete_front(student * head)
{
student *t;
// delete front node
// check for empty list
if (head != NULL)
{
// delete first node
t = head;
head = head->nxt_ptr;
delete(t);
}
else
cout << "List is empty - nothing to delete" << endl;
return head;
}
void deleteNode(struct Node *head, struct Node *n)
{
// When node to be deleted is head node
if (head == n)
{
n = head->next;
//Remove the link of next node
head->next = head->next->next;
return;
}
//When not first node, folow the normal deletion process
//Find the previous node
struct Node *prev = head;
while (prev->next != NULL && prev->next != n)
prev = prev->next;
// Check if node really exists in Linked List
if (prev->next == NULL)
{
cout << endl << "Given node is not present in Linked List";
return;
}
//Remove node from linked list should it exist
prev->next = prev->next->next;
return;
}
void display_list(student *t)
{
if (t == NULL)
cout << "List is Empty!";
else
{
while (t != NULL)
{
cout << "******Student******" << endl;
cout << t->st_ln() << endl;
cout << t->st_fn() << endl;
cout << t->st_score() << endl << endl;
t = t->nxt_ptr;
}
}
}
int main()
{
string ln, fn;
float s;
int n;
ifstream infile;
student *head = NULL; //pointer to a student object
student *cp = NULL; // pointer to end of the list
student *new_st = NULL; // pointer to a new student object
student *f = NULL; // pointer to found node
int option; // the numbe of menu item the user selects
infile.open("lab8d.txt");
while (!infile.eof())
{
infile >> fn >> ln >> s;
//instantiate a student object
new_st = new student;
//load the object with data
new_st->st_fn(fn);
new_st->st_ln(ln);
new_st->st_score(s);
// check for empty list - its a special case
if (head == NULL)
{
head = new_st;
cp = new_st;
}
else // list is not empty
{
cp->nxt_ptr = new_st;
cp = new_st;
}
} // end of loop
// loop to give the user some options
option = display_menu();
while (option != 5)
{
if (option == 1)
display_list(head);
else if (option == 2)
add_student(head);
else if (option == 3)
head = delete_front(head);
else if (option == 4)
{
f = search_last_name(head);
if (f != NULL)
{
cout << f->st_fn() << endl;
cout << f->st_ln() << endl;
cout << f->st_score() << endl;
cout << f->st_pass_or_fail() << endl;
}
else
cout << "Name not in the list" << endl;
}
else if (option == 6)
{
cout << "Enter the number of the node you would like to delete: " << endl;
cin >> n;
}
option = display_menu();
}
system("pause");
return 0;
}
The simpler and self-contained your functions are, the easier they are to test and debug, and the less like they are to fail.
Try something more like this:
Student.h:
#include <string>
class student_list;
class student
{
public:
student();
student(const std::string &fn, const std::string &ln, float s, student *nxt = NULL);
void next(student *s);
student* next() const;
void firstName(const std::string &fn);
std::string firstName() const;
void lastName(const std::string &ln);
std::string lastName() const;
void score(float s);
float score() const;
std::string pass_or_fail() const;
void display(bool showPassOrFail = false) const;
friend class student_list;
protected: // protected can be inherited
student *m_next;
std::string m_fn;
std::string m_ln;
float m_score;
};
Student.cpp:
#include "Student.h"
#include <iostream>
student::student()
: m_next(NULL), m_score(0)
{
}
student::student(const std::string &fn, const std::string &ln, float s, student *nxt)
: m_next(nxt), m_fn(fn), m_ln(ln), m_score(s)
{
}
void student::next(student *s)
{
m_next = s;
}
student* student::next() const
{
return m_next;
}
void student::firstName(const std::string &fn)
{
m_fn = fn;
}
std::string student::firstName() const
{
return m_fn;
}
void student::lastName(const std::string &ln)
{
m_ln = ln;
}
std::string student::lastName() const
{
return m_ln;
}
void student::score(float s)
{
m_score = s;
}
float student::score() const
{
return m_score;
}
std::string student::pass_or_fail() const
{
if (m_score >= 60)
return "PASSED";
else
return "FAILED";
}
void student::display(bool showPassOrFail) const
{
std::cout << lastName() << std::endl;
std::cout << firstName() << std::endl;
std::cout << score() << std::endl;
if (showPassOrFail)
std::cout << pass_or_fail() << std::endl;
}
StudentList.h:
#include <string>
class student;
class student_list
{
public:
student_list();
~student_list();
student* search_last_name(const std::string &ln);
student* insert(const std::string &fn, const std::string &ln, float s, student* after = NULL);
bool remove(int idx);
void display() const;
private:
student *m_head;
};
StudentList.cpp:
student_list::student_list()
: m_head(NULL)
{
}
student_list::~student_list()
{
while (m_head)
remove(0);
}
student* student_list::search_last_name(const std::string &ln)
{
student *t = m_head;
while (t)
{
if (t->lastName() == ln)
break; // found the last name
t = t->next();
}
return t;
}
student* student_list::insert(const std::string &fn, const std::string &ln, float s, student* after)
{
student **r;
if (after)
{
// add to list after the specified node
// get pointer to next node
r = &(after->m_next);
}
else
{
// add to the back of the list
// find pointer to last node
r = &m_head;
while (*r)
r = &((*r)->m_next);
}
// instantiate a new node
student *new_st = new student(fn, ln, s);
if (after)
new_st->next(*r);
// add to list
*r = new_st;
return new_st;
}
bool student_list::remove(int idx)
{
// delete a node at index
// find pointer to node
student **r = &m_head;
while ((*r) && (idx-- > 0))
r = &((*r)->m_next);
if (*r)
{
// delete node
student *t = *r;
*r = t->next();
delete t;
return true;
}
return false;
}
void student_list::display() const
{
student *t = m_head;
if (!t)
std::cout << "List is Empty!" << std::endl;
else
{
do
{
std::cout << "******Student******" << std::endl;
t->display();
t = t->next();
}
while (t);
}
}
Main.cpp:
#include "Student.h"
#include "StudentList.h"
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <limits>
#include <cstdlib>
int read_number()
{
int value;
while (!(std::cin >> value))
{
std::cout << "Must be a number, try again: ";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
return value;
}
int display_menu()
{
int option;
std::cout << std::endl << std::endl;
std::cout << "1. Display List" << std::endl;
std::cout << "2. Add a student" << std::endl;
std::cout << "3. Delete first student" << std::endl;
std::cout << "4. Search by Last Name" << std::endl;
std::cout << "5. Delete student by index" << std::endl;
std::cout << "6. Exit" << std::endl << std::endl;
std::cout << "Choice: ";
do
{
option = read_number();
if ((option >= 1) && (option <= 6))
break;
std::cout << "Must be 1..6, try again: ";
}
while (true);
return (option != 6) ? option : -1;
}
int main()
{
student_list students;
std::ifstream infile("lab8d.txt");
if (infile.is_open())
{
student *cp = NULL;
std::string ln, fn;
float s;
while (infile >> fn >> ln >> s)
cp = students.insert(fn, ln, s, cp);
infile.close();
}
// loop to give the user some options
int option; // the number of menu item the user selects
while ((option = display_menu()) != -1)
{
switch (option)
{
case 1:
{
students.display();
break;
}
case 2:
{
// prompt for student info
std::string info;
std::cout << "Enter new student's first name, last name, and score: ";
std::string ln, fn;
float s;
if (std::cin >> fn >> ln >> s)
students.insert(fn, ln, s);
break;
}
case 3:
{
if (!students.remove(0))
std::cout << "List is empty" << std::endl;
break;
}
case 4:
{
// prompt for last name to search for
std::string ln;
std::cout << "Enter Last Name of the Student: ";
if (std::cin >> ln)
{
student *f = students.search_last_name(ln);
if (f)
f->display(true);
else
std::cout << "Name not found in List" << std::endl;
}
break;
}
case 5:
{
std::cout << "Enter the index of the Student to Delete: " << std::endl;
int idx = read_number();
if (!students.remove(idx))
std::cout << "Index not found in List" << std::endl;
break;
}
}
}
std::system("pause");
return 0;
}
That being said, you really should be using the std::list container instead, eg:
Student.h:
#include <string>
class student_list;
class student
{
public:
student();
student(const std::string &fn, const std::string &ln, float s);
void firstName(const std::string &fn);
std::string firstName() const;
void lastName(const std::string &ln);
std::string lastName() const;
void score(float s);
float score() const;
std::string pass_or_fail() const;
void display(bool showPassOrFail = false) const;
friend class student_list;
protected: // protected can be inherited
std::string m_fn;
std::string m_ln;
float m_score;
};
Student.cpp:
#include "Student.h"
#include <iostream>
student::student()
: m_score(0)
{
}
student::student(const std::string &fn, const std::string &ln, float s)
: m_fn(fn), m_ln(ln), m_score(s)
{
}
void student::firstName(const std::string &fn)
{
m_fn = fn;
}
std::string student::firstName() const
{
return m_fn;
}
void student::lastName(const std::string &ln)
{
m_ln = ln;
}
std::string student::lastName() const
{
return m_ln;
}
void student::score(float s)
{
m_score = s;
}
float student::score() const
{
return m_score;
}
std::string student::pass_or_fail() const
{
if (m_score >= 60)
return "PASSED";
else
return "FAILED";
}
void student::display(bool showPassOrFail) const
{
std::cout << lastName() << std::endl;
std::cout << firstName() << std::endl;
std::cout << score() << std::endl;
if (showPassOrFail)
std::cout << pass_or_fail() << std::endl;
}
Main.cpp:
#include "Student.h"
#include <list>
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <limits>
#include <algorithm>
#include <cstdlib>
int read_number()
{
int value;
while (!(std::cin >> value))
{
std::cout << "Must be a number, try again: ";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
return value;
}
int display_menu()
{
int option;
std::cout << std::endl << std::endl;
std::cout << "1. Display List" << std::endl;
std::cout << "2. Add a student" << std::endl;
std::cout << "3. Delete first student" << std::endl;
std::cout << "4. Search by Last Name" << std::endl;
std::cout << "5. Delete student by index" << std::endl;
std::cout << "6. Exit" << std::endl << std::endl;
std::cout << "Choice: ";
do
{
option = read_number();
if ((option >= 1) && (option <= 6))
break;
std::cout << "Must be 1..6, try again: ";
}
while (true);
return (option != 6) ? option : -1;
}
int main()
{
std::list<student> students;
std::ifstream infile("lab8d.txt");
if (infile.is_open())
{
std::string ln, fn;
float s;
while (infile >> fn >> ln >> s)
students.push_back(student(fn, ln, s));
infile.close();
}
// loop to give the user some options
int option; // the number of menu item the user selects
while ((option = display_menu()) != -1)
{
switch (option)
{
case 1:
{
if (students.empty())
std::cout << "List is Empty!" << std::endl;
else
{
for(const auto &s : students)
{
std::cout << "******Student******" << std::endl;
s.display();
}
}
break;
}
case 2:
{
// prompt for student info
std::string info;
std::cout << "Enter new student's first name, last name, and score: ";
std::string ln, fn;
float s;
if (std::cin >> fn >> ln >> s)
students.push_back(student(fn, ln, s));
break;
}
case 3:
{
if (students.empty())
std::cout << "List is empty" << std::endl;
else
students.erase(students.begin());
break;
}
case 4:
{
// prompt for last name to search for
std::string ln;
std::cout << "Enter Last Name of the Student: ";
if (std::cin >> ln)
{
auto f = std::find(students.begin(), students.end(),
[&](const student &s){ return (s.lastName() == ln); }
);
if (f != students.end())
f->display(true);
else
std::cout << "Name not found in List" << std::endl;
}
break;
}
case 5:
{
std::cout << "Enter the index of the Student to Delete: " << std::endl;
int idx = read_number();
if ((idx < 0) || (idx >= students.size()))
std::cout << "Index not found in List" << std::endl;
else
students.erase(std::next(students.begin(), idx));
break;
}
}
}
std::system("pause");
return 0;
}

Error while using pointers and new operators in C++(Microsoft VS)

i was using pointers and new operator for printing different city names. But the Microsoft Visual Studio show that it is Exception thrown:read access violation.
This happen even when i write *ptr=n; or *ptr=20; ,but works properly if i give ptr=&n; (if n is the variable with some value).
Program to display names of cities
#include <iostream>
#include <cstring>
using namespace std;
class city
{
protected:
char *name;
int len;
public:
char *s;
city();
~city();
void getdata()
{
s = new char[20];
cout << "enter the name of city" << endl;
cin >> s;
len = strlen(s);
name = new char[len + 1];
strcpy_s(name, 10, s);
}
void display()
{
cout << *name << endl;
}
private:
};
city::city()
{
len = 0;//initialization
name = NULL;
}
city::~city()
{
delete[]name;
delete[]s;
}
int main()
{
city *obj[10];
int n = 0;
int en=0;
do
{
obj[n] = new city;
obj[n]->getdata();
n++;
obj[n]->display();
cout << "do you want to enter another city?" << endl;
cout << "(enter 1 for yes and 0 for no"<<endl;
cin >> en;
} while (en);
delete[]obj;
system("pause");
return 0;
}
Screenshot of error
Don't manage memory manually! Use STL to forget memory manage!
#include <iostream>
#include <string>
#include <array>
class city
{
protected:
std::string name;
public:
city() = default;
//~city();
void getdata()
{
std::cout << "enter the name of city" << std::endl;
std::cin >> this->name;
}
void display()
{
std::cout << name << std::endl;
}
};
int main()
{
std::array<city, 10> obj;
for(auto&& o : obj)
{
o.getdata();
o.display();
std::cout
<< "do you want to enter another city?" << std::endl
<< "(enter 1 for yes and 0 for no" << std::endl;
int en=0;
std::cin >> en;
if(0 == en) return 0;
}
return 0;
}
https://wandbox.org/permlink/bz4iF3LNDSyUIZPb