sort array of objects alphabetically c++ - c++

I am enrolled in an Object Oriented programming class and am using code::blocks as my IDE. We have a project that requires to pass an array of objects ( a Libray book array with private names and titles) into a sort array that will sort the titles or authors alphabetically. I have all the components working as they should be except the sort function. I used a sort function that I have used before in other programs but am having trouble getting it to work with this program. I am still in the beginning stages of learning how to code and would appreciate any feedback.
Header file:
#include <iostream>
#include <cstring>
using namespace std;
class Book
{
private:
string title;
string author;
public:
Book();
string getTitle();
string getAuthor();
void setTitle(string Title1);
void setAuthor(string Author1);
};
Main:
#include <iostream>
#include <cstring>
#include <iomanip>
#include "Library.h"
using namespace std;
//Sort function prototype
void s_sort (Book lib_books[], int n);
int main()
{
// Initializes n as the number of books
int n = 15;
//Declaration of array of objects
Book lib_books[15];
// Declartion of the private member "title" for each object
lib_books[0].setTitle("The Alchemist");
lib_books[1].setTitle("The Princess Bride");
lib_books[2].setTitle("The Catcher in the Rye");
lib_books[3].setTitle("1984");
lib_books[4].setTitle("Fahrenheit 451");
lib_books[5].setTitle("The Great Gatsby");
lib_books[6].setTitle("Poland");
lib_books[7].setTitle("The Cantebury Tales");
lib_books[8].setTitle("Leaves of Grass");
lib_books[9].setTitle("Where the Sidewalk Ends");
lib_books[10].setTitle("The Iliad");
lib_books[11].setTitle("Things to Think On");
lib_books[12].setTitle("The Grapes of Wraith");
lib_books[13].setTitle("Hop on Pop");
lib_books[14].setTitle("The Prince and the Pauper");
// Declartion of the private member "author" for each object
lib_books[0].setAuthor ("Paulo Coalho");
lib_books[1].setAuthor ("William Goldman");
lib_books[2].setAuthor ("J.D. Salinger");
lib_books[3].setAuthor ("George Orwell");
lib_books[4].setAuthor ("Ray Bradbury");
lib_books[5].setAuthor ("F. Scott Fitzgerald");
lib_books[6].setAuthor ("James A. Mitchener");
lib_books[7].setAuthor ("Chaucer");
lib_books[8].setAuthor ("Walt Whitman");
lib_books[9].setAuthor ("Shel Silverstein");
lib_books[10].setAuthor("Homer");
lib_books[11].setAuthor("Krishnamurti");
lib_books[12].setAuthor("John Steinbeck");
lib_books[13].setAuthor("Dr. Seuss");
lib_books[14].setAuthor("Mark Twain");
The portion of main that I'm having issues:
// Function to sort the books alphabetically by author
s_sort (lib_books,n);
cout << "\n";
// For loop to print all 15 books with author and title
for(int i = 0; i < 14; i++)
{
cout <<" "<<setw(25)<<lib_books[i].getTitle()<< " " <<lib_books[i].getTitle()<< "\n" ;
}
return 0;
}
//Sort function definition
void s_sort (Book::getTitle(), int n)
{
int m;
string hold;// Initializes 'hold' as a 'string' so all the characters will be used when it is sorted
for (int k=0; k<=n-1; k++)// 'For' loop sorts through the index
{
m = k;
for (int j=k+1; j <= n-1; j++)
{
if (lib_books[j].getTitle() < lib_books[m].getTitle());
//m = j;
}
// Swaps the lib_book[].getTitle() around and uses 'hold' as a placement
hold = lib_books[m].getTitle();
lib_books[m].getTitle() = lib_books[k].getTitle();
lib_books[k].getTitle() = hold;
hold = lib_books[m].getAuthor();
lib_books[m].getAuthor() = lib_books[k].getAuthor();
lib_books[k].getAuthor() = hold;
}
}
Implementation file:
#include <iostream>
#include <cstring>
#include "Library.h"
using namespace std;
Book::Book()
{
title = " ";
author = " ";
}
string Book::getTitle()
{
return title;
}
string Book::getAuthor()
{
return author;
}
void Book::setTitle(string Title1)
{
title= Title1;
}
void Book::setAuthor(string Author1)
{
author= Author1;
}
The problem that I am having is that it doesn't sort the array. It prints out the same list that was defined. I have tried to pass the array by reference but it needs a index number in the function prototype and definition.

Related

How to Define CountProbation() function using Functions from other Files?

I have been racking my brain on how to properly define the function CountProbation() properly in the Course.css file. I know that a for and if loop should probably be included but I am having trouble including functions from other files, even though I am including a header tag at the beginning of the current Course.css file.
Below are the C++ files that are given in the lab:
NOTE: Only the Course.cpp file is the one that needs to be edited. All of the other files are READ ONLY and purely for your information as the reader.
Sorry if it seems like a lot of code, but I didn't just want to include the Course.cpp file because then you might not understand the program.
Here are the compiler Errors/Warnings:
Course.cpp: In member function ‘int Course::CountProbation()’:
Course.cpp:8:18: warning: comparison of integer expressions of different signedness: ‘int’ and ‘std::vector<Student>::size_type’ {aka ‘long unsigned int’} [-Wsign-compare]
8 | for (int i=0; i < roster.size(); ++i) {
| ~~^~~~~~~~~~~~~~~
Course.cpp:9:9: error: ‘GetGPA’ was not declared in this scope
9 | if (GetGPA() < 2.0) {
| ^~~~~~
Course.cpp
#include <iostream>
#include "Course.h"
#include "Student.h"
using namespace std;
int Course::CountProbation() { //This is the function that I have tried to define as you can see by my
int probCount; //code
for (int i=1; i < roster.size(); ++i) {
if (GetGPA() < 2.0) {
probCount = probCount + 1;
}
}
return probCount;
}
void Course::AddStudent(Student s) {
roster.push_back(s);
}
Course.h (READ ONLY)
#ifndef COURSE_H
#define COURSE_H
#include <vector>
#include "Student.h"
class Course {
public:
int CountProbation();
void AddStudent(Student s);
private:
vector<Student> roster; //collection of Student objects
};
#endif
Main.cpp (READ ONLY)
#include <iostream>
#include <string>
#include "Course.h"
using namespace std;
int main() {
Course course;
int probCount;
// Example students for testing
course.AddStudent(Student("Henry", "Cabot", 3.2));
course.AddStudent(Student("Brenda", "Stern", 1.1));
course.AddStudent(Student("Lynda", "Robison", 2.4));
course.AddStudent(Student("Jane", "Flynn", 1.8));
probCount = course.CountProbation();
cout << "Probation count: " << probCount << endl;
return 0;
}
Student.h (READ ONLY)
#ifndef STUDENT_H
#define STUDENT_H
#include <string>
using namespace std;
// Class representing a student
class Student {
public:
Student(string first, string last, double gpa);
double GetGPA() ;
string GetLast();
private:
string first; // first name
string last; // last name
double gpa; // grade point average
};
#endif
Student.cpp (READ ONLY)
#include "Student.h"
// Student class constructor
Student::Student(string first, string last, double gpa) {
this->first = first; // first name
this->last = last; // last name
this->gpa = gpa; // grade point average
}
double Student::GetGPA() {
return gpa;
}
string Student::GetLast() {
return last;
}
This loop (as it was coded in the original question, before it was edited):
for (int i=1; i < roster.size(); ++i) {
if (Student.GetGPA() < 2.0) {
probCount = probCount + 1;
}
}
is flawed for three reasons:
i should start from 0, rather than 1
i should be of type size_t, rather than int
Student is a type, not a variable
A nice way to solve all these problems is to use a ranged for loop, like this:
for (Student &student : roster)
{
if (student.GetGPA() < 2.0)
probCount = probCount + 1;
}
As mentioned in the comments, you also need to initialise probCount to zero before entering the loop:
int probCount = 0;
Finally, it's worth noting that the above loop would normally be coded as:
for (const Student &student : roster)
{
...
but that won't work here as GetGPA is not declared as a const method. Thanks to #user4581301 for pointing this out.

How do you compare and sort a specific parameter within a class?

My professor has asked us to make a program that will take a user's input and continue reading until the end of input. Only then, can the program output what the user has typed.
Input should be based on video title, it's url, comments made on the video, length (in minutes), and rating (in *).
For example:
United Break Guitars, https://www.youtube.com/watch?v+5YGc4zOqozo, Great example of one person getting a giant company to listen, 4.5, ***, Space Versus Tabs, https://www.youtube.com/watch?v=SsoOG6ZeyUl, Decide for yourself: spaces or tabs?, 2.83, ****
Up until what is explained, I have completed and tested to see if everything works. My problem is the next part of the project which requires the user to choose between Rating, Length, or title then sort them based on what the user chose.
If I chose Rating, then the input above should be sorted from highest rated video to lowest.
This is what I have so far:
#include <iostream>
#include <stdlib.h>
#include <cstring>
#include <algorithm>
using namespace std;
#include "video.h"
int main()
{
string user, url, comment, title;
int rating;
double length;
int i = 0, last = 0;
Video *videoObj[100];
Video *temp[100];
// specifies how the videos should be sorted
cin >> user;
cin.ignore();
while (getline(cin,title) ) {
getline(cin, url);
getline(cin, comment);
cin >> length;
cin >> rating;
cin.ignore();
videoObj[i] = new Video(title, url, comment, length, rating);
i++;
last++;
}
temp[i] = new Video(title, url, comment, length, rating);
if(user=="rating"){
for(int i = 0; i < last - 1; i++){
for(int j = i+1; j< last; j++){
if(videoObj[i] -> Rating(videoObj[j])) {
temp[i] = videoObj[i];
videoObj[i]= Rating(videoObj[j]);
Rating(videoObj[j]) = temp[i];
}
}
}
}
for(int i= 0; i < last; i++)
{
videoObj[i]->print();
}
//delete[] videoObj;
return 0;
}
video.cpp file:
#include <iostream>
#include <algorithm>
using namespace std;
#include "video.h"
Video::Video(string video_title, string video_link, string video_comment, double video_length, int video_number)
: title(video_title), link(video_link), comment(video_comment), length(video_length), rating(video_number)
{
}
bool Video::Rating(Video *videoObj) {
if(rating > videoObj-> rating )
{
return true;
}
else
{
return false;
}
}
void Video::print(){
string star;
switch(rating){
case 1:
star = "*";
break;
case 2:
star = "**";
break;
case 3:
star = "***";
break;
case 4:
star = "****";
break;
case 5:
star = "*****";
break;
}
cout << title << ", " << link << ", " << comment << ", " << length << ", " << star << endl;
}
void Video::temp(){
title, link, comment, length, rating;
}
video.h file:
#ifndef VIDEO_H
#define VIDEO_H
using namespace std;
class Video {
public:
Video(string video_title, string video_link, string video_comment, double video_length, int video_number);
void print();
bool Rating(Video *videoObj);
void temp();
private:
string title;
string link;
string comment;
double length;
int rating;
};
#endif
I honestly have no idea how to implement the bubble sort correctly. I have looked up multiple different videos on youtube and posts on stackoverflow, but I can't seem to figure out how to sort a specific parameter within my class.
My professor gave us these instructions for sorting within our class:
When sorting the videos you need to be able to determine how two video objects should be
ordered. The easiest way to do this is to write member functions to handle the comparisons in
class Video. For example, this method could be used when sorting the videos by length:
// return true if the current video is longer than the given video (other) ,
// otherwise return false
bool Video :: longer(Video *other) {
return (mlength > other -> mlength ;
}
I'm not even sure if I did that part correctly in my video.cpp file. Any ideas on how I can get the sorting method to work properly?
Please be gentle, I'm very new to programming. I realize my bubble sort is wrong as well, I just don't know where to start fixing it...
I'd normally use std::sort with a comparison operator for each field you want to be able to compare. You can implement those either as named classes:
struct by_title {
bool operator()(Video const &a, Video const &b) {
return a.title < b.title;
}
};
struct by_rating {
bool operator()(Video const &a, Video const &b) {
return a.rating < b.rating;
}
};
// ...
std::sort(videos.begin(), videos.end(), by_rating);
std::sort(videos.begin(), videos.end(), by_title);
...or you can use a lambda expression to define a comparison:
// sort by rating
std::sort(videos.begin(), videos.end(), [](auto &a, auto &b) { return a.rating < b.rating; });
// sort by title
std::sort(videos.begin(), videos.end(), [](auto &a, auto &b) { return a.title < b.title; });

What is the problem I am having with using arrays with classes?

I have been working on a project for my computer science class and have encountered an issue with the code working. I am shown no error except when I try to compile and I get an error that reads:
Exception thrown: write access violation.
_Left was 0xCCCCCCCC.
The purpose of my project is to take a list of names from an external file, read them into an array, sort said array and then output the sorted list all while using a class for the code.
Here is a copy of my code and I would like to extend my gratitude to whoever can help me through my issue:
**Header File**
#include <iostream>
using namespace std;
class person
{
public:
person();
bool get(ifstream&);
void put(ofstream&);
private:
int capacity = 0;
string first_name[CAPACITY];
string last_name[CAPACITY];
int age[CAPACITY];
};```
**Header function definitions cpp file**
#include<iostream>
#include<string>
#include<fstream>
#include<cstdlib>
const int CAPACITY=20;
using namespace std;
#include "Person.h"
//Names constructor
//Postcondition both first name and last name initialized to zero
person::person()
{
first_name[CAPACITY] = "";
last_name[CAPACITY] = "";
age[CAPACITY]=0;
}
bool person::get(ifstream& in)
{
in >> first_name[CAPACITY] >> last_name[CAPACITY] >> age[CAPACITY];
return(in.good());
}
void person::put(ofstream &out)
{
out << first_name[CAPACITY] << last_name[CAPACITY] << age[CAPACITY];
}
**cpp file which holds main**
#include<iostream>
#include<cstdlib>
#include<fstream>
#include<string>
const int CAPACITY = 20;
using namespace std;
#include "Person.h"
void pop(string *xp, string *yp);
void sort(string name[CAPACITY], int count);
int main()
{
class person names[CAPACITY];
ifstream infile;
ofstream outfile;
string filename;
string name[CAPACITY];
int n = 0;
cout << "Enter the file name you wish to open" << endl;
cin >> filename;
infile.open(filename + ".txt");
outfile.open("Person_New.txt");
if (infile.fail())
{
cout << "The file requested did not open" << endl;
exit(1);
}
while (!infile.eof())
{
names[n].get(infile);
n++;
}
sort(name, CAPACITY);
for (int i = 0; i < CAPACITY; i++)
{
names[i].put(outfile);
}
cout << "The file has been created" << endl;
infile.close();
}
void pop(string *xp, string *yp)
{
string temp = *xp;
*xp = *yp;
*yp = temp;
}
void sort(string name[CAPACITY], int count)
{
int i, j;
for (i = 0; i < count - 1; i++)
{
for (j = 0; j < count - i - 1; j++)
{
if (name[j] > name[j + 1])
{
pop(&name[j], &name[j + 1]);
}
}
}
}
Once again Thank you for any support
It sounds to me like the compiler is getting upset that you are trying to write (i.e. assign a value) at an address that you do not have permission to access. I believe your constructor for the class person might be at fault because of how this class stores its variables, as well as the class header:
Constructor for the class person:
`person::person(){
first_name[CAPACITY] = "";
last_name[CAPACITY] = "";
age[CAPACITY] = 0;
}`
Class header for the class person:
`class person{
public:
//stuff
private:
int capacity = 0;
std::string first_name[CAPACITY];
std::string last_name[CAPACITY];
int age[CAPACITY];
//more stuff
}`
C++ is very specific about its naming conventions, so it makes a distinction between capacity and CAPACITY. Because of this, the variable CAPACITY is not defined within the Person.h file.
Also, because CAPACITY is set to a fixed value in your Person.cpp file, whenever you use first_name[CAPACITY], last_name[CAPACITY], or age[CAPACITY] to assign new values, you are only updating the values at the index equal to CAPACITY unless you update the value of CAPACITY itself. In the code you provided, CAPACITY is equal to 20, so your program attempts to update exclusively index 20 with each method call. This will likely cause issues since the person class only attempts to make its arrays on the runtime stack, with a size of 0 each.
Separately, it seems like you want an array of people, but it appears that you are attempting to use a single person object to store the names and ages of multiple people by making these all arrays. Instead, I would recommend making first_name, last_name, and age not arrays, but rather single variables. Then, you can manipulate an array of type person using your CAPACITY variable. You got pretty close, but you can instead declare it as person myPersonArray[CAPACITY] (no need to mention "class" in front of it -- just be sure that you have #include "Person.h" in your main.cpp file). When you want to update a specific person, you can perform an operation like myPersonArray[updateThisIndexNum].update(newFirstName, newLastName, newAge) or some logical equivalent.
As a final note, I almost always highly recommend against using !infile.eof() to control your while loop when reading any file because eof() only indicates whether you have tried to read past the end of an input file. I would highly recommend checking out this post on Stack Overflow where people far more knowledgeable than I explain exactly why this is usually dangerous and how to avoid it.

Passing an array of pointers to a Class Object

Hoping someone can help a beginner out here. I searched but some of the solutions were out of scope my knowledge. I'm trying to create a function which will take in a an array of pointers to a class object and output a getName() function for each object. But I keep getting a "no instance of overloaded function". I can't figure out what the problem is. Please take a look at following code.
#include <iostream>
#include "Student.hpp"
#include <string>
using namespace std;
void getName(Student *studentArray[], int); //prototype
int main()
{
//Creates class objects with Constructors Name and Score
//Class object has a function getName() to return name
Student stud1("John", 100);
Student stud2("Mary", 90);
Student stud3 ("Jack", 85);
//Create an array of student objects
Student myArray[3]= {stud1, stud2, stud3};
//ERROR HERE NO INSTANCE OF OVERLOADED FUNCTON
getName(myArray, 3)
return 0;
}
void getName(Student *studentsArray[], int arraySize)
{
for(int index=0; index < arraySize; index++)
{
cout << studentsArray[index]->getName() << endl;
}
}
Student *studentsArray[] is an array of pointers to students:
[-> "John", -> "Mary", -> "Jack"]
While Student *studentsArray is a pointer to a student (e.g. the first of an array):
-> [ "John", "Mary", "Jack" ]
using the [] operator you can jump to the offset relative to a pointer
studentsArray[0] == (*studentsArray)
studentsArray[1] == *(studentsArray+1)
studentsArray[2] == *(studentsArray+2)
and the -> operator is syntactic sugar for (*var).
The problem is that you created an array of students instead of an array of pointers of students:
Student myArray[3] = {stud1, stud2, stud3};
should actually be
Student* myArray[3] = { &stud1, &stud2, &stud3 };
Here is a full working example:
#include <iostream>
#include "Student.hpp"
#include <string>
using namespace std;
void getName(Student *studentsArray[], int); //prototype
int main()
{
//Creates class objects with Constructors Name and Score
//Class object has a function getName() to return name
Student stud1("John", 100);
Student stud2("Mary", 90);
Student stud3("Jack", 85);
//Create an array of student objects
Student* myArray[3] = { &stud1, &stud2, &stud3 };
getName(myArray, 3);
return 0;
}
void getName(Student *studentsArray[], int arraySize)
{
for (int index = 0; index < arraySize; index++)
{
cout << studentsArray[index]->getName() << endl;
}
}
The most important thing is that your pointer doesn't actually point any existing variable or its address. In this case, pointer will instead point a randomly chosen memory cell address, so it's really dangerous because you will never know what it will cause, including data lose, memory leak and so on.
With std::vector, it would be something like:
#include "Student.hpp"
#include <iostream>
#include <string>
#include <vector>
void displayNames(const std::vector<Student>& students);
int main()
{
Student stud1("John", 100);
Student stud2("Mary", 90);
Student stud3("Jack", 85);
std::vector<Student> students = {stud1, stud2, stud3};
displayNames(students);
return 0;
}
void displayNames(const std::vector<Student>& students)
{
for (const auto& student : students)
{
std::cout << student.getName() << std::endl;
}
}

c++ segmentation fault for dynamic arrays

I want to add a theater object into a boxoffice object in a C++ code. When I try to add it in main code, first one is added successfully. But a segmentation fault occurs for second and obvioulsy other theater objects. Here is the add function;
#include <iostream>
#include <string>
#include "BoxOffice.h"
using namespace std;
BoxOffice::BoxOffice()
{
sizeReserv = 0;
sizeTheater = 0;
theaters = new Theater[sizeTheater];
reserv = new Reservation[sizeReserv];
}
BoxOffice::~BoxOffice(){}
void BoxOffice::addTheater(int theaterId, string movieName, int numRows, int numSeatsPerRow){
bool theaterExist = false;
for(int i=0; i<sizeTheater; i++)
{
if(theaters[i].id == theaterId)
{
theaterExist=true;
}
}
if(theaterExist)
cout<<"Theater "<<theaterId<<"("<<movieName<<") already exists"<< endl;
else
{
++sizeTheater;
Theater *tempTheater = new Theater[sizeTheater];
if((sizeTheater > 1)){
tempTheater = theaters;
}
tempTheater[sizeTheater-1] = Theater(theaterId,movieName,numRows,numSeatsPerRow);
delete[] theaters;
theaters = tempTheater;
cout<<"Theater "<<theaterId<<"("<<movieName<<") has been added"<< endl;
cout<<endl;
delete[] tempTheater;
}
}
And I get segmentation fault on this line;
tempTheater[sizeTheater-1] = Theater(theaterId,movieName,numRows,numSeatsPerRow);
This is Theater cpp;
#include "Theater.h"
using namespace std;
Theater::Theater(){
id=0;
movieName="";
numRows=0;
numSeatsPerRow=0;
}
Theater::Theater(int TheaterId, string TheaterMovieName, int TheaterNumOfRows, int TheaterNumSeatsPerRow)
{
id = TheaterId;
movieName = TheaterMovieName;
numRows = TheaterNumOfRows;
numSeatsPerRow = TheaterNumSeatsPerRow;
theaterArray = new int*[TheaterNumOfRows];
for(int i=0;i<TheaterNumOfRows;i++)
theaterArray[i]= new int[TheaterNumSeatsPerRow];
for(int i=0; i<TheaterNumOfRows;i++){
for(int j=0;j<TheaterNumSeatsPerRow;j++){
theaterArray[i][j]=0;
}
}
}
This is header file of Theater;
#include <iostream>
#include <string>
using namespace std;
class Theater{
public:
int id;
string movieName;
int numRows;
int numSeatsPerRow;
int **theaterArray;
Theater();
Theater(int TheaterId, string TheaterMovieName, int TheaterNumOfRows, int TheaterNumSeatsPerRow);
};
And this is how i call add functions;
BoxOffice R;
R.addTheater(10425, "Ted", 4, 3);
R.addTheater(8234, "Cloud Atlas", 8, 3);
R.addTheater(9176, "Hope Springs",6,2);
The problematic lines are these:
if((sizeTheater > 1)){
tempTheater = theaters;
}
First you allocate memory and assign it to tempTheater, but here you overwrite that pointer so it will point to the old memory. It does not copy the memory. Since the code is for a homework assignment, I'll leave it up to you how to copy the data, but I do hope you follow the rule of three for the Theater class (as for the BoxOffice class) which will make it very simple.
Also, there's no need to allocate a zero-size "array", just make the pointers be nullptr (or 0).