In my class we recently got introduced to STL vectors. My professor has given us a program that uses arrays, and we are to convert it to use std::vectors instead. He would like us to use iterators, so we're not allowed to use square brackets, the push_back member function, or the at member function. Here's one of the for loops from the program I have to convert:
void readData(Highscore highScores[], int size)
{
for(int index = 0; index < size; index++)
{
cout << "Enter the name for score #" << (index + 1) << ": ";
cin.getline(highScores[index].name, MAX_NAME_SIZE, '\n');
cout << "Enter the score for score #" << (index + 1) << ": ";
cin >> highScores[index].score;
cin.ignore();
}
cout << endl;
}
`
I'm just not quite understanding how to convert them. so far, I was kind of able to get this: for (vector <Highscore> :: iterator num = scores.begin(); num < scores.end(); num++)for the for loop. It doesn't quite make sense to me so I was hoping I can get some more tips or even more information on how to convert them. I don't want an answer, simply just a tip. Thank you! (if its of any help, this is the program I am having to convert and these are the four headers we have to use
void getVectorSize(int& size);
void readData(vector<Highscore>& scores);
void sortData(vector<Highscore>& scores);
vector<Highscore>::iterator findLocationOfLargest(
const vector<Highscore>::iterator startingLocation,
const vector<Highscore>::iterator endingLocation);
void displayData(const vector<Highscore>& scores);
above are the headers that have to be used (having to use these instead of the programs headers)
#include <iostream>
using namespace std;
const int MAX_NAME_SIZE = 24;
struct Highscore{
char name[MAX_NAME_SIZE];
int score;
};
void getArraySize(int& size);
void readData(Highscore highScores[], int size);
void sortData(Highscore highScores[], int size);
int findIndexOfLargest(const Highscore highScores[], int startingIndex, int size);
void displayData(const Highscore highScores[], int size);
int main()
{
Highscore* highScores;
int size;
getArraySize(size);
highScores = new Highscore[size];
readData(highScores, size);
sortData(highScores, size);
displayData(highScores, size);
delete [] highScores;
}
void getArraySize(int& size){
cout << "How many scores will you enter?: ";
cin >> size;
cin.ignore();
}
void readData(Highscore highScores[], int size)
{
for(int index = 0; index < size; index++)
{
cout << "Enter the name for score #" << (index + 1) << ": ";
cin.getline(highScores[index].name, MAX_NAME_SIZE, '\n');
cout << "Enter the score for score #" << (index + 1) << ": ";
cin >> highScores[index].score;
cin.ignore();
}
cout << endl;
}
void sortData(Highscore highScores[], int numItems) {
for (int count = 0; count < numItems - 1; count++){
swap(highScores[findIndexOfLargest(highScores, count, numItems)],
highScores[count]);
}
}
int findIndexOfLargest(const Highscore highScores[], int startingIndex, int numItems){
int indexOfLargest = startingIndex;
for (int count = startingIndex + 1; count < numItems; count++){
if (highScores[count].score > highScores[indexOfLargest].score){
indexOfLargest = count;
}
}
return indexOfLargest;
}
void displayData(const Highscore highScores[], int size)
{
cout << "Top Scorers: " << endl;
for(int index = 0; index < size; index++)
{
cout << highScores[index].name << ": " << highScores[index].score << endl;
}
}
You maybe looking for one of two things.
If you want to add something to a vector, the function is push_back
vecScores.push_back(value) ; //in a for loop.
https://www.cplusplus.com/reference/vector/vector/push_back/
If you want to add something to a map, you could just use the form of
mapScore[index]=value ; // in a for loop.
https://www.cplusplus.com/reference/map/map/operator[]/
Probably your professor wants you to write something like this:
void readData(std::vector<Highscore>& highScores)
{
for (auto it = highScores.begin(); it != highScores.end(); ++it) {
cout << "Enter the name for score #" << std::distance(highScores.begin(), it) << ": ";
cin.getline(it->name, MAX_NAME_SIZE, '\n');
cout << "Enter the score for score #" << std::distance(highScores.begin(), it) << ": ";
cin >> it->score;
cin.ignore();
}
cout << endl;
}
where it is the iterator that's incremented via ++it from highScores.begin() to just before highScores.end(); then you access the members of the highScores's element "pointed by" it via it->member.
Here's a complete demo.
By the way, considering how much your professor likes void(some_type&) functions (and using namespace std;, if that was not your own idea), I would doubt you have much to learn from him. You better buy a good book.
I would do it like this, also get used to typing std::
Why is "using namespace std;" considered bad practice?
Also be careful with signed/unsigned, be precise about it.
If something can't have a negative value use unsigned types (or size_t)
#include <iostream>
#include <string>
#include <vector>
struct HighScore
{
std::string name;
unsigned int score;
};
// use size_t for sizes (value will always >0)
std::vector<HighScore> GetHighScores(size_t size)
{
std::vector<HighScore> highScores;
std::string points;
for (size_t index = 0; index < size; index++)
{
HighScore score;
std::cout << "Enter the name for score #" << (index + 1) << ": ";
std::cin >> score.name;
std::cout << "Enter the score for score #" << (index + 1) << ": ";
std::cin >> points;
// convert string to int
score.score = static_cast<unsigned int>(std::atoi(points.c_str()));
highScores.push_back(score);
}
std::cout << std::endl;
return highScores;
}
int main()
{
auto highScores = GetHighScores(3);
return 1;
}
Related
I finished this code homework assignment tonight. I thought I was done, but I just realized that my "Average" value is coming out wrong with certain values. For example: When my professor entered the values 22, 66, 45.1, and 88 he got an "Average" of 55.27. However, when I enter those values in my program, I get an "Average" of 55.25. I have no idea what I am doing wrong. I was pretty confident in my program until I noticed that flaw. My program is due at midnight, so I am clueless on how to fix it. Any tips will be greatly appreciated!
Code Prompt: "Write a program that dynamically allocates an array large enough to hold a user-defined number of test scores. Once all the scores are entered, the array should be passed to a function that sorts them in ascending order. Another function should be called that calculates the average score. The program should display the sorted list of scores and averages with appropriate headings. Use pointer notation rather than array notation whenever possible."
Professor Notes: The book only states, "Input Validation: Do not accept negative numbers for test scores." We also need to have input validation for the number of scores. If it is negative, including 0, the program halts, we should consider this situation for 'counter' not to be negative while we have a loop to enter numbers. So negative numbers should be rejected for the number of scores and the values of scores.
Here is my code:
#include <iostream>
#include <iomanip>
using namespace std;
void showArray(double* array, int size);
double averageArray(double* array, int size);
void orderArray(double* array, int size);
int main()
{
double* scores = nullptr;
int counter;
double numberOfScores;
cout << "\nHow many test scores will you enter? ";
cin >> numberOfScores;
if (numberOfScores < 0) {
cout << "The number cannot be negative.\n"
<< "Enter another number: ";
cin >> numberOfScores;
}
if (numberOfScores == 0) {
cout << "You must enter a number greater than zero.\n"
<< "Enter another number: ";
cin >> numberOfScores;
}
scores = new double[numberOfScores];
for (counter = 0; counter < numberOfScores; counter++) {
cout << "Enter test score " << (counter + 1) << ": ";
cin >> *(scores + counter);
if (*(scores + counter) < 0) {
cout << "Negative scores are not allowed. " << endl
<< "Enter another score for this test : ";
cin >> *(scores + counter);
}
}
orderArray(scores, counter);
cout << "\nThe test scores in ascending order, and their average, are: " << endl
<< endl;
cout << " Score" << endl;
cout << " -----" << endl
<< endl;
showArray(scores, counter);
cout << "\nAverage Score: "
<< " " << averageArray(scores, counter) << endl
<< endl;
cout << "Press any key to continue...";
delete[] scores;
scores = nullptr;
system("pause>0");
}
void orderArray(double* array, int size)
{
int counterx;
int minIndex;
int minValue;
for (counterx = 0; counterx < (size - 1); counterx++) {
minIndex = counterx;
minValue = *(array + counterx);
for (int index = counterx + 1; index < size; index++) {
if (*(array + index) < minValue) {
minValue = *(array + index);
minIndex = index;
}
}
*(array + minIndex) = *(array + counterx);
*(array + counterx) = minValue;
}
}
double averageArray(double* array, int size)
{
int x;
double total{};
for (x = 0; x < size; x++) {
total += *(array + x);
}
double average = total / size;
return average;
}
void showArray(double* array, int size)
{
for (int i = 0; i < size; i++) {
cout << " " << *(array + i) << endl;
}
}
I try to start my answers with a brief code review:
#include <iostream>
#include <iomanip>
using namespace std; // Bad practice; avoid
void showArray(double* array, int size);
double averageArray(double* array, int size);
void orderArray(double* array, int size);
int main()
{
double* scores = nullptr;
int counter;
double numberOfScores;
cout << "\nHow many test scores will you enter? ";
cin >> numberOfScores;
// This is not input validation, I can enter two consecutive bad values,
// and the second one will be accepted.
if (numberOfScores < 0) {
// Weird formatting, this blank line
cout << "The number cannot be negative.\n"
<< "Enter another number: ";
cin >> numberOfScores;
}
// The homework, as presented, doesn't say you have to treat 0 differently.
if (numberOfScores == 0) {
cout << "You must enter a number greater than zero.\n"
<< "Enter another number: ";
cin >> numberOfScores;
}
scores = new double[numberOfScores];
// Declare your loop counter in the loop
for (counter = 0; counter < numberOfScores; counter++) {
cout << "Enter test score " << (counter + 1) << ": ";
cin >> *(scores + counter);
if (*(scores + counter) < 0) {
cout << "Negative scores are not allowed. " << endl
<< "Enter another score for this test : ";
cin >> *(scores + counter);
}
}
orderArray(scores, counter); // Why not use numberOfScores?
cout << "\nThe test scores in ascending order, and their average, are: " << endl
<< endl;
cout << " Score" << endl;
cout << " -----" << endl
<< endl;
showArray(scores, counter); // Same as above.
cout << "\nAverage Score: "
<< " " << averageArray(scores, counter) << endl
<< endl;
cout << "Press any key to continue...";
delete[] scores;
scores = nullptr;
system("pause>0"); // Meh, I suppose if you're on VS
}
void orderArray(double* array, int size)
{
int counterx;
int minIndex;
int minValue; // Unnecessary, and also the culprit
// This looks like selection sort
for (counterx = 0; counterx < (size - 1); counterx++) {
minIndex = counterx;
minValue = *(array + counterx);
for (int index = counterx + 1; index < size; index++) {
if (*(array + index) < minValue) {
minValue = *(array + index);
minIndex = index;
}
}
*(array + minIndex) = *(array + counterx);
*(array + counterx) = minValue;
}
}
double averageArray(double* array, int size)
{
int x;
double total{};
for (x = 0; x < size; x++) {
total += *(array + x);
}
double average = total / size;
return average;
}
void showArray(double* array, int size)
{
for (int i = 0; i < size; i++) {
cout << " " << *(array + i) << endl;
}
}
When you are sorting your array, you keep track of the minValue as an int and not a double. That's why your average of the sample input is incorrect. 45.1 is truncated to 45 for your calculations. You don't need to keep track of the minValue at all. Knowing where the minimum is, and where it needs to go is sufficient.
But as I pointed out, there are some other serious problems with your code, namely, your [lack of] input validation. Currently, if I enter two consecutive bad numbers, the second one will be accepted no matter what. You need a loop that will not exit until a good value is entered. It appears that you are allowed to assume that it's always a number at least, and not frisbee or any other non-numeric value.
Below is an example of what your program could look like if your professor decides to teach you C++. It requires that you compile to the C++17 standard. I don't know what compiler you're using, but it appears to be Visual Studio Community. I'm not very familiar with that IDE, but I imagine it's easy enough to set in the project settings.
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <string>
#include <vector>
// Assumes a number is always entered
double positive_value_prompt(const std::string& prompt) {
double num;
std::cout << prompt;
do {
std::cin >> num;
if (num <= 0) {
std::cerr << "Value must be positive.\n";
}
} while (num <= 0);
return num;
}
int main() {
// Declare variables when you need them.
double numberOfScores =
positive_value_prompt("How many test scores will you enter? ");
std::vector<double> scores;
for (int counter = 0; counter < numberOfScores; counter++) {
scores.push_back(positive_value_prompt("Enter test score: "));
}
std::sort(scores.begin(), scores.end());
for (const auto& i : scores) {
std::cout << i << ' ';
}
std::cout << '\n';
std::cout << "\nAverage Score: "
<< std::reduce(
scores.begin(), scores.end(), 0.0,
[size = scores.size()](auto mean, const auto& val) mutable {
return mean += val / size;
})
<< '\n';
}
And here's an example of selection sort where you don't have to worry about the minimum value. It requires that you compile to C++20. You can see the code running here.
#include <iostream>
#include <random>
#include <vector>
void selection_sort(std::vector<int>& vec) {
for (int i = 0; i < std::ssize(vec); ++i) {
int minIdx = i;
for (int j = i + 1; j < std::ssize(vec); ++j) {
if (vec[j] < vec[minIdx]) {
minIdx = j;
}
}
int tmp = vec[i];
vec[i] = vec[minIdx];
vec[minIdx] = tmp;
}
}
void print(const std::vector<int>& v) {
for (const auto& i : v) {
std::cout << i << ' ';
}
std::cout << '\n';
}
int main() {
std::mt19937 prng(std::random_device{}());
std::uniform_int_distribution<int> dist(1, 1000);
std::vector<int> v;
for (int i = 0; i < 10; ++i) {
v.push_back(dist(prng));
}
print(v);
selection_sort(v);
print(v);
}
I opted not to give your code the 'light touch' treatment because than I would have done your homework for you, and that's just not something I do. However, the logic shown should still be able to guide you toward a working solution.
(Sorry if this is formatted terribly. I've never posted before.)
I've been working on a program for class for a few hours and I can't figure out what I need to do to my function to get it to do what I want. The end result should be that addUnique will add unique inputs to a list of its own.
#include <iostream>
using namespace std;
void addUnique(int a[], int u[], int count, int &uCount);
void printInitial(int a[], int count);
void printUnique(int u[], int uCount);
int main() {
//initial input
int a[25];
//unique input
int u[25];
//initial count
int count = 0;
//unique count
int uCount = 0;
//user input
int input;
cout << "Number Reader" << endl;
cout << "Reads back the numbers you enter and tells you the unique entries" << endl;
cout << "Enter 25 positive numbers. Enter '-1' to stop." << endl;
cout << "-------------" << endl;
do {
cout << "Please enter a positive number: ";
cin >> input;
if (input != -1) {
a[count++] = input;
addUnique(a, u, count, uCount);
}
} while (input != -1 && count < 25);
printInitial(a, count);
printUnique(u, uCount);
cout << "You entered " << count << " numbers, " << uCount << " unique." << endl;
cout << "Have a nice day!" << endl;
}
void addUnique(int a[], int u[], int count, int &uCount) {
int index = 0;
for (int i = 0; i < count; i++) {
while (index < count) {
if (u[uCount] != a[i]) {
u[uCount++] = a[i];
}
index++;
}
}
}
void printInitial(int a[], int count) {
int lastNumber = a[count - 1];
cout << "The numbers you entered are: ";
for (int i = 0; i < count - 1; i++) {
cout << a[i] << ", ";
}
cout << lastNumber << "." << endl;
}
void printUnique(int u[], int uCount) {
int lastNumber = u[uCount - 1];
cout << "The unique numbers are: ";
for (int i = 0; i < uCount - 1; i++) {
cout << u[i] << ", ";
}
cout << lastNumber << "." << endl;
}
The problem is my addUnique function. I've written it before as a for loop that looks like this:
for (int i = 0; i < count; i++){
if (u[i] != a[i]{
u[i] = a[i]
uCount++;
}
}
I get why this doesn't work: u is an empty array so comparing a and u at the same spot will always result in the addition of the value at i to u. What I need, is for this function to scan all of a before deciding whether or no it is a unique value that should be added to u.
If someone could point me in the right direction, it would be much appreciated.
Your check for uniqueness is wrong... As is your defintion of addUnique.
void addUnique(int value, int u[], int &uCount)
{
for (int i = 0; i < uCount; i++){
if (u[i] == value)
return; // already there, nothing to do.
}
u[uCount++] = value;
}
I'm trying to create a program in which the user can enter up to 100 player names and scores, and then have it print out all the players' names and scores, followed by an average of the scores, and finally, display players whose scores were below average. I've managed to do all of that except for the final piece, displaying below average scores. I'm kind of unsure about how to go about it. In my DesplayBelowAverage function, I've attempted to have it read the current player's score and compare it to the average to see if it should be printed out as a below average score, but it doesn't seem to recognize the averageScore value I created in the CalculateAverageScores function. Here's my code:
#include <iostream>
#include <string>
using namespace std;
int InputData(string [], int [], int);
int CalculateAverageScores(int [], int);
void DisplayPlayerData(string [], int [], int);
void DisplayBelowAverage(string [], int [], int);
void main()
{
string playerNames[100];
int scores[100];
int sizeOfArray = sizeof(scores);
int sizeOfEachElement = sizeof(scores[0]);
int numberOfElements = sizeOfArray / sizeOfEachElement;
cout << numberOfElements << endl;
int numberEntered = InputData(playerNames, scores, numberOfElements);
DisplayPlayerData(playerNames, scores, numberEntered);
CalculateAverageScores(scores, numberEntered);
cin.ignore();
cin.get();
}
int InputData(string playerNames[], int scores[], int size)
{
int index;
for (index = 0; index < size; index++)
{
cout << "Enter Player Name (Q to quit): ";
getline(cin, playerNames[index]);
if (playerNames[index] == "Q")
{
break;
}
cout << "Enter score for " << playerNames[index] << ": ";
cin >> scores[index];
cin.ignore();
}
return index;
}
void DisplayPlayerData(string playerNames[], int scores[], int size)
{
int index;
cout << "Name Score" << endl;
for (index = 0; index < size; index++)
{
cout << playerNames[index] << " " << scores[index] << endl;
}
}
int CalculateAverageScores(int scores[], int size)
{
int index;
int totalScore = 0;
int averageScore = 0;
for (index = 0; index < size; index++)
{
totalScore = (totalScore + scores[index]);
}
averageScore = totalScore / size;
cout << "Average Score: " << averageScore;
return index;
}
void DisplayBelowAverage(string playerNames[], int scores[], int size)
{
int index;
cout << "Players who scored below average" << endl;
cout << "Name Score" << endl;
for (index = 0; index < size; index++)
{
if(scores[index] < averageScore)
{
cout << playerNames[index] << " " << scores[index] << endl;
}
}
}
You are calculating the averageScore variable in the CalculateAverageScore and it is local to that function only so DisplayBelowAverage has no idea about the averageScore value. That's why your logic is not working.
In order to solve this there are two options:
Declare the averageScore as global (although it is not advisable to have global variables)
Pass the averageScore to the DisplayBelowAverage as a parameter. This is a better approach. So what you should do is return the average score that you calculate in CalculateAverageScore and store it in some variable and then pass that to DisplayBelowAverage function as a parameter.
Hope this helps
I'm having an issue with some school work where I need to create two arrays one for names and one for scores which allows the user to input into both arrays (i.e. Enter the players name:; Enter the players score:). Then I need to print the arrays in descending score and then ascending alphabetical. As a hint we were told: Using the string sort function combine the two arrays into one then sort.
However I can't figure out how to link the two values to one another so that if I enter Nathan with a score of 87 the two values can't be split apart.
This is what I have so far (with some things I was trying to get to work but couldn't):
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string names[10];
int scores[10];
string combine[20];
int count = 0;
while (count < 10){
cout << "Please enter a player's name: ";
cin >> names[count];
cout << "Now enter that player's score: ";
cin >> scores[count];
count++;
}
/*sort(begin(names), end(names));
sort(begin(scores), end(scores));*/
for (int i = 0; i < 10; i++){
cout << names[i] << ": " << scores[i] << "\n";
}
system("pause");
}
You want to "link" them from the very beginning:
struct Student {
string name;
int score;
bool operator<(const Student& rhs) const {
return score > rhs.score || (score == rhs.score && name < rhs.name);
}
};
That way, the sort is easy:
sort(begin(students), end(students));
Otherwise, you'd have to make an array of indices:
int indices[10];
std::iota(begin(indices), end(indices), 0);
And sort that:
std::sort(begin(indices), end(indices), [&](int a, int b){
return scores[a] > scores[b] ||
scores[a] == scores[b] && names[a] < names[b];
});
And then print according to indices:
for (int idx : indices) {
std::cout << names[idx] << " with score " << scores[idx] << '\n';
}
As far as combining the two arrays into one you can do something like this:
// create a struct that of type "result"
// that combines both name and score
struct result
{
string name;
int score;
};
int main()
{
string names[10];
int scores[10];
// array of your struct - same number of elements (10 not 20)
result combine[10];
int count = 0;
while (count < 10){
cout << "Please enter a player's name: ";
cin >> names[count];
cout << "Now enter that player's score: ";
cin >> scores[count];
count++;
}
/*sort(begin(names), end(names));
sort(begin(scores), end(scores));*/
for (int i = 0; i < 10; i++){
cout << names[i] << ": " << scores[i] << "\n";
}
// combine into one array
for(int i = 0; i < 10; ++i)
{
combine[i].name = names[i];
combine[i].score = scores[i];
}
// Now sort the combined array
system("pause");
}
Just to refresh my concept I'm working on parallel arrays. One is used to store integer data and the other one for char data i.e GPA.
The problem compiles like a charm but the result is not correct, it displays the Student IDs correctly but not the GPA.
The simple cin works fine
I don't really know how to use cin.get and cin.getline using pointers.
In function enter I want to get the two-character-long string (plus one terminating null character).
Code listing:
#include <iostream>
#include <cstring>
using namespace std;
void enter(int *ar, char *arr, int size);
void exit(int *a, char *yo, int size);
int main()
{
const int id = 5;
const char grade = 5;
int *student = new int[id];
char *course = new char[grade];
cout << "\n";
enter(student, course, 5);
exit(student, course, 5);
}
void enter(int *ar, char *arr, int size)
{
for(int i = 0; i < size; i ++)
{
cout << "Student ID: " << i+1 << "\n";
cin >> *(ar+i);
cin.ignore();
cout << "Student Grade: " << i+1 << "\n";
cin.get(arr, 3);
}
}
void exit(int *a, char *yo, int size)
{
for(int i = 0; i < size; i ++)
{
cout << "ID And Grade Of Student #" << i+1 << ":";
cout << *(a+i) << "\t" << *(yo+j) << endl;
}
}
You are attempting to use part of the C++ language, but not embrace it entirely. There is no need for you to manage memory (at all) to solve this problem. Additionally, it would be much better to solve it using the standard language features:
struct Info
{
int StudentId;
std::string Grade; // this could easily be stored as an int or a char as well
};
int main()
{
const std::vector<Info>::size_type SIZE_LIMIT = 5;
std::vector<Info> vec(SIZE_LIMIT);
for (std::vector<Info>::size_type i = 0; i < SIZE_LIMIT; ++i)
{
std::cout << "Enter a Student ID: ";
std::cin >> vec[i].StudentId;
std::cout << "Enter a Grade: ";
std::cin >> vec[i].Grade;
}
std::for_each(vec.begin(), vec.end(), [&](const Info& i)
{
std::cout << "Student ID: " << i.StudentId << ", Grade: " << i.Grade << std::endl;
});
return 0;
}
Which can very easily be converted to account for more than 5 (e.g. virtually infinite) by adding an overload for std::istream& operator>>(std::istream&, Info&) and changing the for-loop to a std::copy operation.
If you absolutely want to keep your hands tied behind your back, you should at least make the following changes:
const unsigned int CLASS_SIZE = 5;
const unsigned int GRADE_SIZE = 5;
int student[CLASS_SIZE];
char course[CLASS_SIZE][GRADE_SIZE] = {};
// initialize course grades to empty strings, if you don't use the = {} above
for (unsigned int i = 0; i < CLASS_SIZE; ++i)
{
memset(course[i], 0, GRADE_SIZE);
}
// ...
// use your constants for your sizes
enter(student, course, CLASS_SIZE);
exit(student, course, CLASS_SIZE);
// ...
// NOTE: you should check to make sure the stream is in a good condition after each input - I leave the error checking code for you to implement
cout << "Student ID: ";
cin >> ar[i];
cout << "Student Grade: ";
cin >> arr[i]; // also note: since you are not using std::string, this can overflow! careful!
// ...
cout << "ID And Grade Of Student #" << i+1 << ":" << a[i] << "\t" << yo[i] << endl;