Why am I getting a meesed up cout statement from my function? - c++

Hi I am working on a program that should display the latter of two dates, it needs to accept two Date structures and return the latter of them. Latter being 04/31/2014 is latter then 04/30/2014. Here is my code and I do not understand why I am getting a long weird number... Thanks for helping.
#include <iostream>
#include <iomanip>
using namespace std;
struct Date
{
int day;
int month;
int year;
};
int main()
{
void laterDate(Date, Date);
Date one;
Date two;
Date later;
cout << "Enter a Date starting with the day, then month, then year:\n";
cin >> one.day;
cin >> one.month;
cin >> one.year;
cout << "\n\nEnter another date in the same fashion as above:\n";
cin >> two.day;
cin >> two.month;
cin >> two.year;
cout << "\n\nThank you, I will now tell you which date is later then the other!" << endl;
laterDate(one, two);
system("pause");
return 0;
}
void laterDate(Date o,Date t)
{
Date later;
if (o.year >= t.year)
if (o.month >= t.month)
if (o.day > t.day)
{
later.day= o.day;
later.month = o.month;
later.year = o.year;
}
else
{
later.day = t.day;
later.month = t.month;
later.year = t.year;
}
cout << later.day << "/" << later.month << "/" << later.year << endl;
}
OUTPUT
Enter a Date starting with the day, then month, then year:
04
30
2014
Enter another date in the same fashion as above:
04
31
2014
Thank you, I will now tell you which date is later then the other!
-858993460/-858993460/-858993460
Press any key to continue . . .
END OUTPUT

You should break out the logic of comparing the dates from the code which displays the results. The standard idiom for comparing objects that can be totally ordered (such as dates) is to overload operator<.
// the intent of this function is to return true if lhs precedes rhs,
// and return false otherwise (rhs precedes lhs, or they are equal)
bool operator<(Date const& lhs, Date const& rhs)
{
// first test the year.
// if the years differ, there is no need to test the month or the day
if (lhs.year < rhs.year) return true;
if (lhs.year > rhs.year) return false;
// years are equal, test the month
if (lhs.month < rhs.month) return true;
if (lhs.month > rhs.month) return false;
// months are equal, test the day
return lhs.day < rhs.day;
}
Then your function can be easily written like this:
void laterDate(Date const& lhs, Date const& rhs)
{
Date const& later = (lhs < rhs) ? rhs : lhs;
cout << later.day << "/" << later.month << "/" << later.year << endl;
}

if (o.year > t.year ||
(o.year >= t.year && o.month > t.month) ||
(o.year >= t.year && o.month >= t.month &&
o.day > t.day))
{
later.day= o.day;
later.month = o.month;
later.year = o.year;
}
else
{
later.day = t.day;
later.month = t.month;
later.year = t.year;
}
in this way , else will always be called , in your implementation it is only called when the two first condition where true, resulting in the display of random bits

I think I'd structure things a little differently. First, I'd make outputting a Date a friend function of the Date class and next, I'd overload the > operator for comparing Date class instances.
struct Date
{
int day;
int month;
int year;
friend std::ostream &operator<<(std::ostream& out, const Date &d) {
return out << d.day << "/" << d.month << "/" << d.year;
}
bool operator>(const Date &t) const;
};
The implementation of the > operator would look like this:
bool Date::operator>(const Date &t) const
{
if (year > t.year) return true;
if (year < t.year) return false;
if (month > t.month) return true;
if (month < t.month) return false;
return day > t.day;
}
And then your main routine would be this:
int main()
{
Date one;
Date two;
std::cout << "Enter a Date starting with the day, then month, then year:\n";
std::cin >> one.day >> one.month >> one.year;
std::cout << "\n\nEnter another date in the same fashion as above:\n";
std::cin >> two.day >> two.month >> two.year;
std::cout << "\n\nThank you: " << (one > two ? one : two)
<< " is the later date\n";
}
Note, too, that one can chain the input operator parts as shown here. In fact, I'd be inclined to declare an input operator operator>> and promote the Date struct to a full-fledged class.

Related

Way to sort a string array that contains both numbers and letters numerically? (C++)

The program must have the input of a bunch of reminders with a day first, example: (Number) (Reminder).
When 0 is inputted all the reminders must be outputted in order of day. I am only unsure as to how to sort these reminders by day number.
#include <iostream>
using namespace std;
int main() {
string sentence[50];
int i = 0;
while (sentence[i - 1] != "0") {
cout << "Enter a day and reminder: ";
getline(cin, sentence[i]);
++i;
}
i = 0;
while (i <= 50 && sentence[i] != "0" && sentence[i] != "") {
cout << sentence[i] << "\n";
++i;
}
}
Use std::sort, specifically, the overload which takes a comparator.
You will have to write a comparator which compares your strings using the numerical data at the beginning.
Here is an example, based on the example in cppreference link above:
struct Comparator
{
bool operator()(string a, string b) const
{
...
return ...;
}
};
std::sort(&sentence[0], &sentence[i], Comparator());
Read the numbers as numbers, and the rest of the line as text, into some structure. Define a < for that structure that orders things in your desired order. Sort your collection of values.
struct Reminder {
int day;
std::string text;
}
bool operator <(const Reminder & lhs, const Reminder & rhs) {
return lhs.day < rhs.day;
}
std::ostream& operator<<(std::ostream& is, const Reminder & rem) {
return is << rem.day << " " << rem.text << "\n";
}
int main() {
std::vector<Remainder> rems;
for (Remainder rem; (std::cin >> rem.day) && (rem.day != 0);) {
std::getline(std::cin, rem.text);
rems.push_back(rem);
}
std::sort(rems.begin(), rems.end());
for (const auto & rem : rems) {
std::cout << rem;
}
}

C++ Trouble with overloading >>

I'm working on a program and have debugged a lot of what I was doing wrong in it out. I have only one error and have read on stack and other forums about similar problems. But have tried to re-do it over and over with no positive results.
Error Shown in header code and it is:
binary'>>' no operator found which takes a right-hand operand of the type'overloaded-function'(or there is no acceptable conversion)
Month.h
#ifndef MONTH_H
#define MONTH_H
#include <iostream>
#include <string>
using namespace std;
class Month{
private:
static string name;
static int monthNumber;
public:
//Default Constructor
Month(){
setName("January");
setNumber(1);
}
//Input of month only constructor and assigning month number from input of name
Month(string n){
name = n;
setName(n);
if(name == "January" || name == "january"){
setNumber(1);
}
else if(name == "February" || name == "february"){
setNumber(2);
}
else if(name == "March" || name == "march"){
setNumber(3);
}
else if(name == "April" || name == "april"){
setNumber(4);
}
else if(name == "May" || name == "may"){
setNumber(5);
}
else if(name == "June" || name == "june"){
setNumber(6);
}
else if(name == "July" || name == "july"){
setNumber(7);
}
else if(name == "August" || name == "august"){
setNumber(8);
}
else if(name == "September" || name == "september"){
setNumber(9);
}
else if(name == "October" || name == "october"){
setNumber(10);
}
else if(name == "November" || name == "november"){
setNumber(11);
}
else if(name == "December" || name == "december"){
setNumber(12);
}
}
//Input of month number only and assigning month name to that number
Month(int n){
setNumber(n);
}
Month(int n, string m){
monthNumber = n;
name = m;
}
//Set the name of the month
void setName(string n){
name = n;
}
//Set the monthes number (and name for increment and decrement)
void setNumber(int n){
monthNumber = n;
switch(monthNumber){
case 1:
setName("January");
break;
case 2:
setName("February");
break;
case 3:
setName("March");
break;
case 4:
setName("April");
break;
case 5:
setName("May");
break;
case 6:
setName("June");
break;
case 7:
setName("July");
break;
case 8:
setName("August");
break;
case 9:
setName("September");
break;
case 10:
setName("October");
break;
case 11:
setName("November");
break;
case 12:
setName("December");
break;
}
}
//Return the name of the month
string getName(){
return name;
}
//Return the month number
int getNumber(){
return monthNumber;
}
//Overload the -- Operator
Month Month::operator--(int){
if(monthNumber == 1)
{
setNumber(12);
setName("December");
}
else {
monthNumber++;
setNumber(monthNumber);
}
}
Month Month::operator--(){
if(monthNumber == 1)
{
setNumber(12);
setName("December");
}
else {
monthNumber++;
setNumber(monthNumber);
}
}
//Overload the ++ operator
Month Month::operator++(int){
if(monthNumber == 12)
{
setNumber(1);
setName("January");
}
else {
monthNumber++;
setNumber(monthNumber);
}
}
Month Month::operator++(){
if(monthNumber == 12)
{
setNumber(1);
setName("January");
}
else {
monthNumber++;
setNumber(monthNumber);
}
}
//Overloading << and >>
friend ostream &operator<<(ostream &strm, const Month &obj){
strm << "# of Month : " << obj.name << " This Corresponds to the month : " << obj.monthNumber << endl;
return strm;
}
//Error here
//-------------------------------------------------------------------
//binary'>>' no operator found which takes a right-hand operand of
//the type'overloaded-function'(or there is no acceptable conversion)
//-------------------------------------------------------------------
friend istream &operator>>(istream &strm, Month &obj) {
strm >> obj.setNumber >> obj.setName;
return strm;
}
};
#endif
source.cpp
#include "Month.h"
#include <cstdlib>
#include <iostream>
using namespace std;
int main(){
Month coolio, first(1), second("June");
coolio++;
second--;
++first;
cout << "Enter the month number: " << endl;
cin >> coolio;
cout << coolio;
cout << second;
cout << first;
return 0;
}
You cannot read data from an input stream, and combine that with a method call. You need to read the data into a temporary int and a temporary string, and then use these int and string to call the setters, like this:
friend istream &operator>>(istream &strm, Month &obj) {
int number;
string name;
strm >> number >> name;
obj.setNumber(number);
obj.setName(name);
return strm;
}
Moreover, since >> is declared a friend, you can read directly into obj's member variables.
Here are some suggestions on how to simplify your program (so the rest of us don't have to wade through hundreds of lines of code):
Assign To Members directly
You don't need to call setName within the setNumber method.
Access the name variable directly.
One Text Case, One compare
Your code will fail for the case jUNe.
You could convert your month name to all lower case or all upper case before you compare. This reduces your if-else ladder by half.
Search the web for "c++ transform toupper".
Remove Month Compares
There's a fancy technique for mapping month names to numbers, but we'll not use that. You can use an array instead. Let the array index represent the month number:
static const char month_number_to_name[13] =
{
"Nothing",
"january", "february", "march", "april", "may", "june",
"july", "august", "september", "october", "november", "december",
};
// ...
std::cout << "The name of month 10 is: "
<< month_number_to_name[10]
<< "\n";
Save Month Name or Number
There is no need to save both the month name and number. With the translation array above you can convert between name and number.
I recommend keeping the month number variable. If you need the name, using the month number to get the name, the process the name.
Small size, small quantity of defects
There is much research in the programming industry that states the longer a program is, the high probability it will have more defects than a shorter one. Just consider the typing alone. More letters typed increases the chance for a typo.
Use data structures to your advantage to reduce your program size.

Program gives me wrong output, can someone take a look? [closed]

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 6 years ago.
Improve this question
So here's the question:
An office starts its work on 8:00:00 and employees may leave on 17:00:00.
Write an OOP program that gets the time that an employee enters and exits.
If an employee comes later than 8:10:00, program should say that the employee has delayed and if sooner than that, it should say that the employee was on time. If one exits later than 17:30:00, the program should say that the employee has stayed an overtime and if sooner than that, the program should say that the employee has exited on time .
So here's the code:
#include <iostream>
using namespace std;
class wTime
{
public:
void get_entime(int, int, int);
void get_extime(int, int, int);
bool calc_en();
bool calc_ex();
void show_result();
private:
int h1, m1, s1;
int h2, m2, s2;
};
void wTime::get_entime(int x=8,int y=0, int z=0)
{
x = h1;
y = m1;
z = s1;
cout << "Enter the entry time in 24 hour format (hh mm ss): " << endl;
cin >> x >> y >> z;
}
void wTime::get_extime(int a=17, int b=0, int c=0)
{
a = h2;
b = m2;
c = s2;
cout << "Enter the exit time in 24 hour format: (hh mm ss) : " << endl;
cin >> a >> b >> c;
}
bool wTime::calc_en()
{
if (h1 > 8)
return true;//takhir dashte;
if (h1 == 8 && m1 > 10 )
return true;//takhir dashte;
if (h1 < 8)
return false;//on time boode;
if (h1 == 8 && m1 < 9)
return false;//on time boode;
}
bool wTime::calc_ex()
{
if (h2 > 17)
return true;//ezafe kari dashte;
if (h2 >= 17 && m2 >= 30)
return true;//ezafe kari nadashte
if (h2 == 17 && m2 < 30)
return false;
}
void wTime::show_result()
{
if (calc_en() == true)
cout << "Employee has delayed." << endl;
if (calc_en() == false)
cout << "Employee was on time" << endl;
if (calc_ex() == true)
cout << "Employee has stayed an overtime" << endl;
if (calc_ex() == false)
cout << "Employee has exited on time." << endl;
}
int main()
{
wTime em;
em.get_entime();
em.calc_en();
em.get_extime();
em.calc_ex();
em.show_result();
cin.ignore();
cin.get();
return 0;
}
The problem is that, for every hh mm ss that I enter it just returns
Employee has delayed.
Employee has exited on time.
What's wrong?
When you take the user input via cin, you're putting it in local variables (specifically the function parameters) which get destroyed immediately afterwards. You're not actually storing them for the subsequent calculations.
You probably want to do something like this:
void wTime::get_entime()
{
cout << "Enter the entry time in 24 hour format (hh mm ss): " << endl;
cin >> h1 >> m1 >> s1;
}
(Do the equivalent for get_extime() too). That will store the values in the member variables so that they can be used in the calculation methods.
bool wTime::calc_en()
{
if (h1 > 8)
return true;//takhir dashte;
if (h1 == 8 && m1 > 10 )
return true;//takhir dashte;
if (h1 < 8)
return false;//on time boode;
if (h1 == 8 && m1 < 9)
return false;//on time boode;
}
you should put in a default return value
for example 8:10 or 8:09 don't get evaluated (the same problem exists in wTime::calc_ex)
and of course the previously mentioned input problems

How to check if EOF (after using getline)

See update below!
My code (now I included more):
while(getline(checkTasks, workingString)){
countTheDays = 0;
// Captures a clean copy of the line in tasks.dat in it's entirety, stores in workingString.
char nlcheck;
checkTasks.get(nlcheck);
if(nlcheck == '\n'){
}
else{
checkTasks.unget();
//getline(checkTasks, workingString);
// Breaks that line up into more usable pieces of information.
getline(check2,tName, '\t');
getline(check2,tDate, '\t');
getline(check2,trDate, '\t');
getline(check2,tComplete, '\n');
// Converts the string form of these pieces into usable integers.
stringstream(tDate.substr(0,tDate.find_first_of('/'))) >> year;
stringstream(tDate.substr(tDate.find_first_of('/')+1,tDate.find_last_of('/'))) >> month;
stringstream(tDate.substr(tDate.find_last_of('/')+1,tDate.length()-1)) >> day;
stringstream(tComplete) >> checkComplete;
stringstream(trDate) >> checkReminder;
// Adds the number of days until your task is due!
if(year != date[0]){
for(int i = date[1]; i <= 12; i++){
countTheDays += System::DateTime::DaysInMonth(date[0], i);
}
countTheDays-= date[2];
for (int i = 1; i<= month; i++){
countTheDays +=System::DateTime::DaysInMonth(year, i);
}
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
}
else if(month != date[1]){
for(int i = date[1]; i <= month; i++){
countTheDays += System::DateTime::DaysInMonth(date[0], i);
}
countTheDays -= (date[2]);
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
}
else{
countTheDays+= System::DateTime::DaysInMonth(date[0], month);
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
countTheDays -= date[2];
}
// If the task is nearing it's due date (the time frame specified to be notified) it'll notify user.
// Only coded to work if the task is due in the current or following months.
if(countTheDays <= checkReminder){
if( countTheDays < 0){
cout << endl << endl << tName << " is past due!" << endl;
cout << "Should I keep reminding you about this task? Enter Y or N. ";
cin >> continueToRemind;
}
else{
cout << endl << endl << tName << " is due in " <<countTheDays << " days! Don't forget!" << endl;
cout << "Should I keep reminding you about this task? Enter Y or N. ";
cin >> continueToRemind;
}
// If user doesn't want to be reminded, begins process of converting that line in the file to usable info
// and 'overwriting' the old file by creating a new one, deleting the old one, and renaming the new one.
if(continueToRemind == "n" || continueToRemind == "N"){
fileModified = true;
string line;
/* vector<string> lines;
while(getline(tasksClone, line)){
lines.push_back(line);
}
lines.erase(remove(lines.begin(), lines.end(), workingString), lines.end());
if (!lines.empty()) {
auto i=lines.begin();
auto e=lines.end()-1;
for (; i!=e; ++i) {
saveTasks << *i << '\n';
}
saveTasks << *i;
}*/
// This writes a copy of the tasks.dat file, minus the task that the user elected not to be notified of.'
while(getline(tasksClone, testBuffer)){
if(testBuffer == workingString){
// This condition does nothing. Essentially erasing the 'completed' task from the list.
}
else if(testBuffer != workingString && tasksClone.eof()){
// This writes everything except the specified task to taskbuffer.dat
saveTasks << testBuffer;
}
else {
saveTasks << testBuffer << '\n';
}
}
}
}
}
}
}
else{
cout << "The tasks file is empty, you must not have any tasks!" << endl;
}
I hope that question makes sense!
Thanks
Marcus
UPDATE: Reworked the code, again. After telling it to delete 1 task, it never runs this loop. Current code:
while(getline(tasksClone, testBuffer)){
if(testBuffer == workingString){
// This condition does nothing. Essentially erasing the 'completed' task from the list.
}
else if(testBuffer != workingString && tasksClone.eof()){
// This writes everything except the specified task to taskbuffer.dat
saveTasks << testBuffer;
}
else {
saveTasks << testBuffer << '\n';
}
}
Input file:
test1 2012/12/13 10 0;
test2 2012/12/23 20 0;
test3 2012/12/31 28 0;
\n
Output file (after telling it to delete test1 and 2):
test2 2012/12/23 20 0;
test3 2012/12/31 28 0;
\n
The first thing I would do is just read your whole file into a vector of strings, each string corresponding to a line in the file. That can be done quite easily.
std::vector<std::string> lines;
std::string line;
while (std::getline(tasksClone, line))
lines.push_back(line);
Once you have that, processing becomes much easier. You can check if a line is empty like this:
if (lines[i].empty())
That's equivalent to checking if the next character after a newline is another newline. You can remove any lines from the vector that you don't want like this:
lines.erase(std::remove(lines.begin(), lines.end(), workingString), lines.end());
Instead of that though, you could avoid putting them into the vector in the first place by putting a test in the loop that reads the lines from the file.
Once you've done all your processing, you can just write the lines back out to the other file, inserting the newlines manually.
if (!lines.empty()) {
auto i=lines.begin(), e=lines.end()-1;
for (; i!=e; ++i) {
saveTasks << *i << '\n';
}
saveTasks << *i;
}
Instead of adding a new-line at the end of each line, but only if there's another line to write afterwards, I'd just precede each line by a new-line. That'll get you the new-line at the beginning of the file, and no new-line at the end, just as you want.
As usual, code like while (!your_file.eof()) is broken though. You probably want something like:
while (std::getline(taskClone, buffer)) {
if (buffer.empty())
continue;
if (keep(buffer)) // whatever condition you need
saveTasks << "\n" << buffer;
}
You can do the same thing a little more easily with std::remove_copy_if and my ostream_prefix_iterator:
// prefix_iterator.h
#include <ostream>
#include <iterator>
template <class T,
class charT=char,
class traits=std::char_traits<charT>
>
class prefix_ostream_iterator :
public std::iterator<std::output_iterator_tag,void,void,void,void>
{
charT const* delimiter;
std::basic_ostream<charT,traits> *os;
public:
typedef charT char_type;
typedef traits traits_type;
typedef std::basic_ostream<charT,traits> ostream_type;
prefix_ostream_iterator(ostream_type& s)
: os(&s),delimiter(0)
{}
prefix_ostream_iterator(ostream_type& s, charT const *d)
: os(&s),delimiter(d)
{}
prefix_ostream_iterator<T,charT,traits>& operator=(T const &item)
{
// Here's the only real change from ostream_iterator:
// Normally, the '*os << item;' would come before the 'if'.
if (delimiter != 0)
*os << delimiter;
*os << item;
return *this;
}
prefix_ostream_iterator<T,charT,traits> &operator*() {
return *this;
}
prefix_ostream_iterator<T,charT,traits> &operator++() {
return *this;
}
prefix_ostream_iterator<T,charT,traits> &operator++(int) {
return *this;
}
};
Using this along with a line proxy I posted in an earlier answer, you could do the job with code something like:
#include "line.h"
#include "prefix_iterator.h"
std::remove_copy_if(std::istream_iterator<line>(taskClone),
std::istream_iterator<line>(),
prefix_ostream_iterator<std::string>(taskSave, "\n"),
[](std::string const &line) { /* decide if to keep line*/});
It's not too clear what you are trying to do. std::getline
strips the trailing new line, so any time you output what you've
read, you have to add it. (If you're writing to a text file,
it's undefined behavior if the last character written isn't a
'\n'.)
Note too that your main loop is incorrect. The state of
tasksClone.eof() is indeterminate, and you don't verify that
the input has succeeded after doing the getline. What you
need is something like:
std::string line
while ( std::getline( tasksClone, line ) ) {
if ( line != workingString ) {
saveTasks << line << '\n';
}
}
In your example input, the first line you read will be empty.
I solved my problem, just in case anyone wants to know. It's not as memory efficient as it could be, but it functions:
// Reads the file, checks if it's due, and if it's due prompts user to either save or delete the task.
// Captures a clean copy of the line, in its entirety, and stores it to workingString.
while(getline(checkTasks,workingString)){
countTheDays = 0;
// Handles newline characters.
char nlcheck;
checkTasks.get(nlcheck);
if(nlcheck == '\n'){
}
else{
checkTasks.unget();
// Breaks that line up into more usable pieces of information.
getline(check2,tName, '\t');
getline(check2,tDate, '\t');
getline(check2,trDate, '\t');
getline(check2,tComplete, '\n');
// Converts the string from of these pieces into usable integers.
stringstream(tDate.substr(0,tDate.find_first_of('/'))) >> year; stringstream(tDate.substr(tDate.find_first_of('/')+1,tDate.find_last_of('/'))) >> month; stringstream(tDate.substr(tDate.find_last_of('/')+1,tDate.length()-1)) >> day;
stringstream(tComplete) >> checkComplete;
stringstream(trDate) >> checkReminder;
// Adds the number of days until your task is due!
if(year != date[0]){
for(int i = date[1]; i <= 12; i++){
countTheDays += System::DateTime::DaysInMonth(date[0], i);
}
countTheDays-= date[2];
for (int i = 1; i<= month; i++){
countTheDays +=System::DateTime::DaysInMonth(year, i);
}
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
}
else if(month != date[1]){
for(int i = date[1]; i <= month; i++){
countTheDays += System::DateTime::DaysInMonth(date[0], i);
}
countTheDays -= (date[2]);
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
}
else{
countTheDays+= System::DateTime::DaysInMonth(date[0], month);
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
countTheDays -= date[2];
}
// If the task is nearing it's due date (the time frame specified to be notified) it'll notify user.
if(countTheDays <= checkReminder){
if( countTheDays < 0){
cout << endl << endl << tName << " is past due!" << endl;
cout << "Should I keep reminding you about this task? Enter Y or N. ";
cin >> continueToRemind;
}
else{
cout << endl << endl << tName << " is due in " <<countTheDays << " days! Don't forget!" << endl;
cout << "Should I keep reminding you about this task? Enter Y or N. ";
cin >> continueToRemind;
}
// If user doesn't want to be reminded, begins process of converting that line in the file to usable info
// and 'overwriting' the old file by creating a new one, deleting the old one, and renaming the new one.
if(continueToRemind == "n" || continueToRemind == "N"){
fileModified = true;
// Adds workingString to deleteTasks[] to be compared against later.
deleteTasks.push_back(workingString);
}
}
}
}
int match = 0;
// Iterates through tempTasks.dat and compares lines to workingString.
while(getline(tasksClone, testBuffer)){
for(int i = 0; i< deleteTasks.size(); i++){
// If a match is found, it sets the match flag to delete that line.
if(testBuffer == deleteTasks[i]){
match = 1;
}
}
// Deletes that task.
if(match == 1){
//Do nothing, erasing the task
}
// If EOF, writes only the task, without a newline character.
else if(tasksClone.eof()){
saveTasks << testBuffer;
}
// If !EOF, also writes a newline character.
else{
saveTasks << testBuffer << '\n';
}
match = 0;
}
You problem may be in using "\n" if you are viewing your files in Windows or Mac.
Try to use "\r\n" instead.

Comparing values input to values in a vector

I'm trying to input a form of data validation in which when a user enter's a book's ISBN number, if it has already been stored then it will output an error message. However, I'm having trouble doing this. I'm not sure if I'm overloading the == operator correctly, and I'm not sure how to compare the vector values in the store_ISBN() function.
Here is the code:
#include "std_lib_facilities.h"
// Classes ---------------------------------------------------------------------
class Book{
public:
vector<Book> books; // stores book information
Book() {}; // constructor
friend ostream& operator<<(ostream& out, const Book& b);
bool operator==(const Book& d);
string what_title();
string what_author();
int what_copyright();
void store_ISBN();
void is_checkout();
private:
char check;
int ISBNfirst, ISBNsecond, ISBNthird;
char ISBNlast;
string title;
string author;
int copyright;
};
// Class Functions -------------------------------------------------------------
string Book::what_title()
{
cout << "Title: ";
getline(cin,title);
cout << endl;
return title;
}
string Book::what_author()
{
cout << "Author: ";
getline(cin,author);
cout << endl;
return author;
}
int Book::what_copyright()
{
cout << "Copyright Year: ";
cin >> copyright;
cout << endl;
return copyright;
}
void Book::store_ISBN()
{
bool test = false;
cout << "Enter ISBN number separated by spaces: ";
while(!test){
cin >> ISBNfirst >> ISBNsecond >> ISBNthird >> ISBNlast;
for(int i = 0; i < books.size(); ++i)
if(ISBNfirst == books[i]) cout << "test"; // no idea how to implement this line
if((ISBNfirst<0 || ISBNfirst>9) || (ISBNsecond<0 || ISBNsecond>9) || (ISBNthird<0 || ISBNthird>9))
error("Invalid entry.");
else if(!isdigit(ISBNlast) && !isalpha(ISBNlast))
error("Invalid entry.");
else test = true;}
cout << endl;
}
void Book::is_checkout()
{
bool test = false;
cout << "Checked out?(Y or N): ";
while(!test){
cin >> check;
if(check == 'Y') test = true;
else if(check == 'N') test = true;
else error("Invalid value.");}
cout << endl;
}
// Operator Overloading --------------------------------------------------------
bool Book::operator==(const Book& d){ // is this right???
if((ISBNfirst == d.ISBNfirst) && (ISBNsecond == d.ISBNsecond)
&& (ISBNthird == d.ISBNthird) && (ISBNlast == d.ISBNlast)) return true;
else return false;
}
ostream& operator<<(ostream& out, const Book& b){
out << "Title: " << b.title << endl;
out << "Author: " << b.author << endl;
out << "ISBN: " << b.ISBNfirst << "-" << b.ISBNsecond << "-" << b.ISBNthird << "-" << b.ISBNlast << endl;
out << endl;
return out;
}
// Main ------------------------------------------------------------------------
int main()
{
Book store;
string question;
while(true){
store.what_title();
store.what_author();
store.what_copyright();
store.store_ISBN();
store.is_checkout();
store.books.push_back(store);
cout << "Are you finished?(Y or N): ";
cin >> question;
if(question == "Y") break;
else if(question == "N"){
cout << endl;
cin.ignore();}
else error("Invalid value.");
}
cout << endl;
cout << "Books stored -\n" << endl;
for(int i = 0; i < store.books.size(); ++i)
cout << store.books[i];
keep_window_open();
}
Note that in the store_ISBN function I've only included testing for one variable since I don't want to type out the whole thing before I figure out how to do it.
As you can see each time a book passes through the loop in main, the data for that book is stored. I'm then able to output all the data input after the loop by overloading the << operator to print Title, Author, and ISBN. So I think I should be able to access that individual data in the vector to compare to the user input ISBN, but I don't know how. The parts that I am confused about have been commented as such.
I'm not sure quite what the user is expected to type for an ISBN.
Reading from a stream into an int will read digits up to a space, and convert the result to int (if all goes well, anyway). Reading into a char will store the char value. So at the moment you're validating than an ISBN looks like three single digits (0-9), and then the next char. That's not what I think an ISBN looks like.
Your operator== looks OK, although note that for a bool return value,
if (X) return true;
else return false;
can be replaced with
return X;
because conditionals are already of type bool.
After setting your ISBN values (and any other fields you plan to use in operator==, if it's not finished yet), the way to look for a matching book in the store is:
for(int i = 0; i < books.size(); ++i)
if(*this == books[i]) cout << "test";
In other words, look for a book equal to this book. Or you could use std::find from <algorithms>, although in this case it wouldn't really be any more concise.
By the way, it is unusual to use the same class (Book) to represent both a single book, and the whole store. Unpicking that is a fairly complex set of changes and decisions, though, so I'll just say that a class should represent a single kind of thing, and an object of the class represent an example of that kind. So normally Book and Bookstore are different kinds of thing. The vector in Book is an instance variable, meaning that every Book has its own vector of Books. That doesn't really make sense.
books refers to a vector of Book class. You are comparing Book to an integer, which is undefined behavior. You need to dereference the Book object before you can access its data members.
First, don't access vectors using subscript [] notation. It is inefficient and makes life difficult. Use an iterator (something like, not sure on how you would want to implement):
for (std::vector::iterator it = books.begin(); it != books.end(); ++it)
{
}
That isn't your problem, however. You use the -> operator to dereference objects to get to their members. You made your members private, however, so you either need a get function like
ISBNf() { return ISBNfirst; }
Or make your members public, but that is a bad idea (people can fool with your data). However, for simplicity, assume they are public, this is what you want:
for (std::vector::iterator it = books.begin(); it != books.end(); ++it)
{
if (*this == *it) cout << "test";
}
There is no good solution, here, because I have no idea what you are trying to achieve. I think you are trying to compare the number of digits on the integer, but this is not how to achieve that. If you are just trying to make sure you are assigning ISBNfirst properly, let me put your mind to rest: you are. However, you aren't accessing them correctly, which is where the -> operator comes in.
Next, this code is overkill:
else if(!isdigit(ISBNlast) && !isalpha(ISBNlast)
instead, use the isalphnum() function:
else if (!isalphnum(ISBNlast));
Posted; I will edit my post to point out all the flaws in your code.