How to loop through numbers stored in separte variables? - c++

So I got this code, I input three numbers. Now I want to display them in a for loop. From smallest to biggest, and in another loop from biggest to smallest. How can I do this?
int main()
{
int num1, num2, num3;
cout << "Enter first num" << endl;
cin >> num1;
cout << "Enter second num" << endl;
cin >> num2;
cout << "Enter third num" << endl;
cin >> num3;
}
I have done this like this but I think it's not a proper way to do it.
for(int i = 0; i <= 0; i++) {
cout << num1;
cout << num2;
cout << num3;
}
for(int i = 0; i <= 0; i++) {
cout << num3;
cout << num2;
cout << num1;
}
Edit:
is this better?
int main()
{
int numbers[3];
cout << "Enter first num" << endl;
cin >> numbers[0];
cout << "Enter second num" << endl;
cin >> numbers[1];
cout << "Enter third num" << endl;
cin >> numbers[2];
for (int i = 0; i <= 2; i++)
{
cout << numbers[i];
}
for (int i = 2; i >= 0; i--)
{
cout << numbers[i];
}
return 0;
}

What you are trying to do is very common in programming languages. I.e. enter data, process it and output it in one form or another.
A loop is what you use if you want to execute a piece of code a number of times... a number more than 1 that is. In your first example you execute the loop once, making the extra lines of code a bit redundant.
You already updated your code, showing you quickly realized how to used arrays. These types of arrays (i.e. int numbers[3];) are often referred to as C-style arrays, as they were inherited from C. In C++ we can now use std::array<int, 3> numbers;, which more adheres to the C++ style of working. (The std:: part of the type name indicates the type is define in the standard library namespace. The type is part of the C++ language standard.)
The problem with these two types is that they have a static(=fixed) size. I.e. the size has to be know at compile time. This can be quite a limitation if you don't know how many items the user wants to enter. However, the C++ standard defines other container types which can hold a variable amount of items. Of these, std::vector is the dynamic (variable) size counterpart of the array: these both store their items sequentially in memory.
So you can for instance use a loop to add (to the back = push_back()) a number of elements selected by the user to the vector.
#include <vector>
#include <iostream>
[...]
std::vector<int> numbers;
std::cout << "How many numbers do you want to enter?\n";
int N;
std::cin >> N;
numbers.reserve(N); // good practice to reserve memory if you know the number of elements
for (int i = 0; i < N; ++i) {
std::cout << "Enter a number: ";
int number;
std::cin >> number;
numbers.push_back(number);
}
[...]
Note that there is no check on the input: e.g. if the user would enter "-1" after the first question, things would break. I will not consider handling user error in my answer.
You can already see some code duplication in here: cout, type definition, cin. You can extract this in a separate function.
#include <string>
[...]
int ReadUserInput(std::string const& message) {
std::cout << message;
int value;
std::cin >> value;
return value;
}
or even better, you make a function template. I.e. a template for a function: the compiler will generate implementations of this function for you, depending on the type T inferred. I also use the std::string_view now, which can view to different types of strings (std::string, char*)
#include <string_view>
[...]
template<typename T>
T ReadUserInput(std::string_view message = "") {
if (!message.empty()) std::cout << message; //only print is there's an actual message
T value;
std::cin >> value;
return value;
}
Next, the C++ library has more to offer, including a number of algorithms that are commonly used in programming. One of these is a generator that repeatedly calls a function, of which the result is used to assign successive elements in a container. The object that points to a specific element in the container is called an iterator. The C++ standard library offers a convenient iterator type that executes a push_back: the std::back_inserter. The previous code can now be reduced to:
int const N = ReadUserInput<int>("How many numbers do you want to enter?\n");
std::vector<int> numbers;
numbers.reserve(N); // good practice to reserve memory if you know the number of elements
std::generate_n(back_inserter(numbers), N, ReadUserInputGenerator<int>("Enter a number: "));
"But wait", you might ask, "what is this ReadUserInputGenerator?". Well, to make the generate_n work, you need to pass a pointer/handle to a generator function, which is then executed for each element. If we'd just call ReadUserInput<int>("Enter a number: "), then the function would already have been evaluated. So we need to add another intermediate function object that makes this generator function. In the passed we would make a class for this
template<typename T>
class ReadUserInputGenerator {
private:
std::string_view message;
public:
ReadUserInputGenerator(std::string_view message = "") : message(message) {}
T operator()() const { return ReadUserInput(message); }
};
... but now we can do using lambda expressions
template<typename T>
auto ReadUserInputGenerator = [](std::string_view message = "") {
return [message]() { return ReadUserInput<T>(message); };
};
(note to more experienced readers: I'm not really sure about passing string_view by value. I based it on this)
SOOOOO, now we finally have our input. Next you wanted to sort it. Again, this is a common operation. There are actually many ways to sort a collection a values and it is a good excersize to implement these yourself... However, like I mentioned previously, as these kind of operations are common in programming, the C++ standard library actually offers an algorithm for sorting: std::sort.
std::sort(begin(numbers), end(numbers));
^ here begin and end refer to iterators pointing to the begin and end (or actually one past the end) of your vector. You could sort only part of your vector this way. However, the most common case is just begin to end, so in C++20 they've introduced the ranges algorithms, and the previous statement can be reduced to
std::ranges::sort(numbers);
... AAAND now its sorted... printing is next. You can print using a loop... but even there you will have a number of choices. And indexed loop:
for (int i = 0; i < numbers.size(); ++i) {
std::cout << numbers[i] << ' ';
}
An iterator based for loop:
for (auto it = cbegin(numbers); it != cend(numbers); ++it) {
std::cout << *it << ' ';
}
Note: the 'c' before begin and end denote that it is a "const" qualified iterator, i.e. it may not modify the contents of the object it points to.
Or a range based for loop:
for (int number : numbers) {
std::cout << number << ' ';
}
There is also a special convenience iterator type that can push to the cout: std::ostream_iterator. You can copy the vector to this iterator using the algorithm std::copy
std::copy(cbegin(numbers), cend(numbers), std::ostream_iterator<int>(std::cout, " "));
Note, the second argument of the ostream_iterator is the delimiter, i.e. the string appended after each element. Of course there's also a C++20 ranges version.
std::ranges::copy(numbers, std::ostream_iterator<int>(std::cout, " "));
... FINALLY reversing.
One option is just to reverse all elements in the vector and print them out again using one of the above mentioned methods. There's of course an algorithm to do so: std::reverse.
std::reverse(begin(numbers), end(numbers));
However, this operation modifies the contents of the container(vector), which might be costly. If you don't want to to this, you'll have to loop though your vector in reverse order
for (int i = numbers.size() - 1; i >= 0; --i) {
std::cout << numbers[i] << ' ';
}
This looks complex, and it's easy to make errors.
You could instead use the reverse iterators of vector, to traverse through the vector in reverse order: (you need to add an 'r' to the begin/end)
for (auto it = crbegin(numbers); it != crend(numbers); ++it) {
std::cout << *it << ' ';
}
or
std::copy(crbegin(numbers), crend(numbers), std::ostream_iterator<int>(std::cout, " "));
For C++20, there's no range operation to reverse the vector. However, they introduced "views" that are used to observe the values in the vector in a specific way. One such a way is "observe it in reverse order": std::ranges::view::reverse. So in C++20 you will be able to do:
for (int number : numbers | std::views::reverse) {
std::cout << number << ' ';
}
or
std::ranges::copy(numbers | std::views::reverse, std::ostream_iterator<int>(std::cout, " "));
which both don't modify numbers.
The end code could look a little bit something like this (pre C++20 version):
#include <vector>
#include <iostream>
#include <string_view>
#include <iterator>
#include <algorithm>
template<typename T>
T ReadUserInput(std::string_view message = "") {
if (!message.empty()) std::cout << message; //only print is there's an actual message
T value;
std::cin >> value;
return value;
}
template<typename T>
auto ReadUserInputGenerator = [](std::string_view message = "") {
return [message]() { return ReadUserInput<T>(message); };
};
int main() {
int const N = ReadUserInput<int>("How many numbers do you want to enter?\n");
std::vector<int> numbers;
numbers.reserve(N); // good practice to reserve memory if you know the number of elements
std::generate_n(back_inserter(numbers), N, ReadUserInputGenerator<int>("Enter a number: "));
std::sort(begin(numbers), end(numbers));
std::copy(cbegin(numbers), cend(numbers), std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
std::copy(crbegin(numbers), crend(numbers), std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
}

Given that the input doesn't seem to have any meaning other than "some numbers", you should use a container, and the obvious choice would be:
std::vector<int> nums;
From c++20, you don't needs loops at all for this problem, because you can use ranges:
#include<ranges>
namespace rs = std::ranges;
namespace rv = std::views;
and now you can read in numbers like this:
rs::copy_n(std::istream_iterator<int>(std::cin), 3,
std::back_inserter(nums));
I'm not sure if you want to use the order that the user inputs the numbers, but if you want the actual smallest to largest, you can do:
rs::sort(nums);
Now to print out the numbers:
rs::copy(nums,
std::ostream_iterator<int>(std::cout, " "));
and in reverse:
rs::copy(nums | rv::reverse,
std::ostream_iterator<int>(std::cout, " "));
Here's a demo.

You don't need a loop, the one you have it's not really a loop in the sense that it only cycles once, you can use a chained ostream:
cout << num1 << " " << num2 << " " << num3 << "\n";
And
cout << num3 << " " << num2 << " " << num1 << "\n";
But if you want print them sorted by value and you can't use some container where you can apply a sorting algorithm, you'll need some conditionals.
EDIT: Is this better?
Storing it in an array makes it easier to deal with the data, for instance, it will allow you to sort it by value using something as simple as <algorithm> library std::sort.

Related

How to find the greatest number among the numbers given input?

I'm a beginner in programming and as you can see, I created a program where the user is asked to input three numbers. It will display the greatest among the numbers given. But after I finished the code, a question came into my mind, what if the user was asked to input a hundreds of numbers and should display the greatest among the numbers given. So the question is, is it possible to do that? what are the things I need to learn to produce that result? is there any hints you can give me?
#include <iostream>
#include <string>
using std::cout, std::cin, std::endl, std::string;
int main() {
string result = " is the greatest among the numbers given";
double x, y, z;
cout<<"Enter three numbers to decide which is the largest: "<<endl;
cin >>x;
cin >>y;
cin >>z;
system("clear");
if(x>y && x>z){
cout<< x << result;
} else if (y>z && y>x){
cout << y << result;
} else
cout<< z << result;
return 0;
}
With the program below, you can get as many numbers as you want from the user and find the largest of them.
#include <iostream>
int main()
{
int size=0, largestValue=0, value=0;
std::cout << "Enter total numbers you want to add :" << "\n";
std::cin >> size;
for (int i{ 0 }; i < size; ++i)
{
std::cout << "Enter value to add : ";
std::cin >> value;
if (i == 0 || value > largestValue)
{
largestValue = value;
}
}
std::cout << "Largest value = " << largestValue << "\n";
return 0;
}
One solution would be to store your inputs in a list and sort them afterwards. Just google "sorting alorithms". Also there are nice youtube visualizations.
Another one would be to not save the inputs into dedicated variables - in your case x, y, z - but to always save the largest given input:
int largestInput = std::numeric_limits<int>::min();
int input;
for (int i = 0; i < 10000; i++)
{
std::cin >> input;
largestInput = input > largestInput ? input : largestInput;
}
If you know the inputs are large, you can use vectors.
#include <bits/stdc++.h>
using namespace std;
int main(){
int total_num=0;
cout << "Enter total numbers:" << "\n";
cin>>total_num;
int max_number = INT_MIN;
vector<int> v;
for(int i=0;i<total_num;i++){
int x;
cin>>x;
v.push_back(x);
max_number = max(max_number,x);
}
cout<<"Maximum number present: "<< max_number<<endl;
return 0;
}
Although there is no need to store numbers. But it's your choice if you need it later you can use it in that program.
> what are the things I need to learn
what if the user was asked to input a hundreds of numbers
For this, you'll need to learn about arrays. I suggest you first learn about C-style arrays (int x[3]{};), and then std::array (std::array<int, 3> x{};). You also need to learn about loops.
and should display the greatest among the numbers given
Having to find the largest number in an array is very common. If you want to learn how to do so manually, the other answers here should answer your question. Otherwise, look towards the standard library algorithms std::ranges::max() (C++20) and std::max_element.
Examples
Example 1
Here's a program that uses a C-style array and a simple algorithm to get the largest number:
#include <iostream>
int main(){
// Amount of numbers user should input
constexpr int count{ 3 };
std::cout << "Enter " << count
<< " numbers to decide which is the largest:\n";
// The numbers entered by the user
double numbers[count]{}; // Declare and zero-initialize a C-style array of 3 ints
// Get each number from the user and put it in the array
for (int i{ 0 }; i < count; ++i) {
std::cin >> numbers[i];
}
// The biggest number found so far
int max{ numbers[0] }; // Initialize it with the first number
for (int i{ 1 }; i < count; ++i) { // Start at the second element (element 1)
if (numbers[i] > max) { // If the current number is larger than max...
max = numbers[i]; // ...assign it to max
}
}
std::cout << max << " is the greatest among the numbers given\n";
return 0;
}
Note:
int numbers[count]{};
This creates a C-style array called numbers which has count (3) elements. The first element's "index" is 0 and the last element's is 2. The {} initializes the values of all of the numbers to 0 (good practice).
for (int i{ 0 }; i < count; ++i)
std::cin >> numbers[i];
This loops until i isn't less than count (3) and increments i (++i) each time. It starts at 0, so it loops 3 (0 1 2) times. On each iteration, it gets a number from the console and stores it in numbers[i].
Example 2
Here's a shorter program that uses the standard library:
#include <algorithm> // ranges::max()
#include <array> // array<>
#include <iostream> // cin, cout
int main() {
// Amount of numbers user should input
constexpr int count{ 3 };
std::cout << "Enter "
<< count
<< " numbers to decide which is the largest:\n";
std::array<double, count> numbers{}; // Declare an array of 3 ints
for (int i{ 0 }; i < count; ++i) {
std::cin >> numbers[i];
}
// Return the largest number in array "numbers"
std::cout << std::ranges::max(numbers)
<< " is the greatest among the numbers given\n";
return 0;
}
Note:
std::array<int, count> numbers{};
Declares an array of count (3) ints and zero-initializes it.
std::ranges::max(numbers)
This neat function finds the largest number in numbers. It was added in C++20 -- if you're using an older compiler, you should use *std::max_element(numbers.begin(), numbers.end()). If you want to learn how the latter works, you need to learn about iterators and pointers.
Here are some good practices that your tutorial hasn't taught you yet (if it ever will):
DON'T use using namespace std. It's unsafe because it brings everything in the standard library into global scope. The standard library contains a lot of commonly used identifiers like count and list. Bringing these into global scope is dangerous because it can cause naming conflicts.
Don't use copy initialization (int x = 3). Use uniform/brace/list initialization instead (int x{ 3 }). The former sometimes makes an unnecessary copy, whereas the latter doesn't. The latter also refuses to do narrowing conversions (e.g. initializing a short with a long).
Always initialize variables (do: int x{}, don't: int x), even when it seems redundant. If you don't, then the value stored is undefined - it could be anything. Undefined behaviour is hard to debug but luckily easy to avoid.
Use \n instead of std::endl. Both do the same, except std::endl does an extra buffer flush which is slow and unnecessary. \n is shorter anyways.
DRY -- Don't Repeat Yourself. You have the string " is the greatest among the numbers given" three times in your code. You could have stored it in a std::string instead -- then it wouldn't have repeated.
Repeating code is bad, because:
It's harder to read
It's harder to maintain (you would have to modify it everywhere it's repeated)
Maintenance is more error-prone
If I were you, I'd immediately find a different tutorial/book. See this thread.
#include <stdio.h>
int main()
{
int num1, num2, num3, num4;
printf("Enter num1\n");
scanf("%d",&num1);
printf("Enter num2\n");
scanf("%d",&num2);
printf("Enter num3\n");
scanf("%d",&num3);
printf("Enter num4\n");
scanf("%d",&num4);
if(num1>num2 && num1>num3 && num1>num4){
printf("greatest number is %d",num1);
}
if(num2>num3 && num2>num1 && num2>num4){
printf("greatest number is %d",num2);
}
if(num3>num1 && num3>num2 && num3>num4){
printf("greatest number is %d",num3);
}
if(num4>num1 && num4>num2 && num4>num3){
printf("greatest number is %d",num4);
}
return 0;
}

How to get a vector of strings from input?

I'm trying to get a vector of string from input to create a graph , but i don't know why in middle my code it crashes. please help me fix it. I use Visual Studio.
#include <iostream>
#include <vector>
#include <iterator>
void main(void)
{
{
using namespace std;
int8_t n{ 0 };
cout << "enter the size of graph : ";
cin >> n;
vector<string> graph(n);
string connectionsWith;
vector<string>::iterator i;
string::iterator e;
int p{ 0 };
for (i = graph.begin(); i != graph.end(); ++i)
{
cout << '\n' << "enter the vertices that are connected to " << p << " : ";
cin >> connectionsWith;
graph.push_back(connectionsWith);
p++;
}
p = 0;
for (i = graph.begin(); i != graph.end(); ++i)
{
cout << p << " is connected to " << *i;
p++;
}
}
}
In your constructor of graph, you allocate n string. Inside the loop you add on top of the constructed n strings, n more strings via push back. That potentially invalidates your iterators, as ChrisMM said, also not the most efficient way to implement such a scenario.
So as a solution, instead of
vector<string> graph(n);
do
vector<string> graph;
graph.reserve(n);
and iterate over the index, e.g. from 0 to n, and push back.
Especially in the first loop you are not dereferencing the iterator at all, which suggests that using index based loop would show your intent better.
life_steal pointed out the problem. I would like to add few information and other way to solve the problem.
int8_t n{ 0 };
vector<string> graph(n); // Here initialization happening with ASCII. If input is "1" then it would be "49". Consider changing int8_t to int if you unaware of that.
graph.push_back(connectionsWith); //Instead of this line Use: *i = connectionsWith; it directly assign the value.

Finding the end of an array in a loop in C++?

I wanted to distinguish between the end of an array an the rest of the elements (in a for loop), but most examples initializes a variable outside the loop, which I think clutters the loop. The shortest example I have achieved is by looking at pointer addresses in a ranged-based for-loop:
for(auto& x : arr){
cout << x;
if(&x != &*end(arr)-1)
cout << ", ";
}
This doesn't need an extra variable, but I am not 100% sure of the implications from using pointers in C++.
A more (or less?) readable example where I initialize a variable in the for-statement, in a way that looks quite intuitive (edit doesn't give portability to fuctions):
for(int i{0}, len{sizeof(arr)/sizeof(*arr)}; i<l; i++){
cout << arr[i];
if(i!=len-1)
cout << ", ";
}
Is there a more readable/better/shorter way to do this without extra includes?
Are there any cons to these approaches?
Why not do the following?
bool not_first_item = false;
for(auto x : arr){
if (not_first_item) {
cout << ", ";
not_first_item = true;
}
cout << x;
}
It will print a comma before each item except the first one. It will get the result you require without the need of using complicated pointers.
If all you have is a pointer to an element in an array, there is no portable way of detecting the position of that element in an array.
Alternatives; best first:
Use a std::vector. That has similar semantics as a plain old array and has the benefit of carrying in the size.
Pass the size of the array as an additional parameter, with size_t type.
Use a magic value to signify the end of an array.
Note that using &x is pointless as x is a value copy. Consider auto& x instead?
This might help
l=sizeof(arr)
for(int i{0}; i<l-1; i++){
cout << arr[i];
cout << ", ";
}
cout << arr[sizeof(arr)];
or
for(int i{0}; i<sizeof(arr)-1; i++){
cout << arr[i];
cout << ", ";
}
cout << arr[sizeof(arr)];
there is no extra condition.
If showing is the main intention
A concise way that I like, without extra branch:
const char* sep = "";
for (const auto& x : arr) {
std::cout << sep << x;
sep = ", ";
}
Yes it uses extra variable.
As a general rule, you should not discard information that you need. When you use a range-based for loop you abstract away the position of an element in the container (and in fact the form of the container). Therefore, it is not the most appropriate tool for the job. You could do this with an index or an iterator because those hold enough information for you to tell whether the element you are iterating over is the last one.
The standard library offers two helpful functions begin and end that either call the member functions begin and end of STL containers, or pointers to the first and past-the-end elements for C-style arrays. Because of the way the end condition is checked, you don't need anything more than a forward iterator.
assert(std::begin(arr) != std::end(arr));
for (auto it = std::begin(arr); it + 1 != std::end(arr); ++it) {
std::cout << *it << ", ";
}
std::cout << *(std::end(arr) - 1) << '\n';
The above code is fine if you know that you're never going to attempt to print an empty container. Otherwise, you'll need an extra if statement to check for that. Note that even if you have a random access iterator and you use the condition it < std::end(arr) - 1 you might reason that it's fine even for empty arrays, but it is undefined behavior and it might lead to some unexpected bugs when optimizations are turned on.
Not 100% sure what I was looking for but I think that the real answer might be to check for the starting item like #ed_heel proposed, but I really only needed to change what I checked for in the range-based for-loop to make it much neater:
for(auto &x : arr)
{
cout << (&x == arr ? "" : ", ") << x;
}
works since arr is an array (a.k.a. pointer in disguise).

How to take inputs from array and input it into an equation in C++?

My goal is to try and create a program that takes in grades in percents and multiply it with their weight value (either in decimal form or percent form). The equation is basically:
Overall grade = (grade1*weightInDecimal1)+(grade2*weightInDecimal2)+(grade3*weightInDecimal3)+...
or
Overall grade = (grade1*weight%1)+(grade2*weight%2)+(grade3*weight%3)+...
Is there a way to store the inputs and then recall it later in the code? Or possibly a more efficient way?
I also want to try and make a dynamic array. I want to make a program that asks the user for how many assignments they have and makes an array based on that. That way it's not stuck at 4 assignments
#include <string>
#include <iostream>
using namespace std;
int main() {
int numbers[4][2];
for(int i=0;i<4;i++)
{
cout<<"Grade #"<<i<<endl;
cin>>numbers[i][0];
cout<<"Weight for grade #"<<i<<":"<<endl;
cin>>numbers[i][1];
}
for (int i = 0; i<4; i++)
{
cout << "|" << numbers[i][0]*numbers[i][1]<< "|";
}
system ("PAUSE");
return 0;
}
This is what structs are for
#include <string>
#include <iostream>
#include <array>
using namespace std;
struct entry {
int grade;
int weight;
int gradeWeight; //grade*weight
};
int main() {
array<entry,4> numbers;
for(int i=0;i<numbers.max_size();i++)
{
cout<<"Grade #"<<i<<endl;
cin>>numbers[i].grade;
cout<<"Weight for grade #"<<i<<":"<<endl;
cin>>numbers[i].weight;
}
for (int i = 0; i<numbers.max_size(); i++)
{
numbers[i].gradeWeight = numbers[i].grade*numbers[i].weight;
cout << "|" << numbers[i].gradeWeight << "|";
}
system ("PAUSE");
return 0;
}
This way you can also increase the amount of numbers by just increasing the array size.
As pointed by others, if you ask the user for how many assignments they have, std::array is a wrong container because it's dimension is fixed at compile time.
As others, I discurage the use of direct memory allocation but the use of std::vector to manage it.
I just suggest the use of reserve() (method of std::vector), when you know how many assignments.
The following is a full example using, instead a couple of std::vector of int, a single std::vector of std::pair<int, int>
#include <utility>
#include <vector>
#include <iostream>
int main()
{
int valG, valW;
std::size_t dim;
std::vector<std::pair<int, int>> vec;
std::cout << "How many grade/weight couples? ";
std::cin >> dim;
vec.reserve(dim);
for ( auto i = 0U ; i < dim ; ++i )
{
std::cout << "Grade #" << i << "? " << std::endl;
std::cin >> valG;
std::cout << "Weight for grade #" << i << "? " << std::endl;
std::cin >> valW;
vec.emplace_back(valG, valW);
}
for ( auto const & p : vec )
std::cout << '|' << (p.first * p.second) << '|';
std::cout << std::endl;
return 0;
}
There are many reasons to avoid using arrays (dynamic or otherwise). See for example Stroustrup's FAQ entry What's wrong with arrays? As Greg suggests in the comments you will most likely write better quality code if you use a container like std::vector.
If you can calculate or input the size of your container before allocating it you can (if you wish) pass that size to the constructor ...
auto syze{ 0 };
auto initialValue{ 0 };
// calculate or input syze
. . .
// dynamically allocate an "array"
// of ints and an "array" of floats
std::vector<int> grades(syze, initialValue);
std::vector<float> weights(syze, initialValue);
On the other hand if you prefer to use a container that dynamically grows to hold data as it arrives you can do that too...
// dynamically allocate an empty "array"
// of ints and an empty "array" of floats
std::vector<int> grades;
std::vector<float> weights;
while (...condition...)
{
std::cin >> g; // input a grade ...
std::cin >> w; // ... and a weight
// grow the containers by adding
// one item at the end of each
grades.emplace_back(g);
weights.emplace_back(w);
}
Update
I should have pointed out how to calculate the result from the two vectors. You can calculate your overall grade with just one more line of code by using std::inner_product from the STL's <numeric> header. Note that in the code below the last argument is 0.0 (rather than just 0) so that std::inner_product returns a double rather than an int. That avoids any risk of float values being truncated to int (and avoids some pretty ugly warnings from the compiler).
auto overallGrade = std::inner_product(grades.begin(), grades.end(), weights.begin(), 0.0);

multiplying numbers in vector out of order in C++

My name is Matt. I'm new to StackOverflow and am fairly new to C++. Currently working my way through C++ Primer by Lippman.
I'm doing an exercise in the book, and task is to read integers in to the vector, and then multiply those integers by doing first and last, second and second to last, third and third last etc.
I did it myself without looking anything up, or else I'd barely learn if I just copied... my program compiles and acts as expected. My question is: did I do this correctly? is there a more efficient way of doing it?
I not only want to learn how to make working code, but I want to do it correctly. Thank you in advance!
#include <iostream>
#include <string>
#include <vector>
#include <cctype>
using std::cout; using std::cin; using std::vector; using std::endl;
using std::string;
int main()
{
vector<int> numbers;
int usernum = 0;
cout << "Enter some numbers: ";
while (cin >> usernum)
{
numbers.push_back(usernum);
}
unsigned maxElement = numbers.size() - 1;
unsigned minElement = 0;
for (auto i : numbers)
{
cout << numbers[minElement] << " * " << numbers[maxElement] << " = " << numbers[minElement] * numbers[maxElement] << "\n";
++minElement;
--maxElement;
}
return 0;
}
In a comment, you said:
I've noticed it doesn't actually work as fully expected. It goes through vector and multiplies everything twice as maxElement goes right through to beginning, and minElement goes through to end. Not sure how to stop it once it's only done the operation on each one time.
If you don't want to repeat the multiplications, you need to change the for loop a bit.
for ( ; minElement <= maxElement; ++minElement, --maxElement)
{
cout << numbers[minElement] << " * " << numbers[maxElement] << " = " << numbers[minElement] * numbers[maxElement] << "\n";
}
PS
When you use this logic, you'll need to make sure that minElement and maxElement are of a signed type. Otherwise, you will run into problems if numbers has only one element.
The first thing that feels strange for me is the namespaces you are using.
Instead of doing: using namespace std::vector; you can fairly just do using namespace std; because you call std::vector anyways: vector<int> numbers;***. This applies to any "used" namespace you work with. Just do using namespace std; once and for all.
***I am unsure that std::vector/std::cout/... is even a namespace. std - is a namespace. std::vector should be a class under std namespace:
namespace std
{
template<typename T> class vector<T> {...};
}
How come it "acts as expected". I do not get an idea of this loop: while(cin >> usernum). How do you know when the user input is finished from that point? For a first glimpse (did not compile/run it myself) I expect it either:
not compile
crash at runtime or having undefined behaviour
run the while-loop infinitely
Use this instead:
for (int i = 0, end_of_vector = numbers.size(); i < end_of_vector/2; i++)
{
cout << numbers[i] << " * " << numbers[end_of_vector - 1 - i] << " = " << numbers[i] * numbers[end_of_vector - 1 - i] << "\n";
}
Reasons:
In this case you do not need any special variables to store first and last vector indexes.
You iterate only through a half of an array.
Using for (auto i : numbers), is is expected to use i as an element of numbers vector. But you do not do this, instead, you use numbers as is. Thus, this for-loop is ambiguous