I am trying to code a simple macro which based on a condition either calls break or continue in the loop in which it is called. Below is the code:
#include <iostream>
#define BC_IF_EVEN(BC) if(i % 2 == 0) BC
using namespace std;
int main() {
int i = 0;
while(i++ < 30) {
if(i < 15)
BC_IF_EVEN(continue);
else
BC_IF_EVEN(break);
cout << i << " ";
}
cout << endl;
}
The output that I am looking for is: 1 3 5 7 9 11 13 15, but the above code outputs: 1 3 5 7 9 11 13 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 because the else condition in main() gets applied to the if condition in the BC_IF_EVEN macro.
A simple fix is to put scope braces for the if condition in main(), but I do not want to enforce that because the user should be allowed to code in regular way.
N.B. I cannot put a do { .. } while(false) loop in the macro (which is a standard trick to allow semicolons after macro calls in conditionals because the break and continue sent via BC get applied to this inner loop.
Is there an easy way to get the required output without modifying the main() function?
#define BC_IF_EVEN(BC) if (i % 2 != 0); else BC
but really WHY?
Don't invent obscure macros in an attempt to justify your obscure loops. Frequent use of continue and break inside loops is a certain sign of poor program design.
Here's how to fix the program:
When the amount of items you iterate through is known in advance, use a for loop, as they are usually easier to read and harder to mess up.
Since you check if a number is even no matter in which way the program branches, might as well move that check outside the if-else.
for(int i=0; i<30; i++)
{
if(i%2 == 0) // even
{
if(i < 15)
continue;
else
break;
}
cout << i << " ";
}
Now look at the conditions and what the program actually does. This doesn't make sense at all. All it does is to print the odd numbers between 0 and 14 in a very obscure way. Instead, you probably wanted a program which prints the odd numbers between 0 and 15.
Apply common sense: Loop from 0 to 15. Check each number to see if it is odd. If so, print it. Otherwise ignore it.
for(int i=0; i<=15; i++)
{
if(i%2 != 0)
cout << i << " ";
}
Alternatively, don't bother with even numbers at all:
for(int i=1; i<=15; i+=2)
{
cout << i << " ";
}
This is why functions were created, just create a function to check if it is even or odd and return a true if even and false if odd. Macros are ugly when you can do it simply another way. Please for the love all legacy maintainers make readable code.
eg:
// Example program
#include <iostream>
using namespace std;
bool checkeven(int i)
{
if( i % 2 != 0)
return false;
else
return true;
}
int main()
{
for(int i = 0; i < 30; i++) //while(i++ < 30) is readable, but I think this is even easier
{
if(i < 15)
{
if(checkeven(i))
continue;
}
else
{
if(checkeven(i))
break;
}
cout << i << " ";
}
}
Use curly brackets even if you have the only line in if/else statement. In this case you'll fully control the workflow.
The other advantage of this approach is that if you need to comment out the line in if/else statement you'll just put // in the start of the line.
// wrong workflow
if ( expr )
// commented out for debug issues
//do_when_expr();
do_whatever();
// right workflow
if ( expr )
{
// commented out for debug issues
//do_when_expr();
}
do_whatever();
In your case it would be:
#define BC_IF_EVEN( BC ) if (i % 2 == 0) { BC; }
...
if(i < 15)
{
BC_IF_EVEN(continue)
}
else
{
BC_IF_EVEN(break);
}
Try this
#define BC_IF_EVEN(BC) ( { if(i % 2 == 0) BC; } )
You just need an extra pair of curly braces to restrict the scope for your inner if block. Following should work:
#define BC_IF_EVEN(BC) {if(i % 2 == 0) BC;}
Also do not use ';' while using macro:
if(i < 15)
BC_IF_EVEN(continue) //No semicolon
Or if you want use semicolon for code consistency then an extra pair of braces has to be put:
#define BC_IF_EVEN(BC) ({if(i % 2 == 0) BC;})
Related
I have been programming in C++ for the past 3 years, and I have always used the continue keyword in loops with success. But right now, a simple code of mine with continue is not working properly. Here is the code that is showing the problem:
int main()
{
int num = 2, result = 0;
while (num > 1 && num < 50)
{
if (num % 2 != 0)
{
result += num;
}
else
{
continue;
}
num++;
}
cout << "The result is: " << result << endl;
return 0;
}
As stated above, this does not print anything on the console. When I remove the else statement with continue in it, it successfully calculates the result and prints the said result. Does anyone have any idea why the given code is not working correctly (or why the loop in it does not break)? Any sound answer would be much appreciated.
Loop is indeed continuing (continue works properly) correctly
Initially, num = 2, so if condition fails and goes to else. So it will call continue. Then again the loop starts from the beginning with num = 2. This continues forever.
In short, num value is not changing and if condition always fails.
It's a very simple issue. Look at this block of code properly:
else
{
continue;
}
Due to continue, n++ is never called because due to the non-changing value of n, num % 2 != 0 is always false. This is resulting in an infinite loop.
So to fix this issue, just remove the above block of code:
#include <iostream>
int main()
{
int num = 2, result = 0;
while (num > 1 && num < 50)
{
if (num % 2 != 0)
{
result += num;
}
/*else
{
continue;
}*/
num++;
}
std::cout << "The result is: " << result << std::endl;
return 0;
}
Also, consider not using the following in your code:
using namespace std;
..as it's considered as a bad practice. For more info on this, look up why is "using namespace std" considered as a bad practice.
You just have to remove your else part because of no use and terminated cause of continue keyword.
int main()
{
int num = 2, result = 0;
while (num > 1 && num < 50)
{
if (num % 2 != 0)
{
result += num;
}
num++;
}
std::cout << "The result is: " << result << std::endl;
return 0;
}
Since continue is just a thinly disguised goto, rewriting the loop with explicit gotos might make it clearer:
start:
if (num > 1 && num < 50)
{
if (num % 2 != 0)
{
result += num;
}
else
{
goto start;
}
num++;
goto start;
}
Now you see clearly that num isn't incremented when num % 2 != 0 is false.
Just remove the else branch.
I'm trying to do a simple while loop that searches a string for a specific character then returns each place the character appears in the string before ending the loop
Here is a version of my code, where I have been trying to catch when the point where the number is no longer either 0, or less than the length of the string, as I couldn't get the while loop to end without the if statement, I tried adding it in to force 'num' to be outside these bounds and see if the while loop conditions would catch it and end the loop, seemingly not.
#include <iostream>
using namespace std;
int main() {
string phrase = "Hello I am a pineapple";
int phraseLength = int(phrase.length());
int num = 0;
while(num < phrase.length() -1 && num > -1)
{
num = int(phrase.find('a', num));
cout << num << endl;
num++;
if(num < phraseLength -1 || num ==0){
cout << num << endl;
}else{
num = 24;
}
}
I'm more used to python and currently trying to learn c++, I know if I were to use these conditions in python, the loop would end, so why not here?
Sample output:
9
11
12
17
18
-1
0
8
9
11
12
17
18
-1
0
8
9
11
12
17
18
-1
0
8
9
11
12
17
18
-1
0
8
9
11
12
17
18
-1
0
8
9
11
12
17
18
-1
0
8
9
11
12
17
18
-1
0
8
9
11
12
17
18
-1
0
The issue was that (like #kalyanswaroop said) when find() cannot find a character it returns -1, the next step in the loop changes the assigned value from -1 to 0, and so it satisfies the conditions of the loop. In order to prevent this from happening I changed the code to the below, so that if num is -1, it breaks the loop.
#include <iostream>
using namespace std;
int main() {
string phrase = "Hello I am a pineapple";
int phraseLength = int(phrase.length() - 1);
int num = 0;
while(num >= 0)
{
num = int(phrase.find(char('a'), num));
if(num > -1)
{
cout << num << endl;
num++;
}
else{
break;
}
}
return 0;
}
Your loop has no exit condition because you don't test the return value of std::string::find properly.
If you read the manual, you'll see that the return value when no match is found is std::string::npos.
Don't expect it to have any other value than the constant provided by the STL, or you'll be sorry.
This will work:
#include <iostream>
#include <string> // include what you need instead of relying on other includes
//using namespace std; <--- don't do this unless you know exactly what you're doing
// (which is unlikely given your limited acquantaince with C++)
int main(void) // "void" is optional, but indicates (argc,argv) have been purposely ignored
{
std::string phrase = "a Hello I am a pineapple a"; // test edge cases when possible
// (here, the first and last chars)
size_t position = 0; // "num" is a terrible variable name, like "int someint"
// and the proper type to use is size_t (unsigned).
// Using an int will get you a warning.
// Ignore warnings at your own risk...
while (true)
{
position = phrase.find('a', position); // look for the character
if (position == std::string::npos) break; // exit condition
std::cout << position << std::endl; // display found occurrences
position++; // move to next character (or end of string)
}
}
Or if for loops are more your thing, you can slightly reduce the code like so:
for (size_t position = 0 ; ; position++)
{
position = phrase.find('a', position);
if (position == std::string::npos) break;
std::cout << position << std::endl;
}
Some people find that nicer, some harder to read.
I rather like it because it makes position local to the loop, preventing you from doing something unwise like reusing the variable outside the loop.
It's really a matter of preference.
when the phrase.find cant find 'a', it returns -1, and then you have num++ which brings num back to the same condition as the beginning.
Perhaps you should do something like:
while(num < phrase.length() -1 && num > -1)
{
int findPos = int(phrase.find('a', num));
if(findPos != nPos) //nPos is defined as -1
{
num = findPos ;
}
else
{
break ;
}
cout << num << endl;
num++;
}
Suggestion: Change your code
Here is a few suggestions
Using find()
The by far easiest way to do this is by using Find() (Thanks to neko for suggesting this. Not sure if he really suggested that)
Example:
#include <iostream>
#include <string>
#include <algorithm> //Don't know if this is required
int main()
{
string phrase = "Hello I am a pineapple";
auto location = std::find(phrase.begin(), phrase.end(), 'a');
cout << *location;
}
Creating a function like find()
Another way to do this (also to get a taste on how find() might be implemented) is by writting a function similar to find()
Example:
#include <iostream>
#include <string>
using namespace std;
template<typename Iterator, typename T>
Iterator Find_Character(Iterator begin, Iterator end, T Find)
{
while (begin != end && *begin != Find) ++begin;
return begin;
}
int main()
{
string phrase = "Hello I am a pineapple";
auto location = Find_Character(phrase.begin(), phrase.end(), 'a');
std::cout << "Found character: " << *location << endl;
}
I want to know why the value of i is not updating to i=0 when i == n-1, as I have written in the code. The bool flag is just there to check if the if statement was rendering at all or not (It is).
#include <bits/stdc++.h>
using namespace std;
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
int n, ans = 0;
scanf("%d", &n);
int s[n];
bool flag = false;
for (int i = 0; i < n; i++)
{
scanf("%d", &s[i]);
}
for (int i = 0; i < n; i++)
{
s[i] -= 1;
if (s[i] < 0)
break;
ans++;
if (i == (n - 1))
{
i=0;
flag = true;
}
}
printf("\n%d\n", ans);
printf("%d", flag);
}
return 0;
}
How do you know it's not doing what you want. I ran it and got this:
$ ./foo
1
2 3 4
5
1
$
The final value (1) is true. So it looks like it's doing it to me.
However, this is pretty terrible code. It's a really bad practice to muck with your iterator variable inside your loop like that. That's GOING to bite you. Furthermore, you're not going to go back to 0 -- you're going to go back to 1, because the next thing it does is increment the variable with your i++. So your if-statement sets i to 0 and your for-loop turns it into 1.
But this is just weird. If you need to run the loop multiple times, then wrap it in a larger loop.
Others have commented on printf. Personally, I disagree with them. There are times printf is completely valid. HOWEVER -- the way you're using it for such simple, unformatted stuff, isn't really one of them.
I changed the last printf to this:
cout << "Flag (raw): " << flag << ". Which means: " << (flag ? "True" : "False") << endl;
Output is this:
Flag (raw): 1. Which means: True
As you can see -- it's 1, which is not 0, so it's true.
So as part of a coding challenge I tried to make a Fizz Buzz program in C++ without looking at the solution. For those of you who don't know, it should be a loop that replaces any number divisible by 3 with Fizz, any number divisible by 5 with Buzz, and any number divisible by both with FizzBuzz:
1
2
Fizz
4
Buzz
6
7
8
Fizz
Buzz
11
Fizz
I'm almost there with the code below, however, i'm a little annoyed that even though I want the loop to stop entirely at 100, the way i've set up the program means that an extra 1 gets added to i after the loop has ended. Is there a way of stopping my FizzBuzz program from going past 100?
#include <iostream>
using namespace std;
int main () {
for (int i = 1; i < 100; ++i){
if (i % 3 == 0 && i % 5 == 0){
cout << "FizzBuzz\n";
i = i + 1;
}
if (i % 3 == 0){
cout << "Fizz\n";
i = i + 1;
}
if (i % 5 == 0){
cout << "Buzz\n";
i = i + 1;
}
cout << i << "\n";
}
}
So I fixed your code a little bit:
int main()
{
for (int i = 1; i < 101; ++i)
{
if (i % 3 == 0 && i % 5 == 0)
cout << "FizzBuzz\n";
else if (i % 3 == 0)
cout << "Fizz\n";
else if (i % 5 == 0)
cout << "Buzz\n";
else
cout << i << "\n";
}
}
Every time you do i = i + 1;, it's kinda useless because your loop does that. Also, I put everything is an if else chain, instead of and if if chain. That way only on statement will execute at any giving time. Also changed the max to 101 instead of 100 since the for loop will stop at 101 and not print the result of 101.
Hope this helps :)
In c++, variables have a lifetime, called their scope, and after their lifetime expires they are deleted. The i that is defined in the loop declaration has the scope constrained by the closing brace "}" of the for loop. Due to this, the variable i does not exist after the loop, only during. However in the code you have provided, the problem is that you are incrementing i multiple times. In your for loop you increment i every time the body of the for loop is executed, but within that body you increment i when it is divisible by 5 or 3 or both or neither. You can remove all of the i = i + 1; statements and remove most of the bugs.
I'm doing the first project euler problem and I just did this
#include <iostream>
using namespace std;
int main(){
int threes =0;
int fives = 0;
int both = 0;
for (int i = 0; i < 10; i++){
if(i%3==0){
threes += i;
}
if(i%5==0){
fives += i;
}
if ( i % 5 == 0 && i % 3 == 0){
both += i;
}
}
cout << "threes = " << threes << endl;
cout << "fives = " << fives << endl;
cout << "both = " << both << endl;
cout << " threes + fives - both = " << endl;
int result = (threes + fives) - both;
cout << result<< endl;
return 0;
}
My professor recently corrected me for doing this in a different problem saying something about else statements,
but I don't understand WHY i have to add else in front of the next if. for what its worth I have another version with else if(i%5){ fives += .... }
and they both work and get me the right answer.
My question is whats inherently wrong with this way of thinking, is it stylistic or am I not thinking logically about something?
If it works, why use switch statements ever?
The only thing that I see wrong with your implementation is that in the case where the number is both a multiple of 3 and a multiple of 5 not only is the both variable incremented but the fives and threes variables are also incremented. Based on what the professor described I believe he wants you to use an else-if so that the both variable is the only one that is incremented when you pass in a number that is both a multiple of 3 and a multiple of 5.
The reason you get the correct answer both ways is because you are only going to 10 in the for loop, if you increase it to i <= 15 you will get fives and threes being 1 higher than I think he intended.
For example:
for( int i = 0; i < 10; i++ )
{
if( ( ( i % 3 ) == 0 ) && ( ( i % 5 ) == 0 ) )
{
both++;
}
else if( ( i % 3 ) == 0 )
{
threes++;
}
else if( ( i % 5 ) == 0 )
{
fives++;
}
}
The else branch in an if-else statement is only executed if the if branch is false. If you just have two if statements in a row, they'll both be executed, which can be a waste. In the below code, the else prevents the second computation from running if the first is satisfied.
if (expensive_computation1()) {
...
}
else if (expensive_computation2()) {
...
}
Additionally, it's clearer to humans reading the code whether both if statements should be allowed to run or whether only one should.
In this case, maybe you really want this:
if (i % 5 == 0 && i % 3 == 0) {
both += i;
} else if (i % 3 == 0) {
threes += i;
} else if (i % 5 == 0) {
fives += i;
}
(why you do += i instead of ++ I don't know but you didn't explain, so I just copied it)
In your code, threes and fives were incremented even if it would also increase both, which depending on your problem may not be what you want. If you do the if/else way I've just presented, only one of the three variables is increased.
Why use if-else instead of multiple if's?
if-else & if would achieve the same results but if-else achieves them in a performance enhanced way. with multiple if's every if condition will have to be checked. With if-else only one conditional check will have to be performed and the rest of the conditions just don't need to be checked at all.
This would not affect a small program like the one you have but it will sure have some impact in potentially expensive function being called repeatedly over and over again.
If it works, why use switch statements ever?
With nested if-else conditions the code is hard to read and understand. The switch-case construct helps to represent the conditions in a much easier to read & understand format.
To me it looks like stylistics. You can use some autoreformating tool that follows certain established stylistic look (K&R, ANSI, GNU, etc.)
For example astyle is such tool, http://astyle.sourceforge.net/ - just reformat your code with it, and you might have a happy professor.