c++ program printing out address instead of value - c++

I have a program that takes in information through a struct and puts it into a vector, and I'm trying to print that information out but instead get an address. The structure should hold the values correctly so I think it's either my pointers or the way I'm printing it out.
#include <iostream>
#include <cstring>
#include<vector>
using namespace std;
struct student
{
char* fName;
char* lName;
int id;
float gpa;
};
void add(vector<student*>*);
int main()
{
vector <student*>* list = new vector<student*>();
if (strcmp(cmd,"ADD") == 0)
{
add(list);
}
else if (strcmp(cmd,"PRINT") == 0)
{
for(vector<student*>::iterator i = list->begin(); i != list->end(); i++)
{
cout << *i;
}
cout << "print" << endl;
}
}
void add(vector<student*>* paramlist)
{
student* s = new student();
s->fName = new char[25];
s->lName = new char[25];
cout << "Enter first name" << endl;
cin >> s->fName;
cout << "Enter last name" << endl;
cin >> s->lName;
cout << "Enter id number" << endl;
cin >> s->id;
cout << "Enter GPA" << endl;
cin >> s->gpa;
paramlist->push_back(s);
}
Or it might have something to do with the way I iterate through the vector.

You need to add an operator overload for your struct, to define how the struct should appear when printed. You also need to dereference the pointer as well as the iterator.
// Define how the struct should look when printed.
// This function makes it appear like:
// Name: John Smith, ID: 1235, GPA: 4.0
std::ostream &operator<<(std::ostream &os, const student &val) {
os
<< "Name: " << val.fname << " " << val.lname
<< ", ID: " << val.id
<< ", GPA: " << val.gpa
<< endl;
return os;
}
Then later...
for(vector<student*>::iterator i = list->begin(); i != list->end(); i++)
{
// Dereference twice, once for the iterator, and again for the pointer.
cout << **i << endl;
}

You have to dereference twice **i.
With *i you get the address of vector<student*> element that is student*.
You get student, you need other *.
You may use for (auto i: list) to make your life easier.

Related

why can not I access the vector cars?

#include <iostream>
#include <vector>
using namespace std;
struct multa{
int data;
};
struct veiculos{
string placa;
vector<multa*> multas;
};
int tam = 0;
vector<veiculos*> carros;
void insereVeiculos(){
veiculos *carrosparaadd = new veiculos;
cout << "digite a placa do veiculo:" << endl;
cin >> carrosparaadd->placa;
carros.push_back(carrosparaadd);
cout << carros[].placa;
tam++;
}
void inseremultas(){
int cont = 0 ,i = 0;
cout << "Quantas multas vocĂȘ quer adicionar?" << endl;
cin >> cont;
for(i=0;i<cont;i++){
multa *multasparaadd = new multa;
cout << "Digite a data da multa para add:" << endl;
cin >> (*multasparaadd).data;
cout << (*multasparaadd).data;
carros[0]->multas.push_back(multasparaadd);
}
}
why can not I access the vector cars?
with carros[0].placa?I tested it and saw that it is getting the right value from the keyboard
Thanks.
Your expression
cout << carros[].placa;
lacks an index for the array access and since it's a vector of pointers you also need to dereference the accessed element. A correct expression which compiles is for example:
cout << carros[0]->placa;
If you want to print the element you just inserted, you can use either:
cout << carros.back()->placa;
or, since you're inserting a pointer, simply:
cout << carrosparaadd->placa;

How to Access a variable in a filestream loaded in list container

I am the new kid in the block, studying C++. I have loaded a file stream in a list container, using variables. I want to be able to access and change the value of any of those variables. I've been trying for weeks to no avail. Can somebody help?
This is the external text file: flightBoard1.txt
Delta 3431 Paris JFK
Usair 2275 EWR London
Delta 1500 Bonn Milan
This is the main.cpp
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <list>
using namespace std;
template<class T, class U, class V>
void changeFlight(list<string> &myFlight, T loc, U value, V newVal);
int main()
{
string _company;
int _flight;
string _origin;
string _destination;
list<string> flightBoard;
stringstream *ssPtr;
int counter = 0;
ifstream myFile("flightBoard1.txt");
while(myFile >> _company >> _flight >> _origin >> _destination ){
++counter;
ssPtr = new stringstream; // you want to put each line in a different slot in the flightBoard list object
*ssPtr << counter << " " << _company << "\t" << _flight << "\t" << _origin << "\t" << _destination << endl;
flightBoard.push_back(ssPtr->str()); // You need an arrow, this is a pointer
}
list<string>::iterator it;
for(it = flightBoard.begin(); it != flightBoard.end(); it++){
cout << *it ;
}
int oldFlight, newFlight;
cout << endl << "Enter old flight number: ";
cin >> oldFlight;
cout << "Enter new flight number: ";
cin >> newFlight;
changeFlight(flightBoard, ssPtr, oldFlight, newFlight);
delete ssPtr;
myFile.close();
return 0;
}
template<class T, class U, class V>
void changeFlight(list<string> &myFlight, T loc, U value, V newVal){
list<string>::iterator it;
cout << endl << "Flight: " << value << " has been changed to: " << newVal << endl;
for(it = myFlight.begin(); it != myFlight.end(); it++){
// THIS IS WHERE I AM HAVING A PROBLEM
// PLEASE UN-COMMENT BELOW TO SEE PROBLEM
/*if(it -> myFlight -> loc -> value){
value = newVal;
}*/
}
}
To solve your problem I think you should use the better structure for storage of your flights. string is not a good type if you need to manipulate data further. I suggest to introduce class Flight:
class Flight
{
public:
string company;
int flight;
string origin;
string destination;
Flight(const string& _company, int _flight, const string& _origin, const string& _destination)
: company(_company), flight(_flight), origin(_origin), destination(_destination)
{
}
string ToString() const
{
stringstream printer;
printer << company << "\t" << flight << "\t" << origin << "\t" << destination << endl;
return printer.str();
}
};
Also there are a number of problems in code snippet you have posted.
Memory leak inside while loop. You are allocating ssPtr = new stringstream; on each iteration, but delete it only once at the end.
changeFlight has too much template type arguments. If U value should be changed to V newVal inside changeFlight probably it should have the same types.
Hard to change type of flightBoard, list<string> copied everywhere. It's better to create typedef for list<string> type to make your code simpler. E.g. typedef list<string> FlightListType;.
Here is your code with all the mentioned problems fixed:
typedef list<Flight> FlightListType;
template<class T>
void changeFlight(FlightListType& myFlight, T value, T newVal);
int main()
{
string _company;
int _flight;
string _origin;
string _destination;
FlightListType flightBoard;
ifstream myFile("flightBoard1.txt");
while(myFile >> _company >> _flight >> _origin >> _destination )
{
flightBoard.push_back(Flight(_company, _flight, _origin, _destination));
}
FlightListType::const_iterator it;
int counter = 0;
for(it = flightBoard.begin(); it != flightBoard.end(); it++)
{
cout << counter << " " << (*it).ToString();
++counter;
}
int oldFlight, newFlight;
cout << endl << "Enter old flight number: ";
cin >> oldFlight;
cout << "Enter new flight number: ";
cin >> newFlight;
changeFlight(flightBoard, oldFlight, newFlight);
myFile.close();
return 0;
}
template<class T>
void changeFlight(FlightListType& myFlight, T value, T newVal)
{
FlightListType::iterator it;
cout << endl << "Flight: " << value << " has been changed to: " << newVal << endl;
for(it = myFlight.begin(); it != myFlight.end(); it++)
{
if ((*it).flight == value)
{
// TODO: Here you can do with the Flight what ever you need
// For example change it's number
(*it).flight = newVal;
}
}
}

Copy from one structure to another structure of different type

I am trying this piece of code in vs 2008
#include <stdio.h>
#include <iostream>
#include <string>
typedef struct _first
{
int age;
std::string name;
}first;
typedef struct _second
{
int age;
char name[20];
}second;
void copy_structure()
{
first s;
second f;
f.age = 15;
cout<<"Enter the name"<<endl;
fgets(f.name, 20, stdin);
memcpy(&s,&f,20);
cout << "Name: " << s.name << endl;
cout << "Age: "<< s.age << endl;
}
int main()
{
copy_structure();
return 0;
}
while building I didn't get any error but when I run, name field is empty over here
cout << "Name: " << s.name << endl;
I am not getting any output over here, can somebody help me to solve this issue.
You should use an approach based on member-wise copying. For example
void copy_structure()
{
first f;
^^
second s;
^^
s.age = 15;
cout<<"Enter the name"<<endl;
fgets(s.name, 20, stdin);
f.age = s.age;
f.name = s.name;
cout << "Name: " << f.name << endl;
cout << "Age: "<< f.age << endl;
}
Otherwise the internals of the object name of the type std::string will be overwritten and the program will have undefined behaviour.
This looks like C but not like C++... Your current code will also brick your std::string instance. memcpy is dangerous and should not be used, unless you have a very, very good reason. I never had a reason for this so far.
My suggestion:
#include <iostream>
#include <string>
using namespace std;
struct second
{
int age;
char name[20];
};
struct first
{
int age;
string name;
first& operator=(const second& rhs);
};
// some operator for copying
first& first::operator=(const second& rhs)
{
age = rhs.age;
name = rhs.name;
return *this;
}
int main()
{
first s;
second f;
f.age = 15;
cout << "Enter your name" << endl;
cin >> f.name;
s = f;
cout << "Name: " << s.name << endl;
cout << "Age: " << s.age << endl;
return 0;
}
This is improvable, of course. You would usually rather use classes than structs. And you would might also have an operator>> for second.

Trying to make string array passed through methods C++

I'm trying to read names and ages from user, until user inputs "stop". Then just print all these values. Please help me , I'm just the beginner in C++
// Pass.cpp
// Reading names and ages from user and outputting them
#include <iostream>
#include <iomanip>
#include <cstring>
using std::cout;
using std::cin;
using std::endl;
using std::setw;
using std::strcmp;
char** larger(char** arr);
int* larger(int* arr);
void read_data(char*** names, int** ages);
void print_data(char*** names, int** ages);
int main()
{
char** names = new char*[5];
char*** p_names = &names;
int* ages = new int[5];
int** p_ages = &ages;
read_data(p_names,p_ages);
print_data(p_names,p_ages);
}
void read_data(char*** names, int** ages)
{
const char* sent = "stop";
const int MAX = 15;
int count = 0;
char UI[MAX];
cout << "Enter names and ages."
<< endl << "Maximum length of name is " << MAX
<< endl << "When stop enter \"" << sent << "\".";
while (true)
{
cout << endl << "Name: ";
cin.getline(UI,MAX,'\n');
if (!strcmp(UI, sent))
break;
if (count + 1 > sizeof (&ages) / sizeof (&ages[0]))
{
*names = larger(*names);
*ages = larger(*ages);
}
*names[count] = UI;
cout << endl << "Age: ";
cin >> *ages[count++];
}
}
void print_data(char*** names, int** ages)
{
for (int i = 0; i < sizeof(*ages) / sizeof(*ages[0]);i++)
{
cout << endl << setw(10) << "Name: " << *names[i]
<< setw(10) << "Age: " << *ages[i];
}
}
char** larger(char** names)
{
const int size = sizeof(names) / sizeof(*names);
char** new_arr = new char*[2*size];
for (int i = 0; i < size; i++)
new_arr[i] = names[i];
return new_arr;
}
int* larger(int* ages)
{
const int size = sizeof(ages) / sizeof(*ages);
int* new_arr = new int[2 * size];
for (int i = 0; i < size; i++)
new_arr[i] = ages[i];
return new_arr;
}
You are really over complicating things.
Given the original problem:
Write a program that reads a number (an integer) and a name (less than
15 characters) from the keyboard. Design the program so that the data
is done in one function, and the output in another. Store the data in
the main() function. The program should end when zero is entered for
the number. Think about how you are going to pass the data between
functions
The problem wants you to think about passing parameters to functions. A simple solution would be:
#include "stdafx.h"
#include <iostream>
#include <iomanip>
using namespace std;
// Pass in a char array and an integer reference.
// These values will be modified in the function
void read_data(char name[], int& age)
{
cout << endl << "Age: ";
cin >> age;
cin.ignore();
cout << endl << "Name: ";
cin.getline(name, 16);
}
// Pass a const array and an int value
// These values will not be modified
void print_data(char const *name, int age)
{
cout << endl << setw(10) << "Name: " << name
<< setw(10) << "Age: " << age;
}
int main()
{
char name[16];
int age;
cout << "Enter names and ages."
<< endl << "Enter 0 age to quit.";
do {
read_data(name, age);
print_data(name, age);
} while (0 != age)
}
EDIT: Modified per user3290289's comment
EDIT2: Storing data in an array
// Simplify by storing data in a struct (so we don't have to manage 2 arrays)
struct Person {
char name[16];
int age;
};
// Returns how many People were input
int read_data(Person*& arr)
{
int block = 10; // How many persons to allocate at a time
arr = NULL;
int arr_size = 0;
int index = 0;
while (true) {
if (index == arr_size) {
arr_size += block;
arr = (Person *)realloc(arr, arr_size * sizeof(Person)); // Reallocation
// Should check for error here!
}
cout << endl << "Age: ";
cin >> arr[index].age;
cin.ignore();
if (0 == arr[index].age) {
return index;
}
cout << endl << "Name: ";
cin.getline(arr[index++].name, 16);
}
}
void print_data(Person *arr, int count)
{
for (int i = 0; i < count; i++) {
cout << endl << setw(10) << "Name: " << arr[i].name
<< setw(10) << "Age: " << arr[i].age;
}
}
int main()
{
Person *arr;
int count = read_data(arr);
print_data(arr, count);
free(arr); // Free the memory
}
try this:
#include <iostream>
#include <iomanip>
#include <vector>
#include <sstream>
using std::cout;
using std::cin;
using std::endl;
using std::setw;
using std::strcmp;
void read_data(std::vector<std::string> &names, std::vector<int> &ages);
void print_data(std::vector<std::string> &names, std::vector<int> &ages);
int main()
{
std::vector<std::string> names;
std::vector<int> ages;
read_data(names, ages);
print_data(names, ages);
}
void read_data(std::vector<std::string> &names, std::vector<int> &ages)
{
const char* sent = "stop";
cout << "Enter names and ages."
<< endl << "When stop enter \"" << sent << "\".";
while (true)
{
std::string input;
cout << endl << "Name: ";
std::getline(cin, input);
if (!strcmp(input.c_str(), sent))
break;
names.push_back(input);
cout << endl << "Age: ";
std::string age;
std::getline(cin, age);
ages.push_back(atoi(age.c_str()));
}
}
void print_data(std::vector<std::string> &names, std::vector<int> &ages)
{
for (int i = 0; i < names.capacity() ; i++)
{
cout << endl << setw(10) << "Name: " << names.at(i)
<< setw(10) << "Age: " << ages.at(i);
}
}
One problem I see is this if statement:
if (count + 1 > sizeof (&ages) / sizeof (&ages[0]))
&ages is the address of an int**, a pointer, and so it's size is 8 (usually) as that is the size of a pointer type. The function does not know the size of the array, sizeof will only return the correct answer when ages is declared in the same scope.
sizeof(&ages) / sizeof(&ages[0])
will always return 1
I believe one natural solution about this problem is as follows:
create a "std::map" instance. Here std::map would sort the elements according to the age. Here my assumption is after storing the data into the container, you would like to find about a particular student age/smallest/largest and all various manipulation with data.Just storing and printing the data does not make much sense in general.
create a "std::pair" and take the both input from the user into the std::pair "first" and "second" member respectively. Now you can insert this "std::pair" instance value into the above "std::map" object.
While printing, you can now fetch the each element of "std::map" in the form of "std::pair" and then you can display pair "first" and "second" part respectively.

Setting a string value to none when a class related to it is deleted

I need help with something which I believe is simple. I can assign a student to a project. But when I delete the project, the student is still keeping the project name. I'm thinking of just renaming it back to "None" but I have no idea on how to do that. Help?
Edit
map<int, Student> mstore and vector<int> storeid added.
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <map>
using namespace std;
class Human {
public:
virtual void print() const = 0;
};
class Student : public Human {
protected:
string studname;
int studId;
string project;
public:
Student();
Student (string studname, int studId) : studname("Unknown"), studId(0), project("None")
{
cout << "A student is created: Name = " << studname
<< ". Id = " << studId << endl;
}
virtual void print() const {
cout << "Name = " << studname << ". Id = " << studId << ". Project = " << project <<endl; }
void setSName (string sname) { studname = sname; }
void setSID (int sID) { studId = sID; }
void printStudentInfo() const;
void printStudentInfoline() const;
};
void Student::printStudentInfo() const
{
cout << "\nStudent name: " << studname << endl;
cout << "Student ID: " << studId << endl;
cout << "Project: " << project << endl;
}
void Student::printStudentInfoline() const
{
cout << studId << ", " << studname << ", " << project << endl;
}
class Project {
protected:
string projname;
public:
vector <Student> students;
vector <int> storeid;
Project (string projname) : projname(projname) { cout << "Project " << projname << " created" << endl;}
void setPName (string projname) { this->projname = projname; }
void add (int& sid)
{
//student.setProject (projname);
storeid.push_back(sid);
}
int returnid(int& a)
{
return storeid[a];
}
int returnsize()
{ return storeid.size(); }
void printproj() const {
cout << endl << projname << " list: \n";
cout << "Student(s) : " << endl;
for (int i = 0; i < storeid.size(); i++){
cout << storeid[i] << endl;
}
}
void printprojname() const {
cout << projname << endl;
}
};
int main() {
string StudentName;
string ProjectName;
int Studentid;
Student *s1;
Project *p1;
vector<Student> store;
vector<Project> projstore;
map<int, Student> mstore;
map<int, Student>::const_iterator itr;
for (int n=0; n<3; n++) //loop to create 3 students
{
cout <<"Enter name : ";
getline(cin, StudentName);
cout <<"Enter ID : ";
cin >> Studentid;
s1 = new Student(StudentName, Studentid);
s1->setSName(StudentName);
s1->setSID(Studentid);
store.push_back(*s1);
mstore.insert(make_pair(Studentid, *s1));
cin.get();
}
//print map
for(itr=mstore.begin(); itr!=mstore.end() ;++itr)
itr->second.printStudentInfo();
//itr=mstore.begin()+2;
//itr.print();
cout << "Enter project name: ";
getline(cin, ProjectName);
p1 = new Project(ProjectName);
p1->setPName(ProjectName);
//Assigning student to project
cout << endl;
cout << "How many students? :" ;
int y;
cin >> y;
for ( int i = 0; i < y; i++){
cout << "Who would you like to add to this project?" << endl;
int x = 1;
for(itr=mstore.begin(); itr!=mstore.end() ;++itr)
itr->second.printStudentInfoline();
int insID;
cout << "Enter ID number: ";
cin >> insID;
p1->add(insID);
/*
for ( it = store.begin(); it != store.end(); ++it ) {
// For each friend, print out their info
cout << x << ". ";
it->printStudentInfoline();
x++;
}
x = 1;
int insS;
cout << "Enter number: ";
cin >> insS;
p1->add(store[(insS-1)]); //stores selected student into the object
*/
cout << "\nAdding Student done\n" << endl;
}
projstore.push_back(*p1);
//Mstore finds for related ids and displays them accordingly
cout << "print project"<< endl;
vector<Project>::iterator pt;
for ( pt = projstore.begin(); pt != projstore.end(); ++pt ) {
pt->returnsize();
for (int i=0; i <pt->returnsize(); i++){
cout << pt->returnid(i) << endl;
itr=mstore.find(pt->returnid(i));
itr->second.printStudentInfo();
}
}
cout << endl;
cout << "Deleting project" << endl;
cout << "What would you like to remove?" << endl;
int x = 1;
//storeid will display ids. How do I link them to `store` map?
for ( pt = projstore.begin(); pt != projstore.end(); ++pt ) {
cout << x << ". ";
pt->printprojname();
x++;
}
//Now to delete the selected project
int delP;
cout << "Enter number: ";
cin >> delP;
cin.ignore();
system("pause");
projstore.erase(projstore.begin()+delP-1);
// Students
cout << "\n Current students" << endl;
for(itr=mstore.begin(); itr!=mstore.end() ;++itr)
itr->second.printStudentInfo();
}
Look at how you add a Student to a Project:
void add (Student& student)
{
student.setProject (projname);
students.push_back (student); // <-- AHA!
}
First you assign the Project name to the Student, then the Project stores a copy of the Student. After that, the Project has no link to the original Student, and can't inform him/her of its own demise when the time comes.
You'll have to rethink this design; there are three major options: 1) the Students can look up their respective Projects in the store, 2) the Project can look up its Students in the students vector, or 3) the Project owns the Students (in which case they should probably be GraduateStudents).
EDIT:
If that's the way you want to do it, use map<int, Student> store to store the Students, using ID number as an index. Then a Project can have a vector<int> (or set<int>) of student ID numbers. It can look Students up in the store with ease.
EDIT:
To print out the entire collection of students:
for(map<int, Student>::const_iterator itr=store.begin(); itr!=store.end() ;++itr)
itr->second.print();
EDIT:
If the Project has a vector<int> of student ID numbers, then what argument do you think Project::add(?) should take?
EDIT:
The Project can act on a Student by means of the student ID number and access to mstore:
// in Project:
mstore[id].whatever()
EDIT:
Sometimes asking the right question -- or in this case, phrasing the question correctly -- is half the battle. 'Now how do I change "None" to the inserted project name?' A better way to put it is 'How does the Project change one of its Student's project from "None" to projname?' Once you put it that way, the answer is almost obvious:
// in Project:
mstore[id].setSProject(projname);
Note that Student does not yet have setSProject(string), you'll have to add it. Also, note that this solution is not ideal since 1) anybody can change a Student's project, and 2) a Student's project need not actually be the name of a real Project. There is more than one way to deal with these problems.