Arranging Vector Outputs from multiple string variables - c++

This is an assignment I am attempting to work on where I am attempting to create a program that asks for a books title, its author, and its date of publication, before displaying all inputs at the end. My primary obstacle is trying to get everything to display in a somewhat decent way, with additional text written to clarify the information properly.
It should look like this:
Title: Great Expectations Fahrenheit 451 Animal Farm
Author: Charles Dickens Ray Bradbury George Orwell
Date: 1824 1956 1948
#include <string>
#include <vector>
using namespace std;
int main ()
{
int i=0;
int n;
string bookTitle;
string bookAuthor;
string bookDate;
vector<string> Title;
vector<string> Author;
vector<string> Date;
cout << "Enter the Number of Books: ";
cin >> n;
cin.ignore();
for (i; i < n; i++)
{
cout << "Type the Book's Title: ";
getline (cin, bookTitle);
Title.push_back(bookTitle);
cout << "Type the Book's Author: ";
getline (cin, bookAuthor);
Author.push_back(bookAuthor);
cout << "Type the Book's Date: ";
getline (cin, bookDate);
Date.push_back(bookDate);
}
cout << endl;
cout << "The Titles: ";
for (auto it = Title.begin(); it != Title.end(); ++it) {
cout << *it << " ";
}
cout << endl;
cout << "Written by: ";
for (auto ib = Author.begin(); ib != Author.end(); ++ib) {
cout << *ib << " ";
}
cout << endl;
cout << "Written in: ";
for (auto ic = Date.begin(); ic != Date.end(); ++ic) {
cout << *ic << " ";
}
return 0;
}

First, let's organize your code a bit, by storing each book in a structure:
struct Book {
string title;
string author;
string date;
};
vector<Book> books;
Read them like this:
for (int i = 0; i < n; i++)
{
Book book;
getline (cin, book.title);
getline (cin, book.author);
getline (cin, book.date);
books.push_back(book);
}
For each book, you can store a useful column width for your output. To keep it simple, only the book's title and author are considered when choosing the column width:
vector<int> widths;
int padding = 2;
for (const Book& book : books)
{
widths.push_back(padding + std::max(book.title.size(), book.author.size()));
}
Now, use std::setw from <iomanip> to set the appropriate column width for each book:
cout << "The Titles: ";
for (int i = 0; i < n; i++) {
cout << std::setw(widths[i]) << books[i].title;
}
cout << endl;
cout << "Written by: ";
for (int i = 0; i < n; i++) {
cout << std::setw(widths[i]) << books[i].author;
}
cout << endl;
cout << "Written in: ";
for (int i = 0; i < n; i++) {
cout << std::setw(widths[i]) << books[i].date;
}
cout << endl;
Output:
The Titles: Great Expectations Fahrenheit 451 Animal Farm
Written by: Charles Dickens Ray Bradbury George Orwell
Written in: 1824 1956 1948

I would recommend using the std::setw() function within the library to set a consistent field width to format the output neatly.
For example:
cout << setw(WIDTH) << *it << " ";

Related

Why my array doesn't print different subjects name inputted by a user?

The objective is to take input of subjects and their marks from a user and finally display them as a report card. Everything works as expected except that the compiler prints the name of the last subject entered for each different subject name in the final report.
Here is the C++ code that I tried:
#include <iostream>
using namespace std;
int main() {
string fname, lname;
int subjects;
float totalMarks;
cout << "Enter your first name: ";
cin >> fname;
cout << "Enter your last name: ";
cin >> lname;
cout << "Enter total marks: ";
cin >> totalMarks;
cout << "Marks of how many subjects: ";
cin >> subjects;
float subjectMarks[subjects];
string subjectNames[subjects];
for (int i = 0; i < subjects; i++) {
for (int j = 0; j < subjects; j++) {
cout << "Enter name of subject: ";
cin >> subjectNames[j];
break; // I've used 'break' to exit the inner loop and go to outer loop for
// entering the marks obtained in the subject
};
cout << "Enter marks obtained in the subject: ";
cin >> subjectMarks[i];
};
cout << "Dear, " << fname << " " << lname << "! The subjects and their marks are shown below: \n";
cout << "RESULTS IN SUBJECTS\n\n";
for (int i = 0; i < subjects; i++) {
for (int j = 0; j < subjects; j++) {
cout << subjectNames[j] << "\t\t";
break;
}
cout << subjectMarks[i] << endl;
};
return 0;
}
What I expected?
As you can see in the screenshot, 'Chemistry' is printed twice with different marks. It should have printed first 'Physics' with marks '80' and then 'Chemistry' with marks '70' as inputted by the user. I doubt there is a problem with subjectNames[] array.
But this is what actually happened
enter image description here
I'm stuck on this problem for more than 3 hours. Please help!
The loop for reading and the loop for writing is wrong. You don't need nested loops. Just have one variable when reading and one when writing:
// reading
for (int i = 0; i < subjects; i++) {
std::cout << "Enter name of subject: ";
std::cin >> subjectNames[i];
std::cout << "Enter marks obtained in the subject: ";
std::cin >> subjectMarks[i];
};
// writing
std::cout << "Dear, " << fname << " " << lname
<< "! The subjects and their marks are shown below:\n"
"RESULTS IN SUBJECTS\n\n";
for (int i = 0; i < subjects; i++) {
std::cout << subjectNames[i] << "\t\t"
<< subjectMarks[i] << '\n';
}
Also note that your subjectMarks and subjectNames are Variable Length Arrays (VLAs) and those aren't supported in standard C++. Only some compilers supports them as an extension. I recommend that you use std::vectors instead:
#include <vector>
// ...
std::vector<float> subjectMarks(subjects);
std::vector<std::string> subjectNames(subjects);

Output does not include all input for my array

I have this program that is barely started:
#include <iostream>
#include <iomanip>
#include <ctime>
#include <string>
using namespace std;
class Grade
{
public:
string studentID;
int userChoice = 0;
int size = 0;
double* grades = new double[size]{0};
};
void ProgramGreeting(Grade &student);
void ProgramMenu(Grade& student);
string GetID(Grade& student);
int GetChoice(Grade& student);
void GetScores(Grade& student);
int main()
{
Grade student;
ProgramGreeting(student);
ProgramMenu(student);
}
// Specification C1 - Program Greeting function
void ProgramGreeting(Grade &student)
{
cout << "--------------------------------------------" << endl;
cout << "Welcome to the GPA Analyzer! " << endl;
cout << "By: Kate Rainey " << endl;
cout << "Assignment Due Date: September 25th, 2022 " << endl;
cout << "--------------------------------------------" << endl;
GetID(student);
cout << "For Student ID # " << student.studentID << endl;
}
void ProgramMenu(Grade &student)
{
cout << "--------------------------------------------" << endl;
cout << setw(25) << "Main Menu" << endl;
cout << "1. Add Grade " << endl;
cout << "2. Display All Grades " << endl;
cout << "3. Process All Grades " << endl;
cout << "4. Quit Program." << endl;
cout << "--------------------------------------------" << endl;
GetChoice(student);
}
string GetID(Grade &student)
{
cout << "Enter the student's ID: ";
cin >> student.studentID;
if (student.studentID.length() != 8) {
cout << "Student ID's contain 8 characters ";
GetID(student);
}
return student.studentID;
}
int GetChoice(Grade &student)
{
cout << "Enter your selection: ";
cin >> student.userChoice;
if (student.userChoice == 1) {
GetScores(student);
}
else if (student.userChoice == 2)
{
}
else if (student.userChoice == 2)
{
}
else if (student.userChoice == 4)
{
exit(0);
}
else
{
cout << "Please enter 1, 2, 3 or 4" << endl;
GetChoice(student);
}
}
void GetScores(Grade &student)
{
int count = 0;
double score = 0;
cout << "How many test scores would you like to enter for ID# "
<< student.studentID << "? ";
cin >> student.size;
while (count != student.size) {
cout << "Enter a grade: ";
cin >> score;
for (int i = 0; i < student.size; i++) {
student.grades[i] = score;
}
count++;
}
for (int i = 0; i < student.size; i++) {
cout << student.grades[i] << " ";
}
}
I am trying to make sure my array is recording all test scores, but when I output the array in my GetScore function, each element in the array is the same or equal to the last score I entered. For example, if I choose 3 for size and then enter three values of 99.2 86.4 90.1, all three elements will read 90.1.
Why is this happening?
Your Grade class is allocating an array of 0 double elements (which is undefined behavior), and then your GetScores() function does not reallocate that array after asking the user how many scores they will enter, so you are writing the input values to invalid memory (which is also undefined behavior).
Even if you were managing the array's memory correctly (ie, by using std::vector instead of new[]), GetScores() is also running a for loop that writes the user's latest input value into every element of the array, instead of just writing it to the next available element. That is why your final output displays only the last value entered in every element. You need to get rid of that for loop completely.
Try something more like this instead (there are several other problems with your code, but I'll leave those as separate exercises for you to figure out):
class Grade
{
public:
...
int size = 0;
double* grades = nullptr;
};
...
void GetScores(Grade &student)
{
int size = 0;
double score = 0;
cout << "How many test scores would you like to enter for ID# " << student.studentID << "? ";
cin >> size;
if (student.size != size) {
delete[] student.grades;
student.grades = new double[size]{0};
student.size = size;
}
for(int i = 0; i < size; ++i) {
cout << "Enter a grade: ";
cin >> score;
student.grades[i] = score;
}
for (int i = 0; i < size; ++i) {
cout << student.grades[i] << " ";
}
}
Alternatively:
#include <vector>
...
class Grade
{
public:
...
vector<double> grades;
};
...
void GetScores(Grade &student)
{
size_t size = 0;
double score = 0;
cout << "How many test scores would you like to enter for ID# " << student.studentID << "? ";
cin >> size;
student.grades.resize(size);
for (size_t i = 0; i < size; ++i) {
cout << "Enter a grade: ";
cin >> score;
student.grades[i] = score;
}
/* alternatively:
student.grades.clear();
for (size_t i = 0; i < size; ++i) {
cout << "Enter a grade: ";
cin >> score;
student.grades.push_back(score);
}
*/
for (size_t i = 0; i < size; ++i) {
cout << student.grades[i] << " ";
}
}
I removed my for loop from my while loop.
void GetScores(Grade &student)
{
int count = 0;
double score = 0;
cout << "How many test scores would you like to enter for ID# "
<< student.studentID << "? ";
cin >> student.size;
while (count != student.size) {
cout << "Enter a grade: ";
cin >> score;
student.grades[count] = score;
count++;
}
for (int j = 0; j < student.size; j++) {
cout << student.grades[j] << " ";
}
}

validate age input to prompt message when enter alphabet, symbol and negative number

I want to validate the input age with the code I wrote below
cout << "Enter the Age of The " << qty << " Passenger(s) :: ";
for (int i = 1; i <= qty; i++) {
cout << "\nAge for Passenger " << i << " :: ";
cin >> age[i];
while ((!(cin >> age[i])) || (age[i]<=0)) {
// Explain the error
cout << "Error: Enter a valid age for Passenger " << i << " : ";
// Clear the previous input
cin.clear();
// Discard previous input
cin.ignore(123, '\n');
}
}
But, there is a problem. The program will stop running when I enter the age inside the range.
So, I want to ask is there any effective way to validate the age input.
Consider using std::getline and std::stringsstream. So you are just reading line and then trying to parse it.
For example:
#include <iostream>
#include <sstream>
int main(int argc, const char * argv[])
{
int qty = 10;
int* age = new int[11];
std::cout << "Enter the Age of The " << qty << " Passenger(s) :: ";
for (int i = 1; i <= qty; i++) {
std::cout << "\nAge for Passenger " << i << " :: ";
std::string s;
std::getline(std::cin, s);
std::stringstream stream(s);
while ((!(stream >> age[i])) || (age[i]<=0)) {
// Explain the error
std::cout << "Error: Enter a valid age for Passenger " << i << " : ";
std::getline(std::cin, s);
stream = std::stringstream (s);
}
}
for (int i = 1; i <= qty; i++) {
std::cout << age[i];
}
delete [] age;
return 0;
}
Also note, that it is bad pattern to use using namespace std and indexation from 1

How to input data from user into 2d array and cout to user c++

So I am fairly new to 2d arrays in c++ and I know im doing something wrong but im not sure what.
#include <iostream>
using namespace std;
int main(){
string favBands[10][2];
cout << "Welcome to the favorite band printer outer!" << endl;
int count = 1;
string band;
string song;
for(int i = 0; i < 10; i++){
for(int j = 1; j < 2; j++){
cout << "Enter your number " << count << " band:\n" << endl;
count += 1;
cin >> band;
favBands[i][j] = band;
cout << "Enter " << favBands[i][j] << "'s best song:\n" << endl;
cin >> song;
favBands[i][j] = song;
}
}
}
I want to ask the user to enter their 10 favorite bands and then ask for their favorite song from that band in a pair. So for example:
Enter your number 1 favorite band:
Black Eyed Peas (user input)
Enter your favorite Black Eyed Peas song:
Boom Boom Pow (user input)
I am able to do all of this but the problem comes when I try to print the array to the user. I think my problem may lie in how i input the user data into my array but im not sure how to fix it. Thanks!
You will only need one for loop. see we are storing data for 10 users. and for every user we are taking two data at index 0 and index 1. So we don't need second for loop. please observe code and ask if you still have any confusion. I will be happy to figure it out as well.
#include <iostream>
using namespace std;
int main(){
string favBands[10][2];
cout << "Welcome to the favorite band printer outer!" << endl;
int count = 1;
string band;
string song;
for(int i = 0; i < 10; i++)
{
cout << "Enter your number " << count << " band:\n" << endl;
count += 1;
cin >> band;
favBands[i][0] = band;
cout << "Enter " << favBands[i][0] << "'s best song:\n" << endl;
cin >> song;
favBands[i][1] = song;
}
}
Allow me to suggest using two separate arrays instead of a 2D array, one for bands and one for songs, and then cout'ing the song, like so:
#include <iostream>
using namespace std;
int main() {
string favBands[10];
string favSongs[10];
cout << "Welcome to the favorite band printer outer!" << endl;
int count = 1;
string band;
string song;
for (int i = 0; i < 10; i++) {
cout << "Enter your number " << count << " band:\n" << endl;
count += 1;
cin >> band;
favBands[i] = band;
cout << "Enter " << favBands[i] << "'s best song:\n" << endl;
cin >> song;
favSongs[i] = song;
cout << "Your favorite song by " << favBands[i] << " is " << favSongs[i] << ".\n";
}
}
Although both bands and songs are strings, 2D arrays aren't really best suited for this type of problem.

Loop over list of objects skipped

I'm making a list of Student Objects, and want to iterate over them and output the values they have. I'm not sure why the for loop is being skipped over. Any help/guidance would be appreciated. Here is the loop:
void studentInfo(list<Student> stuList) {
cout << "in studentinfo" << endl;
for (list<Student>::iterator it = stuList.begin(); it != stuList.end(); ++it) {
cout << "in student info loop" << endl;
cout << it->toString();
}
cout << "after loop" << endl;
}
I get the cout messages that are right before and after the loop. Here is the toString() method if you need.
string Student::toString() {
stringstream outString;
outString << "Name: " << name << "\nID: " << id << "\nAge: " << age << endl;
return outString.str();
}
This is how the list is being populated, I'm adding 2 student objects usually when testing:
void addToList(list<Student> stuList) {
string tempName;
int tempID;
int tempAge;
int numStudents;
cout << "How many students will you be entering?\n";
cin >> numStudents;
for (int i = 0; i < numStudents; i++) {
cout << "Enter student name: \n";
cin >> tempName;
cout << "Enter student id: \n";
cin >> tempID;
cout << "Enter student age: \n";
cin >> tempAge;
stuList.push_back(Student(tempName, tempID, tempAge));
}
}