Different results in Linux than in Windows C++ - c++

I've created my code in Microsoft Visual Studio Express 2013 and it compiles and runs fine. I've moved this over to Linux and it gives me a different result for the GPA output. The GPA's are coming as 0 and 6.95281e-310 instead of the 3.9 and 3.5.
Also wondering if there is a difference between the strcmp and strncpy in Linux since I had to add #include <cstring> in my student.h?
Is there something else I should be using instead of strncpy in Linux?
student.h
#ifndef STUDENT_H
#define STUDENT_H
#include <iostream>
#include <cstring>
using namespace std;
class Student
{
public:
Student(const char initId[], double gpa);
bool isLessThanByID(const Student& aStudent) const;
bool isLessThanByGpa(const Student& aStudent) const;
void print()const;
private:
const static int MAX_CHAR = 100;
char id[MAX_CHAR];
double gpa;
};
#endif
student.cpp
#include "student.h"
//implement the required 3 functions here
Student::Student(const char initId[], double gpa) : gpa(gpa)
{
// initialize a newly created student object with the passed in value
strncpy(id, initId, Student::MAX_CHAR - 1);
if (Student::MAX_CHAR > 0)
{
id[Student::MAX_CHAR - 1] = '\0';
}
}
bool Student::isLessThanByID(const Student& aStudent) const
{
// compare the current student object with the passed in one by id.
if (strcmp(id, aStudent.id) > 0)
{
return true;
}
else
{
return false;
}
}
bool Student::isLessThanByGpa(const Student& aStudent) const
{
// compare the current student object with the passed in one by gpa
if (gpa < aStudent.gpa)
{
return true;
}
else
{
return false;
}
}
void Student::print() const
{
cout << id << '\t' << gpa << endl;
}
app.cpp
#include "student.h"
int main()
{
Student s1("G10", 3.9);
Student s2("G20", 3.5);
s1.print();
s2.print();
if(s1.isLessThanByID(s2))
{
cout << "about right!" << endl;
}
else
{
cout << "uhmm ..." << endl;
}
if(!s1.isLessThanByGpa(s2))
{
cout << "about right!" << endl;
}
else
{
cout << "uhmm ..." << endl;
}
//system("pause");
return 0;
}

strcmp compares strings http://www.cplusplus.com/reference/cstring/strcmp/
strncpy copies them http://www.cplusplus.com/reference/cstring/strncpy/
There IS a great diff really between them, in Linux and other systems as well.

Related

How can I read data from a file into a vector of class without using getLine()?

I have some data in the file that I would like to be able to read into a vector of a class-type/object. This object also has within itself a vector that takes in another class type, and the data that needs to populate that inner vector is also contained within the text file. How can I read the data from the file into the vectors accordingly without using getLine()?
The data is formatted as so in the document.
143 Jones
1234 2 C
-1
123 Smith
4321 4 A
132 3 B
-1
Where the first line is the ID of the student followed by their name, and below it is a series of classes that student has taken followed by the number of credits each course is worth and the grade the student got for the course.
Below is the course class header code
#pragma once
#include <iostream>
class Course {
public:
Course(int, int, std::string);
int getCourseCode() const {return courseCode;}
int getCredits() const {return courseCredits;}
std::string getGrade() const {return grade;}
void print(std::ostream &os) const;
private:
int courseCode;
int courseCredits;
std::string grade;
};
inline std::ostream &operator <<(std::ostream &os, const Course &course) {
course.print(os);
return os;
}
inline Course::Course(int courseCode, int courseCredits, std::string grade) {
this->courseCode = courseCode;
this->courseCredits = courseCredits;
this->grade = grade;
}
Below is the student class header code
#pragma once
#include <vector>
#include "course.h"
class Student {
public:
Student(int, std::string, std::vector<Course> courses);
int getID() const;
double getGPA() const;
std::string getName() const;
void print(std::ostream &os) const;
std::vector<Course> courses;
private:
int id;
std::string name;
};
inline std::ostream &operator << (std::ostream &os, const Student &student) {
student.print(os);
return os;
}
Below is the student.cpp code
#include "student.h"
#include <string>
using namespace std;
Student::Student(int id, std::string name, vector<Course> courses) {
this->id = id;
this->name = name;
this->courses = courses;
}
int Student::getID() const {
return id;
}
string Student::getName() const {
return name;
}
double Student::getGPA() const {
double total;
double creds;
double cgrade;
double gpa;
for(int i = 0; i < courses.size(); i++) {
if(courses[i].getGrade() == "A") cgrade = 4.0;
else if(courses[i].getGrade() == "B") cgrade = 3.0;
else if(courses[i].getGrade() == "C") cgrade = 2.0;
else if(courses[i].getGrade() == "D")cgrade = 1.0;
total += cgrade * courses[i].getCredits();
creds += courses[i].getCredits();
}
gpa = total / creds;
return gpa;
}
void Student::print(std::ostream &os) const {
os << id << " " << name << ": " << this->getGPA() << endl;
for(int i = 0; i < courses.size(); i++) {
os << courses[i];
}
}
This is what I've tried so far in terms of trying to load the vectors
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include "student.h"
using namespace std;
void loadStudents(string fileName, vector<Student> &students);
bool compareCourses(const Course &c1, const Course &c2);
bool compareStudents(const Student &s1, const Student &s2);
void printResults(string fileName, vector<Student> &students);
int main() {
try {
vector<Student> students;
loadStudents("students.data", students);
cout << students.size() << " records processed" << endl;
return 0;
}
catch(string message) {
cout << "Error: " << message << endl;
exit(1);
}
};
void loadStudents(string fileName, vector<Student> &students) {
ifstream studentsFile(fileName.c_str());
if(!studentsFile.good()) {
throw string("Input file: " + fileName + ", not found!");
}
int id;
string name;
vector<Course> cs;
while(studentsFile >> id >> name >> cs) {
students.place_back(student);
}
studentsFile.close();
}
bool compareCourses(const Course &c1, const Course &c2) {
return c1.getGrade() < c2.getGrade();
}
bool compareStudents(const Student &s1, const Student &s2) {
return s1.getGPA() < s2.getGPA();
}
void printResults(string fileName, vector<Student> &students) {
ofstream outputFile(fileName.c_str());
if(!outputFile.good()) {
throw string("Output file: " + fileName + ", not found!");
}
for(auto student : students) {
outputFile << student.print(outputFile) << endl;
}
outputFile.close();
}
I'm getting an error stating that "no operator ">>" matches these operands" in the while loop inside the loadStudents function, which I think pertains to the istream for the vector.
The desired output is something like this printed to an output file.
143 Smith: 3.57143
4321 (4 credits): A
132 (3 credits): B
143 Jones: 2
1234 (2 credits): C
2 records processed
Where the student ID and name are printed along with their calculated GPA and the courses they took below them followed by a message stating the number of students that were processed.
My main issue pertains to the loading of the students vector with the subsequent data of the course information being appropriately loaded into the courses vector for each student. Is this possible without using the getLine() method and istream >>?

Comparing stacks

I have a project to compare the contents of two stacks and I am having issues with this function. I believe I have the rest of the program done correctly. I am getting errors on B.myCharacters.empty() (Expression must have class type) and B==B.myCharacters (no operator "==" matched these operands).
bool CharStack::IsEqual(CharStack & B)
{
if (B.empty())
{
cout << "Stack is empty" << endl;
return false;
}
else if (B.myCharacters.empty())
{
cout << "Stack is empty" << endl;
return false;
}
else if (B == B.myCharacters)
return true;
}
Any help would be greatly appreciated.
Here is the header and driver. They were provided by the teacher for this project and I am not allowed to change them, even if there is a better way to do it.
#include <iostream>
#include <string>
using namespace std;
const int STACK_CAPACITY = 128;
typedef char StackElement;
class CharStack
{
private:
char myCharacters[STACK_CAPACITY]; // STL stack of chars.
int myTop;
public:
CharStack();
bool empty();
void push(const StackElement & value);
StackElement top() const;
void pop();
void StringToStack(const string & inStr);
friend ostream & operator <<(ostream & out, const CharStack & CS);
CharStack Reverse();
bool IsEqual(CharStack & B);
};
Driver
#include <string>
#include <cassert>
#include "Header.h"
using namespace std;
//introduces namespace std
int main(void)
{
ifstream in;
string fileName, line[30];
int i = 0;
CharStack N, M, P;
cout << "Enter file name for palindrome check: ";
cin >> fileName;
in.open(fileName.c_str());
assert(in.is_open());
while (!in.eof())
{
getline(in, line[i]);
N.StringToStack(line[i]);
cout << N << endl;
P = N;
M = N.Reverse();
if (P.IsEqual(M))
cout << "This line is a palindrome line" << endl;
else
cout << "This line is not a palindrome line" << endl;
i++;
}
cout << "\nProgram ended normally.\n";
system("pause");
}
Assuming your CharStack internally keeps the characters in a std::string, i.e.
class CharStack
{
std::string myCharacters; // internal data
public:
bool IsEqual(CharStack const&) const;
/* ... */
};
and IsEqual() should return if two stacks are identical, then the implementation is simply
bool CharStack::IsEqual(CharStack const&other) const
{
return myCharacters == other.myCharacters;
}
This compares an empty and a non-empty stack as not equal, but two empty stacks as equal, which arguably is the correct behaviour. If you want two empty stacks to be not equal you can
bool CharStack::IsEqualNonEmpty(CharStack const&other) const
{
return !myCharacters.empty() && myCharacters == other.myCharacters;
}
Note also the various uses of the keyword const.

Initialize member in print() from another function

Not sure where I am at the moment, trying to figure it out. I need to initialize the members in print() const as it is giving me random gibberish. No matter what I try to do, it does not seem to work. Not sure what to even do. Can anyone give me a hand?
*edit: Added in the rest of the code. Forgot it when I submitted the first time.
Student.cpp
#include "student.h"
//implement the required 3 functions here
Student::Student(const char initId[], double gpa)
{
// initialize a newly created student object with the passed in value
}
bool Student::isLessThanByID(const Student& aStudent) const
{
// compare the current student object with the passed in one by id.
if (strcmp(id, aStudent.id) > 0)
{
return true;
}
else
{
return false;
}
}
bool Student::isLessThanByGpa(const Student& aStudent) const
{
// compare the current student object with the passed in one by gpa
if (gpa < aStudent.gpa)
{
return true;
}
else
{
return false;
}
}
void Student::print() const
{
cout << id << '\t' << gpa << endl;
}
student.h
#ifndef STUDENT_H
#define STUDENT_H
#include <iostream>
using namespace std;
class Student
{
public:
Student(const char initId[], double gpa);
bool isLessThanByID(const Student& aStudent) const;
bool isLessThanByGpa(const Student& aStudent) const;
void print()const;
private:
const static int MAX_CHAR = 100;
char id[MAX_CHAR];
double gpa;
};
#endif
app.cpp
#include "student.h"
int main()
{
Student s1("G10", 3.9);
Student s2("G20", 3.5);
s1.print();
s2.print();
if(s1.isLessThanByID(s2))
{
cout << "about right!" << endl;
}
else
{
cout << "uhmm ..." << endl;
}
if(!s1.isLessThanByGpa(s2))
{
cout << "about right!" << endl;
}
else
{
cout << "uhmm ..." << endl;
}
system("pause");
return 0;
}
There is nothing in that code that sets the values of Student::id and Student::gpa. Your constructor has parameters initId and gpa; you should copy those into your object. Based on the declaration of Student that you provided, something this should be appropriate:
Student::Student(const char initId[], double gpa) : gpa(gpa)
{
strncpy(id, initId, Student::MAX_CHAR-1);
id[Student::MAX_CHAR-1] = '\0';
}

Using an enum from a class (C++)

I'm reading a book on C++ and was writing out some code to practice using the interface and implementation of a class. I've searched for solutions to my issue for a while to no avail.
I have a class with an enumeration inside of it. While trying to instantiate an object of that class, I am having trouble accessing the enum types outside of the class. I have tried using Book::Horror, Biblo::Horror, Biblo::Book::Horror, Horror, and even things like Biblo::Book::Genre::Horror. Can't seem to get it to let me access the types of the enum for the instantiation of my object in the main.cpp file.
Any help is appreciated! The more complex uses of C++ are still new to me. Here is my source:
book.h
#include <iostream>
#include <string>
using namespace std;
namespace Biblo{
class Book{
public:
enum Genre{
No_Genre, Horror, Comedy, Romance, Mystery
};
// The rest of this header is working fine I think, just this enum
class Invalid{}; // Used for throwing errors
Book(int n_ISBN, int n_copyrightYear, string n_title, string n_author, Genre n_genre);
Book();
// Accessors (non-modifying)
int getISBN() const { return ISBN; }
int getCopyrightYear() const { return copyrightYear; }
string getTitle() const { return title; }
string getAuthor() const { return author; }
string getGenre() const;
// Mutators
void changeAuthor(string newAuthor);
private:
int ISBN;
int copyrightYear;
string title;
string author;
Genre genre;
}; // End Book
// Helper Functions go here
bool operator==(const Book& a, const Book& b);
bool operator!=(const Book& a, const Book& b);
} // End Biblo
and main.cpp
#include <iostream>
#include "book.h"
using namespace std;
int main()
{
Biblo::Book book(100, 2012, "The Walrus", "The Eggman", Book::Horror); // THIS LINE GIVES ERROR
cout << "ISBN: " << book.getISBN() << endl;
cout << "Copyright: " << book.getCopyrightYear() << endl;
cout << "Title: " << book.getTitle() << endl;
cout << "Author: " << book.getAuthor() << endl;
cout << "Genre: " << book.getGenre() << endl;
return 0;
}
Edit: here is the book.cpp file
#include <iostream>
#include "book.h"
#include <string>
namespace Biblo{
Book::Book(int n_ISBN, int n_copyrightYear, string n_title, string n_author, Genre n_genre)
:ISBN(n_ISBN), copyrightYear(n_copyrightYear), title(n_title), author(n_author), genre(n_genre)
{
// constructor
}
Book::Book()
:ISBN(0), copyrightYear(0), title(""), author(""), genre(Genre::No_Genre)
{
// Default constructor
}
// Accessors
string Book::getGenre() const
{
if (Book.genre == Genre::No_Genre)
return "No Genre!";
if (Book.genre == Genre::Horror)
return "Horror";
if (Book.genre == Genre::Comedy)
return "Comedy";
if (Book.genre == Genre::Romance)
return "Romance";
if (Book.genre == Genre::Mystery)
return "Mystery";
}
// Mutators
void Book::changeAuthor(string newAuthor)
{
author = newAuthor;
}
// Helper Functions
bool operator==(const Book& a, const Book& b)
{
if (a.getISBN() != b.getISBN())
return false;
if (a.getCopyrightYear() != b.getCopyrightYear())
return false;
if (a.getTitle() != b.getTitle())
return false;
if (a.getAuthor() != b.getAuthor())
return false;
if (a.getGenre() != b.getGenre())
return false;
return true;
}
bool operator!=(const Book& a, const Book& b)
{
return !(a==b);
}
} // End Biblo
It seems you tried everything but the thing you needed! The enum is nested inside the Book class which is within the Biblo namespace. The code you are looking for is:
int main()
{
Biblo::Book book(100, 2012, "The Walrus", "The Eggman", Biblo::Book::Horror);
return 0;
}
You need to include the enum class. eg.:
Biblio::Book::Genre::Horror
Bunch of things that are going wrong really.
As others mentioned your enum is stashed one level deeper than you think it is, and your complaint about fixing it then producing an undefined reference is probably because at that point you bump into the fact there's nothing much initialized, and if you got past that you are returning items somewhat poorly when it comes to the enumerator.
If you use the right name space, quickly put in an actual implementation for the constructor, and get the most immediate return for your enum (an int might work) it should work, and probably look like this:
#include <iostream>
#include <string>
using namespace std;
namespace Biblo{
class Book{
public:
enum Genre{
No_Genre, Horror, Comedy, Romance, Mystery
};
// The rest of this header is working fine I think, just this enum
class Invalid{}; // Used for throwing errors
Book(int n_ISBN, int n_copyrightYear, string n_title, string n_author, Genre n_genre);
Book();
// Accessors (non-modifying)
int getISBN() const { return ISBN; }
int getCopyrightYear() const { return copyrightYear; }
string getTitle() const { return title; }
string getAuthor() const { return author; }
int getGenre() const { return genre; }
// Mutators
void changeAuthor(string newAuthor);
private:
int ISBN;
int copyrightYear;
string title;
string author;
Genre genre;
}; // End Book
Book::Book(int n_ISBN, int n_copyrightYear, string n_title, string n_author, Genre n_genre){
ISBN = n_ISBN; copyrightYear = n_copyrightYear; title = n_title; author = n_author;
};
}
using namespace std;
int main()
{
Biblo::Book book(100, 2012, "The Walrus", "The Eggman", Biblo::Book::Horror); // THIS LINE GIVES ERROR
cout << "ISBN: " << book.getISBN() << endl;
cout << "Copyright: " << book.getCopyrightYear() << endl;
cout << "Title: " << book.getTitle() << endl;
cout << "Author: " << book.getAuthor() << endl;
cout << "Genre: " << book.getGenre() << endl;
return 0;
}
Are you sue the book you're following isn't discussing details such as initializer lists or something else for constructors concurrent to, or previous to, the subjects you're looking at?
The code looked somewhat incomplete.
Edited in line here on SO, so bear with the poor formatting and the merged h/cpp look :)

How to use 'fout' with inheritance

I'm taking a class in C++ and I've run into a problem. We have to create a list of bankaccounts that each have their own savings and checking account. I've come quite far, but now I have to use "ofstream& fout" to print the checking and savings of an imaginairy account.
My header file of "Account.h" looks like this (I think it's correct):
#include <iostream>
#include <cmath>
#include <fstream>
#ifndef ACCOUNT_H
#define ACCOUNT_H
using namespace std;
class Account{
protected:
string number;
double balance;
public:
Account(){}
Account(string nr, double bl);
void deposit(double am);
string get_number();
double get_balance();
double withdraw(double am);
bool equals(Account other);
virtual void print();
void println();
void println(string s);
virtual void println(ofstream& fout);
virtual void read(ifstream& fin);
};
#endif
My definition file is where it all goes horribly wrong with the fstream part:
#include "Account.h"
Account::Account(string nr, double bl){
if (bl >= 0){
number = nr;
balance = bl;
}
else{
number = "incorrect";
}
}
void Account::deposit(double am){
if (am >= 0){
balance = balance + am;
}
}
string Account::get_number(){
return number;
}
double Account::get_balance(){
return balance;
}
double Account::withdraw(double am){
if (0 <= am && am <= get_balance()){
balance = balance - am;
return am;
}
else{
return 0;
}
}
bool Account::equals(Account other){
if (number == other.get_number()){
return true;
}
return false;
}
void Account::print(){
cout << "<Account(" << number << ",";
cout << balance << ")>" ;
}
void Account::println(){
print();
cout << endl;
}
void Account::println(string s){
cout << s;
println();
}
void Account::println(ofstream& fout){
fout << number << ",";
fout << balance;
fout << endl;
}
void Account::read(ifstream& fin){
fin >> number;
}
There is something wrong with the declaration of void Account::println(ofstream& fout). It gives me the output
<Account(number,balance,0)>
instead of
<Account(number,balance)>
Why does this happen? I have many more problems with the printing of the savings and checking numbers, but i feel if I understand why this is happening I can solve those. Thank you to anyone who wants to help me.
Account::println(ofstream&) will print "", but since the balance is a double, it prints with a decimal place:
if balance == 0.0, it will be printed as eiter 0.0 or 0,0, depending on your locale.
Either way, you have way too many print methods, and I think the solution should be implemented through an output operator:
Header:
class Account {
// ....
// no print methods defined
};
std::ostream& operator <<(std::ostream& out, const Account& a);
Source:
std::ostream& operator <<(std::ostream& out, const Account& a)
{
return out << "";
}
Client code:
#include <iostream> // console
#include <fstream> // file
Account a;
// print to console
std::cout << a << std::endl;
// print to file
std::ofstream fout("./account.txt");
fout << a << std::endl;