For loop and while loop comparison - c++

So I did the next exercise, just with while loop:
Write a program that prompts the user for two integers.
Print each number in the range specified by those two integers.
Here is the code:
#include <iostream>
int main()
{
std::cout << "Write two numbers: " << std::endl;
int v1 = 0, v2 = 0;
std::cin >> v1 >> v2;
std::cout << "The numbers between " << v1 << " and " << v2 << " are: " << std::endl;
while (v2 < v1 && ++v2 < v1)
{
std::cout << v2 << std::endl;
}
while (v1 < v2 && ++v1 < v2)
{
std::cout << v1 << std::endl;
}
}
Now I have to do it with the for loop, which I did like this:
#include <iostream>
int main()
{
std::cout << "Write two numbers: " << std::endl;
int a, b;
std::cin >> a >> b;
std::cout << "The numbers between " << a << " and " << b << " are: " << std::endl;
for (; a < b && ++a < b; a)
{
std::cout << a << std::endl;
}
for (; b < a && ++b < a; b)
{
std::cout << b << std::endl;
}
}
It looks almost the same, but it works.
My questions is: I'm I missing something about the for loop, could I do it simpler?
PD: Just for loop, I'm not in the If chapter yet, I want to go step by step on the "C++ Primer 5th edition".

for is specified in terms of while, you aren't missing anything.
for (init-statement conditionopt;
iteration-expressionopt) statement
produces code equivalent to:
{ init-statement while (condition) { statement
iteration-expression; } }
Except that
Names declared by the init-statement (if init-statement is a declaration) and names declared by condition (if condition is a
declaration) are in the same scope (which is also the scope of
statement).
continue in the statement will execute iteration-expression
Empty condition is equivalent to while(true)
from cppreference
You don't need anything in iteration-expression for(;;) is equivalent to while(true)
it would be more normal to increment in the iteration-expression, and not repeat almost the same test.
#include <iostream>
int main()
{
std::cout << "Write two numbers: " << std::endl;
int a, b;
std::cin >> a >> b;
std::cout << "The numbers between " << a << " and " << b << " are: " << std::endl;
for (; a < b; ++a)
{
std::cout << a << std::endl;
}
for (; b < a; ++b)
{
std::cout << b << std::endl;
}
}

The for loop is intended to loop between two numbers. The use of your for loops unreadable for it's intentions. Take a look at this
int end = 10;
for (int begin = 0; begin < end; ++begin){/*do something*/}
This is the standard structure of a for loop. Now for your example you will get the following
#include <algorithm>
if (a > b) std::swap(a, b);
for (int begin = a; begin <= b; ++begin){
std::cout << begin << std::endl;
}

There is no need on using something like a < b && ++a < b since a < b is contained in ++a < b condition. So just using ++a < b you will get the same results.
Now about the for you should write it like this just to make your code a bit clear:
for (; a < b; ++a)
{
std::cout << a << std::endl;
}
I am not using the initialization sentence as you have already initialized your variables, however I encorage you to initialize a in the for sentence
In general terms, the for is divided in three sections:
for (<initialization sentence>; <condition sentence>; <post-execution sentence>)
The initialization only runs when the for sentence is reached, and the loop is running while the condition is met. The post-execution it is normally used to increase or change state of the variables involved in the condition criteria. The only constraint you have is that condition must be a boolean sentence.
None of those sections should be an assigment, a common comparison or a variable increment. You could use whatever fits your requirements and met the for constraints.
To sum up, a for sentence is a 'wrapped' structure of a while. You could get the same results with both. The difference is on a cleaner image of your code and a better understanding of the algorithms.

The code in the question is somewhat confusing, because it tries to do several things at once. I'd separate them.
Instead of writing two loops, I'd just change the limits:
if (v2 < v1)
std::swap(v2, v1);
Now it's easy:
while (++v1 < v2)
std::cout << v1 << '\n';
Same thing for the for loop. After adjusting the limits, just do it:
for ( ; ++a < b; )
std::cout << a << '\n';

Related

less-than operator doesn't work properly after few executions

I'm a beginner to learning C++. Just today I tried to learn the boolean operator and if-else statement.
This is the code:
int main(){
//if-else statement
int a, b;
bool result = (a < b);
std::cout << "input number 1 : ";
std::cin >> a;
std::cout << "input number 2 : ";
std::cin >> b;
std::cout << std::boolalpha << result <<std::endl;
if(result == true){
std::cout << a << " is less than " << b << std::endl;
}
if(!(result == true)){
std::cout << a << " is NOT less than " << b << std::endl;
}
return 0;
}
These are the results after a few executions:
Initially the results were fine, but then after a couple times it went wrong.
Does anybody know what the cause of this is?
Your mistake is that you compare the two variables and save the result before you assign any proper values to these variables. In other words, you compare uninitialized variables a and b which have undefined values.
First, you do:
bool result = (a < b);
And then after you get the values:
std::cin >> a;
std::cin >> b;
You should do the following instead:
// ...
int a, b;
std::cout << "input number 1 : ";
std::cin >> a;
std::cout << "input number 2 : ";
std::cin >> b;
bool result = a < b; // <-- move this down here!
// ...
You expect result to be evaluate a == b when you use it later. Instead bool result = (a < b); initializes result with (a < b) once and its value does not change afterwards. As neither a nor b are initialized when you declare result your code has undefined behavior.
You can make result a function object to make it work as you expected by using a lambda expression. However, to call it you'll have to add ():
int main(){
//if-else statement
int a = 0;
int b = 0;
auto result = [&](){ return a < b; };
std::cout << "input number 1 : ";
std::cin >> a;
std::cout << "input number 2 : ";
std::cin >> b;
std::cout << std::boolalpha << result() <<std::endl;
if(result()) {
std::cout << a << " is less than " << b << std::endl;
} else {
std::cout << a << " is NOT less than " << b << std::endl;
}
}
You should always initialize variables. Using the value of uninitialized variables is undefined behavior and can happen easily (as in your code) when you do not initialize variables. Instead of if (condition) {} if (!condition){} you can use if (condition) {} else {}. Instead of if (result() == true) you can write if (result()). And return 0; is implicit in main, you need not write it.
You overall code as it should be.
Explanations in the comments:
int main() {
//if-else statement
int a, b;
std::cout << "input number 1 : ";
std::cin >> a;
std::cout << "input number 2 : ";
std::cin >> b;
bool result = (a < b); // put this here, because now a and b have
// determined values
std::cout << std::boolalpha << result << std::endl;
if (result) { // or simple if (a < b) and drop result alltogether
std::cout << a << " is less than " << b << std::endl;
}
else { // no need for testing the opposite of result
std::cout << a << " is NOT less than " << b << std::endl;
}
return 0;
}

C++20 Coroutines and iostream

I am playing around with C++ 20's Coroutines. The sample is compiled with clang++.
The compiler error I am facing is
error: invalid operands to binary expression ('std::ostream' (aka
'basic_ostream') and 'cppcoro::generator')
which is about the following line
std::cout << numbers << " ";
the full code snipped looks like this:
#include <thread>
#include <iostream>
#include <vector>
#include <cppcoro/generator.hpp>
using namespace std;
// coroutine
cppcoro::generator<int> generatorForNumbers(int begin, int inc = 1)
{
// for Schleife ohne Abbruchbedingung
for (int i = begin;; i += inc)
{
co_yield i;
}
}
int main()
{
auto numbers = generatorForNumbers(-10);
for (int i= 1; i <= 20; ++i)
{
std::cout << numbers << " ";
}
std::cout << "\n\n";
// inline works
for (auto n: generatorForNumbers(0, 5))
{
std::cout << n << " ";
}
std::cout << std::endl;
}
Executable code snipped can be found here:
https://godbolt.org/z/4cxhqxPP7
From the documentation of cppcoro::generator, the only "meaningful" operations you can do to a generator is get begin and end iterators via begin() and end(). This is precisely why your second use for (auto n : generatorForNumbers(0, 5)) works. It iterates over the generator. Though you technically hit undefined behavior since there's no stopping condition for the generator so it overflows an int.
You can't print the generator directly. You have to iterate over it. So you could do this instead:
auto numbers = generatorForNumbers(-10);
auto it = numbers.begin();
for (int i= 1; i <= 20; ++i)
{
std::cout << *it << " ";
++it;
}
or better (in my opinion):
int i = 0;
for (auto n : generatorForNumbers(-10))
{
if (++i > 20)
break;
std::cout << n << " ";
}
or even better using ranges (thanks to #cigien in the comments):
for (auto n : generatorForNumbers(-10) | std::views::take(20))
{
std::cout << n << " ";
}

print multiple numbers in ascending order in C++

So I'm working on this project where I have to gather 2 integers from a user 3 times (loop), and each time I have to print the two integers in ascending order. The restriction is that you can only have two cout statements within your loop (one is asking for their input and the second is outputting the ascending order).
My only issue with that is, when I think about ascending order, I would do it like (which has two count statements):
if (m<n) {
cout << m << n << endl;
if (m>n){
cout << n << m << endl;
So far, this is what I have:
#include <iostream>
using namespace std;
int main(int,char**) {
int n, m, z;
for (n=0;n<3;n++){
cout << "Give me two numbers: ";
cin >> m;
cin >> z;
//if (m>z);
//cout << m << z << "sorted is: " << m << z << endl;
// This is where I'm getting stuck because I need two count statements to organize in ascending order as shown above
}
}
So have you considered to change which variable holds the lower number? e.g.
if(m > n){
int temp = n;
n = m;
m = temp;
}
Then you can just use one print
cout << m << " " << n << endl;
This is where I'm getting stuck because I need two count[sic]
statements to organize in ascending order as shown above
You have marked this post as C++:
Additional options to consider:
use algorithm lib:
#include <algorithm>
std::cout << std::min(m,n) << " " << std::max(m,n) << std::endl;
or use conditional / ternary operator in your cout:
std::cout << ((m<n) ? m : n) << " " << ((n<m) ? m : n) << std::endl;
References are sometimes fun ... but perhaps this challenge is too trivial.
// guess m < n
int& first = m;
int& second = n;
if(!(m<n)) { first = n; second = m; }
std::cout << first << " " << second << std::endl;
Pointers can do the same:
// guess m < n
int& first = &m;
int& second = &n;
if(!(m<n)) { first = &n; second = &m; }
std::cout << *first << " " << *second << std::endl;
or you can use
lambda expressions, or
c++ functions, or
c++ class methods
But I think each of these would be directly comparable to either of the first alternatives.

For loop prints an extra comma

cout<<"Set B : {";
for(i=0;i<b;i++)
{
cout<<setB[i];
cout<<",";
}
cout<<" }"<<endl;
The code above is not printing correctly. It should print Set B : {1,2,3} but it prints an extra comma ==> Set B : {1,2,3,}
Use
cout << "Set B : {";
for (i = 0; i < b; ++i) {
if (i > 0) cout << ",";
cout << setB[i];
}
cout << " }" << endl;
I changed your algorithm :
Before it meant : "Put the number and then put a comma"
Now it means : "If there is a number behind me put a comma, then put the number"
Before, you always printed a comma when you printed a number so you had an extra comma.
For each iteration of the for loop, the program is going to execute -everything- inside the for loop. So, your loop runs through and prints each number in your set and then a comma.
The problem is that even on your last run through the loop, it is going to print a comma, because it's part of the loop.
cout << "Set B : {";
for(i = 0; i < b; i++){
cout << setB[i];
if (i < (b-1))
cout << ",";
}
cout << " }" << endl;
This code will run the exact same, except the second to last time it runs through the loop, it will not print a comma. No need to get too fancy. :)
Personally I like this solution better. You first print out the first element and then a , [second element].
cout <<"Set B : {" << setB[0];
for(i = 1; i < b; i++)
{
cout << ",";
cout<<setB[i];
}
cout << " }" << endl;
Warning!: This will NOT work if the array is empty.
The loop code prints a pair of number and comma. Try using this one:
cout<<"Set B : {";
for(i=0;i<b;i++)
{
cout<<setB[i];
if(i < b-1) cout<<",";
}
cout<<"}"<<endl;
You're loop is executing the cout << "," 3 times. The following will give what you want:
#include <iostream>
using namespace std;
int main(){
int setB[] = {1,2,3};
cout<<"Set B : {";
for(int i=0;i<3;i++)
{
cout<<setB[i];
if ( i < 2 )
cout<<",";
}
cout<<" }"<<endl;
return 0;
}
The way I often deal with these loops where you want to put something like a space or a comma between a list of items is like this:
int main()
{
// initially the separator is empty
auto sep = "";
for(int i = 0; i < 5; ++i)
{
std::cout << sep << i;
sep = ", "; // make the separator a comma after first item
}
}
Output:
0, 1, 2, 3, 4
If you want to make it more speed efficient you can output the first item using an if() before entering the loop to output the rest of the items like this:
int main()
{
int n;
std::cin >> n;
int i = 0;
if(i < n) // check for no output
std::cout << i;
for(++i; i < n; ++i) // rest of the output (if any)
std::cout << ", " << i; // separate these
}
An other way, without extra branch:
std::cout << "Set B : {";
const char* sep = "";
for (const auto& e : setB) {
std::cout << sep << setB[i];
sep = ", ";
}
std::cout <<" }" << std::endl;
I really like to promote the use of a range library to write declarative code instead of nested for-if statements in an imperative style.
#include <range/v3/all.hpp>
#include <vector>
#include <iostream>
#include <string>
int main()
{
using namespace ranges;
std::vector<int> const vv = { 1,2,3 };
auto joined = vv | view::transform([](int x) {return std::to_string(x);})
| view::join(',');
std::cout << to_<std::string>(joined) << std::endl;
return 0;
}
If you can use STL, try the following:
#include <iterator>
#include <iostream>
int main() {
int setB[]{1,2,3};
std::cout << "Set B : { ";
for(auto i = std::begin(setB), e = std::end(setB); i != e;) {
std::cout << *i;
for(++i; i !=e; ++i) { std::cout << ", " << *i; }
}
std::cout << " }" << std::endl;
return 0;
}

Simple C++ Inclusive Calculator Code Review

C++ newbie here. Anything wrong or complicated with this code? The main question I have is whether I can use v1 and v2 inside while (val <= v2)?
#include <iostream>
int main ()
{
std::cout << "Enter two numbers: " << std::endl;
int v1 = 0, v2 = 0;
std::cin >> v1 >> v2;
int sum = 0, val = v1;
while (val <= v2)
{
sum += val;
++ val;
}
std::cout << "The sum of " << v1 << " through " << v2 << " inclusive is " << sum << std::endl;
return 0;
}
Yes, you can, they're local variables in main() so they're in scope until main() returns (i. e. the whole lifetime of the program).
Of course you can. The statement inside the while-loop needs to evaluate to a boolean expression, i.e. true or false. And as you can state that either it is true that val <= v2 or not, this is perfectly fine.