Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 9 years ago.
Improve this question
I wrote a code that works fine. I just want extra eyes to highlight every thing that should/could be improved. I have to create a student.dat file, and write data (name, age, gpa of each student) given by a user, then close it, and reopen it for reading then, displaying the gpa of students. The Student is a Class object. I just want to check where I am with the notion of OOP (at least with that problem). I am using Dev-C++. The code is below:
#include <iostream>
#include <conio.h>
#include <fstream>
#include <string>
#include <iomanip>
#define W setw
using namespace std;
class Student
{
private:
char name[40];
int age;
double GPA;
public:
Student(){};
void read();
void show(char* ,int ,double );
int writefile(ofstream &OS);
double getgpa(double*, int );
void readfile();
};
void Student::read(void)
{
int nbrSt=0;
cout<<"Please enter the information of the student: "<<endl;
cout<<"'y' to Continue, Ctrl+Z to exit! "<<endl;
cout<<"Name, Age and GPA:\n";
ofstream OS("student.dat", ios::out);
while (cin>>name>>age>>GPA)
{
//writing in the file
writefile(OS);
nbrSt++; //increment the number of students
cout<<"Name, Age and GPA:\n";
}
OS.close();
}
int Student::writefile(ofstream & OS)
{
OS<<'\n'<<W(10)<<name<<W(6)<<age<<W(10)<<GPA;
return 0;
}
void Student::show(char* Name, int Age, double gpa)
{
cout<<'\n'<<W(10)<<Name<<W(6)<<Age<<W(8)<<gpa<<endl;
}
double Student::getgpa(double* allGPA, int nbrgpa)
{
double sum=0;
int i =0;
for ( i=0;i<nbrgpa; i++)
sum+=allGPA[i];
if(nbrgpa>0)
return sum/nbrgpa;
}
void Student::readfile()
{
char Name[30];
int Age;
double aveGPA, gpa;
int nbrgpa=0;
double allGPA[50];
int i=0;
ifstream IS("Student.dat", ios::in);
cout<<"reading from Binary file"<<endl;
if (IS.is_open())
while(IS>>Name>>Age>>gpa)
{
nbrgpa++;
show(Name, Age, gpa);
allGPA[i]=gpa;
i++;
}
IS.close();
aveGPA=getgpa( allGPA, nbrgpa);
cout<<"Average GPA of students: "<<aveGPA<<endl;
}
int main(void)
{
Student S;
S.read();
S.readfile();
return 0;
}
Student(){};
is illegal syntax
Student(){}
is correct.
void Student::read(void)
is badly designed. Student::read should be a method which reads one student. The reading of multiple stduents and the writing of students should be in other functions or methods.
int Student::writefile(ofstream & OS)
should be
int Student::writefile(ostream & OS)
so it works with all kinds of streams (not just file streams). Obviously you should then rename the method. Just call it write for instance.
double Student::getgpa(double* allGPA, int nbrgpa)
should not be a member of Student, it should be a global function.
Your main issue is object-orientated design. You shouldn't just add everything to the Student class without thinking about what you are doing. Methods in the Student class should be about one student, methods that read or write one Student for instance. Everything else should be in global functions (or in other classes if you add a second class to your program).
I just want extra eyes to highlight every thing that should/could be improved.
#define W setw
Don't do that. You may think it makes code using setw look simpler, but other people looking at your code will have to search for what W resolves to.
using namespace std;
Don't declare using namespace std globally. It's not a big problem in small projects, but it makes the code more difficult to reuse.
The interface of your class is non-standard. Consider reading by creating ostream << student operator and reading by creating 'istream >> student'. This respects the rule of least surprise and enables you to (for example) read a sequence of students using iteration.
You need much better function names:
Your read function writes to a file. It would be a big WTF moment for me to see that in production code. Either change the name, or change the functionality.
Your read function is called on a student instance (Student s; s.read();) but it doesn't work on an instance. It in fact transfers/stores a set of records from cin to a file, and sets the instance it is called on, to the last record. If the reading fails half way through the data (i.e. cin>>name>>age>>GPA gets the name correctly but not the age or GPA) it leaves the instance it is called on, in an invalid state.
Consider moving your code from char name[40]; and double* allGPA, int nbrgpa to std::string and std::vector<double> respectively. Using raw data is error-prone and unnecessarily complicated.
There's a lot more to be said, but I think I've given you enough :-).
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
For my assignment I have to make a program to read student data from standard input, sort it by last name / first name, and print out the result to standard output. Students consists of a last name, first name, and a grade point average. It says to there are no more than 50 students.
It also says you should not rely on an external library function to do the sort.
Here is the example:
Ware Henry 87.2
Dantes Edmond 91.4
Earhart Amelia 92.6
Here is how it should be sorted:
Dantes Edmond 91.4
Earhart Amelia 92.6
Ware Henry 87.2
Here is the code I have so far that is not working properly:
#include <iostream>
#include <string>
using namespace std;
class student
{
public:
student();
void input();
void output();
void sort();
private:
string Fname;
string Lname;
float gpa;
}
student::student()
{
Fname = "";
Lname = "";
gpa = 0;
}
void student::input()
{
cout << "Enter first name, last name, and gpa"<<endl;
cin >> Fname >> Lname >> gpa;
}
void student::sort()
{
char temp;
int count = 0;
int i = 1;
while (i < word.size()) {
if (word[i - 1] > word[i]) {
temp = word[i];
word[i] = word[i + 1];
word[i + 1] = temp;
i++;
if (i >= word.size())
{
alpha(word);
}
}
else
{
count++;
}
}
return word;
}
void main()
{
student.input();
}
Any advice on where I went wrong and any possible solutions?
your student class has member variables to hold only one student, you need 50 instances of class student.
then you should hold these instances in an array/vector (whatever for container you are allowed to use) I assume you need to use a raw array so something like this will do.
student* students = new student[50];
what you then need is a compare function in your class to be able to sort the array, the compare function knows the internals of your class and you can decide how you want to sort the list e.g. after surname.
the sort function could be inside your class declared as a static function or maybe more logically an external function since student is not a container of student instances.
don't forget to delete the array when done
delete [] students;
in real world problems you would use std containers and e.g. algorithm sort for this kind of work.
Your compiler must have told you that word and alpha used in sort method are undeclared identifiers and count is assigned but never used.
Solution: Never ever steal code from wild wild web without understanding what it does. You may take others' code as inspiration, but blind copy-paste is a big no-no.
To give you a next step: you haven't even stored your students, you just input one, how would you sort just one entry? Think (and code) what you should use to store them and start working from there on how to sort them.
Good luck.
There are several reasons why your code is not working, first reason is that your class definition needs semicolon ';' at the end to close it.
class student
{
public:
student();
void input();
void output();
void sort();
private:
string Fname;
string Lname;
float gpa;
}; //semicolon here
In your sort() method the variable word is used but never declared, coding is not magic, the variable must declared and initialized before it is used like in your code.
while (i < word.size()) { //word must be declared somewhere
Also, in the sort method, you call a function alpha(word), this function does not exist in your program.
The sort method is of type void, which means it will not return anything, yet you are trying to return a string.
Another problem with the sort method is that it is never called from anywhere and will never be run.
There is also a big problem here with the way you are trying to use your class. To use the methods of the class you first have to instantiate an object of that class, you can then access the methods of the class through the object like this:
int main()
{
student theStudent;
theStudent;
theStudent.input();
return 0;
}
Another fundamental problem is that you are only going to get data for one object like this, you need to store several objects in something like an array and then sort the objects in the array:
int main()
{
student students[5];
for (int i = 0; i < 5; i++)
{
student newStudent;
students[i] = newStudent;
newStudent.input();
}
sort(students);
delete[] students;
return 0;
}
Which brings us to the sort method. It would be wise to not do the sorting as a method of the student class, but as a function called from main instead (like in the example above), that way it is easy to sort the array of student objects from main.
These are a few advice to start with, i am not going to do your complete homework for you though, if you use google and some of your precious energy, i believe that you will succeed.
When i run this code, and open the .dat file in notepad/wordpad it shows some weird characters
#include<iostream>
#include<fstream>
using namespace std;
class Student
{
int rollno;
char name[20];
char div[20];
public:
void accept()
{
cout<<"enter rollno"<<endl;
cin>>rollno;
cout<<"Enter name"<<endl;
cin>>name;
cout<<"Enter div"<<endl;
cin>>div;
}
void write_rec()
{
ofstream f;
f.open("Student.dat",ios::binary|ios::app);
Student s;
s.accept();
f.write((char*)&s,sizeof(s));
f.close();
}
void display()
{
ifstream f;
Student s;
f.open("Student.dat",ios::binary|ios::in);
while(f.read((char*)&s,sizeof(s)))
s.show();
f.close();
}
void show()
{
cout<<rollno<<endl;
cout<<name<<endl;
cout<<div<<endl;
}
};
int main()
{
Student s;
s.write_rec();
s.display();
}
The code is getting compiled and run perfectly but when i open the "Student.dat" file it shows some weird characters
This line:
f.write((char*)&s,sizeof(s));
Is writing the raw binary bytes of your Student object into the file. If that's not the behavior you intended, you'll need to do something else, e.g. translate the member fields of your Student object (in particular the rollno variable, which is an int) into ASCII text strings and write those strings into the file instead.
on both places when you open file:
f.open("Student.dat",ios::binary|ios::app);
and:
f.open("Student.dat",ios::binary|ios::in);
you open as binary. try to remove this option.
as you can see here and here, these are platform specific behaviors.
take a look at this example
EDIT:
and, of course, as Jeremy observed, you have to write meaningful text to your file. on this line:
f.write((char*)&s,sizeof(s));
you are actually writing each byte (as (char*)) of your object. if you understand what you're doing, and that's what you want to observe, than ok. but maybe you should compare both outputs, from this method and from Jeremy's suggestion.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
For my upcoming project in my computer science class, we have to make a star wars quiz game. Here is the project description:
The file star_wars.txt contains characters' names and the episode they first appeared in (this is chronological based on the release date - 4,5,6,1,2,3). You will populate a vector called cast with the contents of star_wars.txt. The cast vector is of type Character. The class Character has attributes matching the star_wars.txt file: first name, last name, episode. The program will ask the user what episode the character first appeared in. Tell the user if they are correct or incorrect. Keep track of how many they get correct, and give them a ranking based on their score.
Example of star_wars.txt:
Admiral Ackbar 6
Lando Calrissian 5
etc...
How would I put this file into a vector and display only the first and last name when asking the question?
Here is what I have so far:
#include<iostream>
#include<vector>
#include<string>
#include<fstream>
using namespace std;
class Character
{
private:
int score;
int episode;
int guess;
public:
void readIn(vector<Character>&cast);
void readOut();
string first;
string last;
};
int main()
{
Character ch;
vector<Character> cast;
cout<<"Welcome to the star wars quiz! I will tell you a character and you have to tell me what episode they first appeared in. Lets play!"<<endl;
ch.readIn(cast);
cout<<ch.first<<endl;
return 0;
}
void Character::readIn(vector<Character>&cast)
{
ifstream myFile("star_wars.txt");
while ( !myFile.eof() )
{
myFile>>first;
}
}
I will only go over the reading in of the input. Displaying should be simple enough to figure out on your own.
What you can do is create an operator >> for your Character class:
#include <istream>
#include <string>
class Character
{
private:
int score;
int guess;
public:
friend std::istream& operator>>(std::istream& is, Character& ch);
std::string first;
std::string last;
int episode;
};
std::istream& operator>>(std::istream& is, Character& ch)
{
is >> ch.first >> ch.last >> ch.episode;
return is;
}
Once you have this, then you can use >> to input to a Character, like this:
int main()
{
Character ch;
cin >> ch;
}
Note that I moved the episode to the public section, but you should really have public get and set functions for these items, as well as place those members in the private section.
Also, you don't want a vector within the class. What you want to do is have a way to input the items into a vector from outside the class. You can do it the long way:
int main()
{
std::ifstream ifs("myinputfile.txt");
std::vector<Character> vCh;
while (ifs)
{
Character ch;
ifs >> ch; // read a line into ch
vCh.push_back(vCh); // add this to the vector
}
}
Or the sophisticated way:
#include <iterator>
//...
int main()
{
std::ifstream ifs("myinputfile.txt");
std::istream_iterator<Character> fileStart(ifs), fileEnd;
std::vector<Character> vCh(FileStart, fileEnd);
}
Here is a live example
Note that the above example shows an overloading of both operator >> and operator << for output. I won't go over every single line as to what it does, but you can do your own research as to what is being done.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I had the below C++ question in the recent interview but could not do. Please help.
Given a company structure where every employee reports to a superior, all the way up to the CEO, how would you print out all the employees that a particular individual oversees?
Write a method that implements this, given the below:
// Employee object contains a string denoting the.
// employee name, and an array containing
// employees who report to this employee
Employee {
String name;
Employee[] employees;
}
I have seen and understand the recursive function. But I have not encounter such a recursive object/structure like this one.
My new question is how can an object is created and initialized from this class/structure since it is recursive?
Thank you very much again.
With the information given it is very hard to answer (and question should probably be set on hold). Anyway...
I think a recursive approach is the answer. You need a function that can take a name, search the full employee list for that name and then call the function again for every employee in the local array. Something like:
void doit(Employee& e)
{
// Print e.name
// For each employee tmp in e.employees (i.e. local array)
doit(tmp);
}
Note - this requires that there are no loops in manager-employee arrays. If there is this will be an endless loop. So this is a dangerous approach.
EDIT:
This is added due to the comment from OP.
As indicated above the question is vague and doesn't really give sufficient information to provide a good answer. The struct given in the question is not valid C++ and there is no description of how the company wide list of employees are maintained.
However to keep it simple, the printing could look like this:
struct Employee
{
void PrintAllReportingEmployee(int level)
{
cout << string(4*level, ' ') << name << endl;
level++;
for (auto& e : employeesDirectlyReportingToThisEmployee)
{
e.PrintAllReportingEmployee(level);
}
}
string name;
vector<Employee> employeesDirectlyReportingToThisEmployee;
};
// Code in some print function:
// Step 1 - find the relevant employee
Employee tmp = SomeFunctionReturningAnEmployeeBasedOnName("NameOfPerson");
// Step 2 - print all employees reporting directly and indirectly
tmp.PrintAllReportingEmployee(0);
This assumes a single top-level Employee (e.g. director) with a vector of employees directly reporting to the director. Each of these would then have a vector of employees reporting to them and so. So it is kind of an tree structure.
Note, if I should design a employee db, I would not go with such a solution.
Who ever asked the question was looking for an answer with something to do with class inheritance. So a class Persion is extended by Employee where Person is also extended by Manager etc etc where they all share some similar properties but not everything.
This means that your code can be expanded upon by other programmers and one change can fix many different classes!
Although this code does not demonstrate class inheritance, it will work.
/*
THE OUTPUT:
Jacobs-MacBook-Pro:~ jacob$ ./employee
Foo McGoo
Bar Too
Jacobs-MacBook-Pro:~ jacob$
*/
#include <iostream>
#include <string>
#include <vector>
using std::string;
using std::vector;
using std::cout;
using std::endl;
/* define class (this should be in a header file) */
class Employee{
public:
//Variables
string Name;
//Functions
Employee(const string&); //constructor
void AddCoWorker(const Employee&);
void ShowCoWorkers();
private:
vector<Employee> employees;
}; //Note the semicolon
//Entry point
int main(int argc, char **argv){
Employee foo("Foo McGoo");
Employee bar("Bar Too");
Employee me("Bevis");
me.AddCoWorker(foo);
me.AddCoWorker(bar);
me.ShowCoWorkers();
return 0;
}
//Class functions (should be in a separate cpp file)
Employee::Employee(const string& name){
this->Name = name;
}
void Employee::AddCoWorker(const Employee &e){
this->employees.push_back(e);
}
void Employee::ShowCoWorkers(){
int count = this->employees.size();
for(int i = 0; i < count; i++){
//Print the names of each co worker on separate lines
cout << this->employees[i].Name << endl;
}
}
i am new to c++ and i'm try to write a code that reads integers of a text file and saves each integer in different variables line by line.
I am having problems with the syntax and how to arrange the code. Basically the text file contains 4 integers per line which values are to be read to the a class planet's coordinates and id as shown below. I know the code beloe is incomplete but this is the first time im programming with c++ and need help. please you do not need to explain this using planets or anything. I just need a general understanding
#include <iostream>
#include <fstream>
using namespace std;
class planet{
public :
float x_coordinates;
float y_coordinates;
float z_coordinates;
int id;
};
planet*generate_planet(istream &fin)
{
planet *x= new planet;
fin >> x->id >> x->x_coordinates >> x->y_coordinates >> x->z_coordinates;
return (x);
}
void report_planet( planet &p)
{
cout<<"planet "<<p.id<<" has coordinates (" << p.x_coordinates<<","<< p.y_coordinates<<","<< p.z_coordinates<<")"<<endl;
}
int main()
{
planet p;
planet *x;
ifstream fin("route.txt");
generate_planet(fin);
report_planet(*x);
return 0;
}
You have some errors in your code.
Note that in this line:
fin>>x->id>>x->x_coordinates>>x->y_coordinates>>x->y_coordinates; You write twice to x->y_coordinate instead of x->z_coordinate.
Also, your void report_planet(planet &p) function receives planet & as argument, but you pass it fin which is of time ofstream
Another thing is you're trying to read a file, not write to one, hence the use of ofstream is wrong, you should use ifstream instead.
Does your code even compile?
Good luck.