I am new to programming and an trying to create an array with a series of records in and then have the programme accept input and finally print out the contents of the list.
I am having trouble recording the values of some of the variables in my addRecord() function as the output of the code below is the following:
constructor called
-1:-1 Eat lunch
-1:-1 Watch TV
destructor called
Why am I missing the call to L1.addRecord(5, 30, "Make dinner"); completely and why aren't the times coming through (they are coming through as -1 which is set in the constructor)?
Thank you
#include <iostream>
#include <string>
using namespace std;
class Record {
private:
int hour;
int minute;
string todo;
public:
Record()
{
hour = -1;
minute = -1;
todo = "N/A";
}
void setData(int hour, int minute, const char* td);
void setData(Record& e);
void printRecord();
};
class List
{
private:
Record* recordArr;
int maxRecords;
int actualRecordCount;
public:
List(int maxRecords);
List(List& s) {
actualRecordCount = s.actualRecordCount;
maxRecords = s.maxRecords;
recordArr = new Record[maxRecords];
for (int i = 0; i < actualRecordCount; i++)
{
recordArr[i].setData(s.recordArr[i]);
}
std::cout << "copy constructor called." << std::endl;
}
~List();
bool addRecord(int hour, int minute, const char* todo);
void printList();
};
///////////////////////////
void Record::setData(int hour, int minute, const char* td)
{
hour = hour;
minute = minute;
todo = td;
}
void Record::setData(Record& e)
{
hour = e.hour;
minute = e.minute;
todo = e.todo;
}
void Record::printRecord()
{
std::cout << hour << ":" << minute << " " << todo << std::endl;
}
List::List(int maxRecords)
: maxRecords(maxRecords)
{
actualRecordCount = 0;
recordArr = new Record[maxRecords];
std::cout << "constructor called" << std::endl;
}
List::~List()
{
std::cout << "\ndestructor called";
delete[] recordArr;
}
bool List::addRecord(int hour, int minute, const char* todo)
{
Record newRecord; // create new Record
newRecord.setData(hour, minute, todo); //assign values
if (actualRecordCount >= maxRecords) // array full
{
return false;
}
else
{
recordArr[actualRecordCount] = newRecord; // put new Record into the array of Entry
actualRecordCount++; // increment Entry count
return true;
}
}
void List::printList()
{
for (int i = 0; i < actualRecordCount; i++)
{
recordArr[i].printRecord();
cout << endl;
i++;
}
}
int main() {
List L1(20);
L1.addRecord(2, 30, "Eat lunch");
L1.addRecord(5, 30, "Make dinner");
L1.addRecord(7, 30, "Watch TV");
L1.printList();
}
void Record::setData(int hour, int minute, const char* td)
{
hour = hour;
"hour" is the name of a parameter to this setData() method. hour=hour;, therefore, sets this parameter to itself. This accomplishes absolutely nothing, whatsoever. Same for other two assignments that follow.
Your obvious intent here is to initialize the class that happens to have members with the same name. When different things have the same name in C++ there's a complicated set of rules that choose which "thing" the name represents. These rules are the same on the left and the right side of the = operator, so both of these hours end up referring to the same object: the parameter to this class method.
You can simply rename the parameters to the method:
void Record::setData(int hourArg, int minuteArg, const char* tdArg)
{
hour = hourArg;
and so on. Or, if you wish to keep the parameter names the same, make things more explicit:
this->hour=hour;
The other error is here
void List::printList()
{
for (int i = 0; i < actualRecordCount; i++)
{
recordArr[i].printRecord();
cout << endl;
i++;
}
}
You have i++ twice.
One problem is that your Record::setData function with three arguments doesn't actually set the hour and minute fields of the class object! This is caused by your use of arguments with the same name as the class members, which (IMHO) is bad coding style. So, in the following code, your first two assignments just replace the argument values with themselves:
void Record::setData(int hour, int minute, const char* td)
{
hour = hour; // This and the following line are self-assignments to the arguments
minute = minute; // given and, as such, are effectively doing nothing!
todo = td; // This, however, is OK, because there is no ambiguity.
}
To fix this, either add an explicit this-> reference to the targets:
void Record::setData(int hour, int minute, const char* td)
{
this->hour = hour;
this->minute = minute;
todo = td;
}
Or (much better, in my opinion) give the first two arguments non-ambiguous names:
void Record::setData(int in_hour, int in_minute, const char* td)
{
hour = in_hour;
minute = in_minute;
todo = td;
}
Related
Below is a program that has class definitions for Item, Customer and Sales. The main simply creates object object of each class and test its member functions. Modify the main program such that it provides a menu driven interface where user can create objects of Item, Customer and a complete a sales transaction with the sales object.The program should also have an option for display the records of items,customers and sales.To make your program more useful,include file handling such that when objects are created for Items,Customers and Transaction,the user will be prompted to save the recordon the file or not.
here's the code it's not displaying anything pleasee help i'm running it by Dev c++
#include <conio.h>
#include <iostream>
#include <string.h>
using namespace std;
class Item {
int itemCode;
private:
double price;
double discount;
protected:
int qtyOnStock;
char *name;
public:
Item() {
itemCode = 0;
strcpy(name, "UNKNOWN");
price = 0;
discount = 0;
qtyOnStock = 100;
}
void setItemCode(int c) { itemCode = c; }
int getItemCode() { return itemCode; }
double getPrice() { return price; }
void setPrice(double p) { price = p; }
void setDiscount(double d) { discount = d; }
double getDiscount(double d) { return ((d < 20 ? d : 20) / 100 * price); }
void setName(char *n) { name = n; }
char *getName() { return name; }
void setQtyOnStock(int q) { qtyOnStock = q; }
int getQtyOnStock() { return qtyOnStock; }
};
class Customer {
private:
int id;
char *name;
char *contactNo;
int type;
public:
Customer() {
id = 0;
strcpy(contactNo, "No Num");
strcpy(name, "No Name");
type = 0;
}
void setId(int newId) { id = newId; }
int getId() { return id; }
void setName(char *n) { strcpy(name, n); }
char *getName() { return name; }
void setContactNo(char *c) { strcpy(contactNo, c); }
char *getContactNo() { return name; }
};
class Sales {
private:
Item item;
Customer cust;
char *date;
int qtySold;
public:
Sales() { date = "mm-dd-yyyy"; }
void setItem(Item newItem) { item = newItem; }
Item getItem() { return item; }
void setCustomer(Customer newCust) { cust = newCust; }
Customer getCustomer() { return cust; }
void setDate(char *newDate) { strcpy(date, newDate); }
char *getDate() { return date; }
void setQtySold(int newQty) { qtySold = newQty; }
int getQtySold() { return qtySold; }
};
int main() {
Item item1;
Customer cust1;
Sales sales1;
item1.setItemCode(143);
item1.setName("Ballpen");
item1.setPrice(12.5);
item1.setQtyOnStock(250);
cust1.setId(123);
cust1.setName("Juan dela Cruz");
sales1.setItem(item1);
sales1.setCustomer(cust1);
sales1.setDate("10-27-2018");
sales1.setQtySold(98);
item1.setQtyOnStock(item1.getQtyOnStock() - sales1.getQtySold());
system("cls");
cout << sales1.getItem().getName() << endl << item1.getQtyOnStock();
getch();
return 0;
}
The main and biggest proble is that you do C-style string handling with char* and even that in a wrong way.
If you would enable all warning in your compiler, it would already tell you the problems. My VS2019 gives 15 errors, 1 warning and 7 messages, when I try to compile your code. Please see:
So, the main problem is that you are using char* that are not initialzed, meaning they point to somehwere, and that you do not allocate memory to store your strings.
So all your strcpy functions will fail and probably crash your system. Also the assignments to a char* will fail in most cases.
You will overwrite some random memory.
All this can be immediately fixed, without big problems, if you would use std::string instead of char*. Because char* are that error prone, C++ introduced the std::string, so, please use it.
Sometimes you have C++ teachers that want you to use char*. Those teachers should be fired. But if you really need to use char*. Then you must allocate memory, before coping data.
Let us assume that you have a string "myName" and you want to copy that.
char* name{};
name = new char[strlen(myName)+1]; // +1 for the trailing '\0'
strcpy(name, myName);
// ...
// ...
// Do stuff
// ...
// ...
delete [] name; // Release memory at the end
But as said. Simply use std::string
Your program as is, cannot work. You need a major refactoring.
In your Item class:
protected:
int qtyOnStock;
char *name;
public:
Item() {
itemCode = 0;
strcpy(name, "UNKNOWN");
price = 0;
discount = 0;
qtyOnStock = 100;
}
name is an unitialized char pointer so copying to it will result in UB.
change char* name to std::string name, replace strcpy(...) name = "UNKNOWN".
Normally though you initialize member variables like this:
Item()
: itemCode(0), itemCode(0), name("UNKNOWN"), price(0), discount(0), qtyOnStrock(100)
{}
a newer compiler lets you initialize in other ways like when declared e.g.:
protected:
int qtyOnStock{100};
std::string name{"UNKNOWN"};
...
i have these set and get methods declared in my main cpp file
void issuesofRelevance::setApproach(int Approach) {
approach = Approach;
}
int issuesofRelevance::getApproach() {
return approach;
}
void issuesofRelevance::setSignifiance(int Significance) {
significance = Significance;
}
int issuesofRelevance::getSignificance() {
return significance;
}
The following H file is attatched in which I call the setMethods in its constructor.
class issuesofRelevance
{
public:
std::vector<std::string> issueName;
int significance;
int approach;
std::vector<std::string> newList;
issuesofRelevance(std::vector<std::string> issueName, int significance, int approach){
issueName = issueName;
significance = significance;
approach = approach;
setApproach(15);
setSignifiance(15);
}
issuesofRelevance();
void setIssues();
std::string getIssues();
void setApproach(int x);
void setSignifiance(int);
int getApproach();
int getSignificance();
};
I call the get functions in main int() as such
cout << object.getApproach();
cout << object.getSignificance();
However, when i go to run the code in the console I get no output when it should return the values of 10 and 15. Im unsure as to why this is occuring
Thankyou.
my full main as requested
int main(int argc, char* argv[]) { //takes in n, number of electorates, and m, the number of campagian days
issuesofRelevance newIssues(newIssues.issueName, newIssues.significance, newIssues.approach);
return 0;
Party party;
Person person;
Electrorates electorate;
string numberofElectoratesAsString = argv[1]; //number of electorates taking as a argument
string DaysOfElectionAsString = argv[2]; //takes in argument 2
int numberofElectorates = std::stoi(numberofElectoratesAsString);
int DaysOfElection = std::stoi(DaysOfElectionAsString );
cout << "Number of electorates: " << electorate.assignID(electorate.numberofElectorates(numberofElectorates));
cout << "Stance: " << person.setinitalStance(numberofElectorates, DaysOfElection) << endl;
newIssues.setIssues();
cout<<newIssues.getApproach()<< " "<<newIssues.getSignificance();
return 0;
}
default constructor
issuesofRelevance::issuesofRelevance(){
}
A problem has come up in my application where my PrintAll function will not work correctly and only ultimately crash my application. My app is supposed to read strings from a file and insert them into an array. The problem is it is reading incorrectly and will ultimately crash my app. Here is where I think the problem lies:
int main()
{
LoadMovies();
MovieList *movies = LoadMovies();
//movies->MovieList::PrintAll();
// // test methods for the Movie and MovieList classes
//PrintAllMoviesMadeInYear(movies, 1984);
//PrintAllMoviesWithStartLetter(movies, 'B');
//PrintAllTopNMovies(movies, 5);
//delete movies;
return 0;
}
MovieList* LoadMovies()
{
vector<string> movies;
ReadMovieFile(movies);
MovieList ml = MovieList(movies.size());
string name;
int year;
double rating;
int votes;
for (int i = 0; i < movies.size(); i++)
{
istringstream input_string(movies[i]);
getline(input_string, name, '\t');
input_string >> year >> rating >> votes;
Movie movie (name, year, votes, rating);
ml.Add(movie);
}
ml.PrintAll();
}
Complete Example:
/*
* File: MovieStatsProgram.cpp
* Author:
* Date:
* ===============================================================
* This is a console app to test the Movie and MovieList classes.
*
* TODO:
*
* You need to finish the implementation of the loadMovies method
* to create and initialize the MovieList object.
*
* You also need to create three static methods:
*
* PrintAllMoviesMadeInYear - it will print all the movies made in a
* given year once sort in alphabetical order and once sorted by the number
* of votes with the movie with the most number of votes printed first.
*
* PrintAllMoviesWithStartLetter - it will print all the movies started with
* a given letter sorted in alphabetical order
*
* PrintAllTopNMovies - it will display the top N movies based on the number of
* votes
*/
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <iomanip>
#include <fstream>
using namespace std;
class Movie {
public:
Movie();
Movie(string n, int y, int v, double r);
string get_name();
void set_name(string n);
int get_year();
void set_year(int y);
int get_votes();
void set_votes(int v);
double get_rating();
void set_rating(double r);
string PrintMovie();
private:
string name;
int year_made;
int votes;
double rating;
};
Movie::Movie() {
name = "null";
year_made = 0;
votes = 0;
rating = 0.0;
}
Movie::Movie(string n, int y, int v, double r) {
name = n;
year_made = y;
votes = v;
rating = r;
}
string Movie::get_name() {
return name;
}
void Movie::set_name(string n) {
name = n;
}
int Movie::get_year() {
return year_made;
}
void Movie::set_year(int y) {
year_made = y;
}
int Movie::get_votes() {
return votes;
}
void Movie::set_votes(int v) {
votes = v;
}
double Movie::get_rating() {
return rating;
}
void Movie::set_rating(double r) {
rating = r;
}
string Movie::PrintMovie() {
cout << fixed << setprecision(1) << rating << "\t\t" << votes << "\t\t" << "(" <<
year_made << ")" << "\t" << name << endl;
}
class MovieList {
public:
MovieList(int size);
~MovieList();
int Length();
bool IsFull();
void Add(Movie const& m);
string PrintAll();
private:
Movie* movies;
int last_movie_index;
int movies_size;
int movie_count = 0;
};
MovieList::MovieList(int size) {
movies_size = size;
movies = new Movie[movies_size];
last_movie_index = -1;
}
MovieList::~MovieList() {
delete [] movies;
}
int MovieList::Length() {
return last_movie_index;
}
bool MovieList::IsFull() {
return last_movie_index == movies_size;
}
void MovieList::Add(Movie const& m)
{
if (IsFull()) {
cout << "Cannot add movie, list is full" << endl;
return;
}
++last_movie_index;
movies[last_movie_index] = m;
}
string MovieList::PrintAll() {
for (int i = 0; i < last_movie_index; i++) {
movies[last_movie_index].Movie::PrintMovie();
//cout << movies[last_movie_index] << endl;
}
}
void ReadMovieFile(vector<string> &movies);
MovieList* LoadMovies();
enum MovieSortOrder
{
BY_YEAR = 0,
BY_NAME = 1,
BY_VOTES = 2
};
int main()
{
LoadMovies();
MovieList *movies = LoadMovies();
//movies->MovieList::PrintAll();
// // test methods for the Movie and MovieList classes
//PrintAllMoviesMadeInYear(movies, 1984);
//PrintAllMoviesWithStartLetter(movies, 'B');
//PrintAllTopNMovies(movies, 5);
//delete movies;
return 0;
}
MovieList* LoadMovies()
{
vector<string> movies;
ReadMovieFile(movies);
MovieList ml = MovieList(movies.size());
string name;
int year;
double rating;
int votes;
for (int i = 0; i < movies.size(); i++)
{
istringstream input_string(movies[i]);
getline(input_string, name, '\t');
input_string >> year >> rating >> votes;
Movie movie (name, year, votes, rating);
ml.Add(movie);
}
ml.PrintAll();
}
void ReadMovieFile(vector<string> &movies)
{
ifstream instream;
instream.open("imdbtop250.txt");
if (instream.fail())
{
cout << "Error opening imdbtop250.txt" << endl;
exit(1);
}
while (!instream.eof())
{
string movie;
getline(instream, movie);
movies.push_back(movie);
}
instream.close();
}
When I use MovieList::PrintAll in the main function, my function just crashes, and when I put it in the LoadMovies function, it will read and add data incorrectly before crashing. The size of the list is 251 and the application will just read the same data 251 times.
You have a two part problem:
1: As Brad S stated, your function returns nothing. This is a no-no.
MovieList* LoadMovies()
{
MovieList ml = MovieList(movies.size());
// Your function returns a pointer to a MovieList, so...
return &ml;
}
So, problem #2 is that you're going to return a pointer to something you created on the stack in your function. When you try to access it outside of your function, you'll run into undefined behavior.
Option 1:
MovieList* ml = new MovieList( movies.size() );
return ml;
You now need to delete ml when you're done w/ it.
Option 2:
Change your function to return a non-pointer... then you don't have the hassle of managing the memory.
EDIT: Try this
int main()
{
// Don't need this
// LoadMovies();
MovieList *movies = LoadMovies();
// Uncommented this
delete movies;
return 0;
}
MovieList* LoadMovies()
{
vector<string> movies;
ReadMovieFile(movies);
// CHANGE
MovieList* ml = new MovieList(movies.size());
// CHANGE
string name;
int year;
double rating;
int votes;
for (int i = 0; i < movies.size(); i++)
{
istringstream input_string(movies[i]);
getline(input_string, name, '\t');
input_string >> year >> rating >> votes;
Movie movie (name, year, votes, rating);
ml.Add(movie);
}
ml.PrintAll();
// CHANGE
return ml;
}
Your MovieList class has a fundamental problem. This comes to light on this line:
MovieList ml = MovieList(movies.size());
Your MovieList class has a member that is a pointer to dynamically allocated memory. Once you have this, you have to manage copying and assignment by creating a user-defined copy constructor and assignment operator.
The easiest fix for this is to use std::vector<Movie> instead of Movie * as a member variable of MovieList. Then copy-assignment comes for free and you don't need to implement further functions.
However, if you can't use std::vector for some reason, the following functions can be added:
class MovieList {
public:
//...
MovieList(const MovieList& m);
MovieList& operator=(MovieList m);
//...
};
#include <algorithm>
//...
// copy constructor
MovieList::MovieList(const MoveList& m) {
movies_size = m.size;
movie_count = m.movie.count;
last_movie_index = m.last_movie_index;
movies = new Movie[movies_size];
for (int i = 0; i < movies_size; ++i)
movies[i] = m.movies[i];
}
//...
// assignment operator
MovieList& MovieList::operator=(MoveList m) {
std::swap(m.movie_size, movie_size);
std::swap(m.last_movie_index, last_movie_index);
std::swap(m.movies, movies);
std::swap(m.movie_count, moviE_count);
return *this;
}
The easiest way to describe this to you is not to describe what these do. The best thing for you is to use your debugger and put a breakpoint in any of these functions and step through the code. When you hit the line I mentioned above, you will more than likely see that the copy constructor function is called -- then you can see it in action as to what it is doing.
The assignment operator is the function that's called when you assign an existing MovieList to another MovieList. It's implemented via the copy/swap idiom. This relies on a working copy constructor (provided above), and a destructor (which you already provided in your code). It works by creating a temporary MovieList, and swapping out the internals of the current MovieList with the temporary MovieList. There are many threads on SO as to how this works.
As to the reason why you need these functions above is that without the above functions, the line:
MovieList ml = MovieList(movies.size());
will create two MovieList objects, one temporary and one non-temporary, however the movies pointer for both will be pointing to the same memory. When the temporary is destroyed, the destructor is called, thus deleting the memory pointed to by movies. Now you have m1 pointing to memory that has gone up in smoke. Bad news when you try to use m1.
The user-defined copy and assignment functions above properly copy the object so that you get two distinct memory allocations for movies, so that when the destructor is called, the memory deleted will be unique to that object.
Again, all of this would be alleviated if you used std::vector and forego having to write copy ctor/assignment operators.
I have two classes (appointment, schedule), and a driver (main).
main.cpp:
#include <iostream>
#include "schedule.h"
#include "appointment.h"
using namespace std;
int main()
{
schedule mySch2("hello");
appointment myAppt(100002,"appointment",10,1,2013);
myAppt.printS(cout,2);
mySch2.addtoSchedule(myAppt);
system("PAUSE");
return EXIT_SUCCESS;
}
schedule.h
#ifndef SCHEDULE_H
#define SCHEDULE_H
#include<iostream>
#include "appointment.h"
using namespace::std;
const int SCH_ENTRIES = 10;
class schedule
{
public:
schedule(void);
schedule(const char *p);
bool addtoSchedule(const appointment &);
private:
char title[40];
int count;
appointment appointmentArray[SCH_ENTRIES];
};
#endif
schedule.cpp
#include "schedule.h"
#include "appointment.h"
#include <iostream>
using namespace::std;
schedule::schedule(void)
{
}
schedule::schedule(const char *p)
{
strcpy(title, p);
count = 0;
cout << title << endl;
cout << count << endl;
cout << "----" << endl;
}
bool schedule::addtoSchedule(const appointment & myAppt)
{
cout << appointmentArray[0].getDay();
return false;
}
appointment.h (I did not write this, this was provided) - not super important for this question
#ifndef APPOINTMENT_H
#define APPOINTMENT_H
#include <fstream>
#include <cstring>
using std::ostream;
// The Designer decides upon the following data and actions (i.e. Functions)
// and places the class in the file appointment.h
class appointment
{
public:
appointment(void); // default constructor
appointment(long, const char [],int d, int m, int y); // 5 argument constructor
appointment(const appointment &); // copy constructor
void keyBoardInput(void); // Assume no blanks in the desc
long getSource(void) const; // return source
void setSource(long); // change source
void setMonth(int);
void setDay(int);
void setYear(int);
int getMonth(void) const;
int getDay(void) const;
int getYear(void) const;
const char *getDescription(void) const; // return the address of the description
void changeDescription(const char *) ; // change an existing description
void copyTo(appointment &) const; // copy invoking instance to parameter
void incrementDate (void); // advance the date by ONE day
// You can assume 30 days in each month
void printS(ostream &, int dateFormat) const; // print all fields
// dateFormat == 1 month/day/year
// dateFormat == 2 day/month/year
~appointment(); // destructor - indicate the address
// of the variable that is leaving
private:
void setDescription(const char *); // used to allocated memory
// data
long source; // id of the person scheduling the appointment
char * desc; // description of the appointment - Dynamic Data
int day; // day, month, and year when the appointment
int month; // will happen
int year;
};
#endif
appointment.cpp (I did not write this, this was provided) - not super important for this question
#include "appointment.h"
#include <iostream>
using std::cin;
using std::cout;
appointment::appointment()
{
day = 0;
cout << "default appt\n";
}
appointment::appointment(long lSource, const char cDescription[], int d, int m, int y)
{
source = lSource;
day = d;
month = m;
year = y;
setDescription(cDescription);
}
appointment::appointment(const appointment & aToCopy)
{
source = aToCopy.getSource();
day = aToCopy.getDay();
month = aToCopy.getMonth();
year = aToCopy.getYear();
setDescription(aToCopy.getDescription());
}
void appointment::setDescription(const char * cSource)
{
if (desc != NULL) free (desc);
if (cSource == NULL)
return;
desc = (char *)malloc (strlen (cSource) + 1);
strcpy(desc, cSource);
}
long appointment::getSource(void) const
{
return source;
}
void appointment::setSource(long lSource)
{
source = lSource;
}
void appointment::setMonth(int iMonth)
{
month = iMonth;
}
void appointment::setDay(int iDay)
{
day = iDay;
}
void appointment::setYear(int iYear)
{
year = iYear;
}
int appointment::getMonth(void) const
{
return month;
}
int appointment::getDay(void) const
{
return day;
}
int appointment::getYear(void) const
{
return year;
}
//return the address of the description
const char * appointment::getDescription(void) const
{
return desc;
}
//change an existing description
void appointment::changeDescription(const char * cDescription)
{
setDescription(cDescription);
}
void appointment::copyTo(appointment &p) const
{
p.source = source;
p.day = day;
p.month = month;
p.year = year;
p.setDescription(desc);
}
void appointment::incrementDate(void)
{
int days;
switch (month)
{
case 1: // Jan: 31 Days
case 3: // Mar: 31 Days
case 5: // May: 31 Days
case 7: // Jul: 31 Days
case 10: // Oct: 31 Days
case 12: // Dec: 31 Days
days = 31;
break;
case 4: // Apr: 30
case 6: // Jun: 30
case 8: // Aug: 30
case 9: // Sep: 30
case 11: // Nov: 30
days = 30;
break;
case 2: // Feb: 28/29 Days (Depends on year modulus 4 a modulus 100).
days = !(year % 4) || !(year % 100) ? 29 : 28;
break;
}
day++;
if (day > days)
{
month++;
day = 1;
if (month > 12)
{
month = 1;
year++;
}
}
}
void appointment::printS(ostream &out, int dateFormat) const
{
if (dateFormat == 1)
{
out << month << "/" << day << "/" << year << "\n";
}
else if (dateFormat == 2)
{
out << day << "/" << month << "/" << year << "\n";
}
else
out << "Unsupported dateFormat parameter specified (should be 1 or 2).";
}
appointment::~appointment()
{
if (desc != NULL)
{
free (desc);
desc = NULL;
}
}
void appointment::keyBoardInput()
{
char temp[1024];
cout << "Please type the description: ";
cin.getline (temp, sizeof(temp) - 1, '\n');
cout << std::endl;
setDescription(temp);
}
My error occurs when the main driver calls mySch2.addtoSchedule(myAppt);
If I uncomment out the line inside of schedule appointmentArray[0].getDay() then everything runs and works fine with no segmentation error. As soon as that line gets uncommented, it throws the error during runtime (after a crash and I go into the debugger and step through the program).
You never initialize desc to nullptr for class appointment before invoking setDescription. This happens in both constructors. Learn to use an initializer list:
appointment::appointment()
: source(), desc(), day(), month(), year()
{
cout << "default appt\n";
}
appointment::appointment(long lSource, const char cDescription[], int d, int m, int y)
: source(lSource), desc(), day(d), month(m), year(y)
{
setDescription(cDescription);
}
appointment::appointment(const appointment & aToCopy)
: source(aToCopy.getSource())
, desc()
, day(aToCopy.getDay())
, month(aToCopy.getMonth())
, year(aToCopy.getYear())
{
setDescription(aToCopy.getDescription());
}
Why did it fault?
Without initialization the value in desc is indeterminate and therefore undefined behavior to dereference, and certainly so to pass to free.
void appointment::setDescription(const char * cSource)
{
if (desc != NULL) free (desc); // desc contains non-null garbage.
if (cSource == NULL)
return;
desc = (char *)malloc (strlen (cSource) + 1);
strcpy(desc, cSource);
}
That said, I would strongly encourage using a std::string instead. It would make the copy-consructor for this class completely disappear, and the default constructor trivial.
Comments about using malloc() in a C++ program reserved, as that opinion is all-but beat to death already on this forum (and I agree with te prevailing opinion).
I'm attempting to make my class do the following...
EmployeeHandler: Initializes m_employeeCount to zero.
AddEmployee: Invoked by menu option 1. Displays "NEW EMPLOYEE". Prompts the user for
the employee’s first name, last name, and pay rate, one at a time. Uses Employee.Setup to add
an employee to m_lstEmployee. Displays "Employee m_employeeCount added". Increments
m_employeeCount.
EmployeeSelection: Displays the list of employees, by index; prompts the user for an employee
index and returns the index.
EditEmployee: Invoked by menu option 2. Uses EmployeeSelection to get the index of the
employee to edit. Verifies if the index is valid and displays an error message if it is not. Uses
Employee.Output to display the selected employee’s current information. Prompts the user for
the employee’s new first name, last name, and pay rate, one at a time. Uses Employee.Setup to
change the employee’s information in m_lstEmployee. Displays “** Employee index updated”,
where index is the user selected index.
LayoffEmployee: Invoked by menu option 3. Uses EmployeeSelection to get the index of the
employee to lay-off. Uses Employee.Output to display the selected employee’s first name, last
name, and pay rate. Uses Employee.LayOff to lay the employee off. Displays "Employee
index laid off", where index is laid off employee’s index.
DisplayEmployeeList: Invoked by menu option 4. Displays "EMPLOYEES". Then uses
Employee.Output to display every employee record something like this, "[1] David Johnson,
PAY: $5.00 (CURRENT EMPLOYEE)" and a former employee record something like this, "[2]
David Johnson, PAY: $5.00 (FORMER EMPLOYEE)", where the number in the brackets is the
employee’s index in m_lstEmployee.
GetEmployee: Returns the address of the selected employee record in m_lstEmployee.
GetEmployeeCount: Returns the number of employees in m_employeeCount.
So far I have...
#ifndef _EMPLOYEEHANDLER
#define _EMPLOYEEHANDLER
#include "Employee.h"
class EmployeeHandler
{
public:
EmployeeHandler()
{
m_employeeCount = 0; //undefined?
};
void AddEmployee()
{
string firstName;
string lastName;
float payRate;
cout<<"NEW EMPLOYEE"<<endl;
cout<<"First Name:"<<endl;
cin>>firstName;
cout<<"Last Name:"<<endl;
cin>>lastName;
cout<<"Pay Rate:"<<endl;
cin>>payRate;
Employee.Setup(firstName,lastName,payRate); //Problem here
cout<<"**Employee m_employeeCount added"<<endl;
m_employeeCount+=1; //m_employeeCount undefined?
}
void EditEmployee()
{
int indexEdit;
string newFirst;
string newLast;
float newPay;
cout<<"Which employee would you like to edit"<<endl;
cin>>indexEdit;
EmployeeSelection(indexEdit); //undefined?
Employee.Output(); //
cout<<"Employee new first name:"<<endl;
cin>>newFirst;
cout<<"Employee new last name:"<<endl;
cin>>newLast;
cout<<"Employee new pay rate:"<<endl;
cin>>newPay;
Employee.Setup(newFirst,newLast,newPay); ///
cout<<"** Employee index updated"<<endl;
}
void LayoffEmployee()
{
EmployeeSelection();
Employee.Output(EmployeeSelection); //Problems here
Employee.LayOff(EmployeeSelection);
cout<<"Employee laid off"<<endl;
}
void DisplayEmployeeList()
{
cout<<"EMPLOYEES"<<endl;
for (int i=0; i<50; i++)
cout<<[i]<<Employee.Output(m_1stEmployee)<<endl; //
}
int EmployeeSelection()
{
int indexNumber;
for (int i= 0; i <50; i++)
cout<<[i]m_1stEmployee<<endl; //
cout<<"Which Employee Index would you like to select?"<<endl;
cin>>indexNumber;
for (int i = 0; i <50; i++)
if ([i]=indexNumber) //
return [i]
}
Employee& GetEmployee( int index )
{if (index=; // completely confused here
}
int GetEmployeeCount()
{
return m_employeeCount;
};
private:
Employee m_lstEmployee[50];
int m_employeeCount;
};
#endif
The employee.h file is as follows...
#ifndef _EMPLOYEE
#define _EMPLOYEE
#include<iostream>
#include<iomanip>
#include <string>
using namespace std;
class Employee
{
public:
void Setup( const string& first, const string& last, float pay );
{
m_firstName = first;
m_lastName = last;
m_payPerHour = pay;
m_activeEmployee = true;
}
string GetName()
{
return m_firstName+""+m_lastName
};
bool GetIsActive()
{
return m_activeEmployee;
};
void LayOff()
{
m_activeEmployee= false;
};
void Output()
cout<<GetName()<<",PAY:$"<<fixed<<setprecision(2)<<m_payPerHour<<endl;
private:
string m_firstName;
string m_lastName;
float m_payPerHour;
bool m_activeEmployee;
};
#endif
I've been stuck writing this class for the last two days trying to figure out what I'm doing wrong. This is the first time I've attempted to write classes in C++. Any and all help is much, much appreciated. I have marked places where I'm having problems with //.
Your code has many, many problems...
I'll start by providing compilable code that more or less does what you want. I'm not sure how you can go about asking questions, but compare it to your own code and read a good c++ book...
I've replaced your array with a vector. I've used a constructor to initialize Employee. I've (to my own dismay) added std, mainly because Employee shall live in its own header and it's not good to use a namespace in a header.
In c++ the operator[] is postfix (after the indexed expression).
Also, under normal circumstances I'll try and keep interface and implementation seperate where possible. At the least I would not use inline functions if not absolutely necessary.
The new code...:
#include <iostream>
#include <iomanip>
#include <vector>
#include <iterator>
#include <string>
class Employee
{
public:
//This is a constructor....
Employee( const std::string& first, const std::string& last, float pay )
//The members can be initialized in a constructor initializer list as below.
: m_firstName( first ), m_lastName( last ), m_payPerHour( pay ),
m_activeEmployee() //Scalars are initialized to zero - bool to false...
{
}
std::string GetName() const
{
return m_firstName+" "+m_lastName;
}
bool GetIsActive() const
{
return m_activeEmployee;
};
void LayOff()
{
m_activeEmployee = false;
}
std::ostream& Output( std::ostream& out ) const
{
return out << GetName() <<",PAY:$"
<< std::fixed << std::setprecision(2) << m_payPerHour;
}
private:
std::string m_firstName;
std::string m_lastName;
float m_payPerHour;
bool m_activeEmployee;
};
inline std::ostream& operator << ( std::ostream& os, const Employee& employee )
{
return( employee.Output( os ) );
}
class EmployeeHandler
{
public:
void AddEmployee()
{
std::string firstName;
std::string lastName;
float payRate;
std::cout<<"NEW EMPLOYEE"<<std::endl;
std::cout<<"First Name:"<<std::endl;
std::cin>>firstName;
std::cout<<"Last Name:"<<std::endl;
std::cin>>lastName;
std::cout<<"Pay Rate:"<<std::endl;
std::cin>>payRate;
employees_.push_back( Employee( firstName,lastName,payRate ) );
std::cout<<"**Employee m_employeeCount added"<<std::endl;
}
void EditEmployee()
{
std::string newFirst;
std::string newLast;
float newPay;
std::cout<<"Which employee would you like to edit"<<std::endl;
int indexEdit = GetSelection();
Employee& employee = employees_[indexEdit];
std::cout << employee << std::endl;
std::cout<<"Employee new first name:"<<std::endl;
std::cin>>newFirst;
std::cout<<"Employee new last name:"<<std::endl;
std::cin>>newLast;
std::cout<<"Employee new pay rate:"<<std::endl;
std::cin>>newPay;
employee = Employee( newFirst, newLast, newPay );
std::cout<<"** Employee index updated"<<std::endl;
}
void LayoffEmployee()
{
int index = GetSelection();
if( employees_[index].GetIsActive() )
{
std::cout << "Laying off employee:\n" << employees_[index] << std::endl;
employees_[index].LayOff();
}
else
{
std::cerr << "Already layed off employee:" << employees_[index] << std::endl;
}
}
void DisplayEmployeeList()
{
std::copy( employees_.begin(), employees_.end(), std::ostream_iterator<Employee>( std::cout, "\n" ) );
}
int GetSelection()
{
std::size_t indexNumber;
std::cout << "Select an employee from the list below by specifying its number:" << std::endl;
DisplayEmployeeList();
do{
while( !std::cin >> indexNumber )
{
std::cin.clear();
std::cin.ignore();
std::cerr << "Select a number..." << std::endl;
}
if( indexNumber >= employees_.size() )
{
std::cerr << "Select a number within range of list below:" << std::endl;
DisplayEmployeeList();
}
}
while( indexNumber >= employees_.size() );
return indexNumber;
}
Employee& operator[]( std::size_t index )
{
return employees_[index];
}
const Employee& operator[]( std::size_t index ) const
{
return employees_[index];
}
std::size_t EmployeeCount() const
{
return employees_.size();
}
private:
std::vector<Employee> employees_;
};
int main( int argc, char* argv[] )
{
return 0;
}
Finally - the code is merely compiled, not tested. I suspect I might have made a mistake, but alas, time!!!