Counter in for loop falsely incrementing after execution - c++

I have 3 nested loops in which the code doesn't in anyway modify the counters, I need the value of the topmost-level loop counter to use later in the code. It looks like this
int i;
for( i = 0; !found && i <f_i.size();i++){
for(unsigned int j = 0; !found && j < f_g.size();j++){
for(unsigned int k = 0; !found && k < f_g.size();k++){
///Do Stuff
found = (/*Condition that's fulfilled after 2 iterations on k*/);
}
}
}
//Stuff that uses i
The condition is fulfilled after 2 iteration of the innermost loop, so i has the value 0 at that point.
Using GDB I saw that the value of i jumps to 1 after the condition is checked in the topmost loop, which gives me a wrong later in my program, or worse an out of bounds access.
Thanks in advance

This is how for loops work. The increment is done before the condition is checked.
The proper way (easier to read, easier to maintain) to do what you want is to add a variable, outside the loop.
int index;
And set it when you find the element:
found = ...
if (found) index = i;

The variable i is incremented due to the third expression of the for loop
int i;
for( i = 0; !found && i <f_i.size();i++){
^^^^
for(unsigned int j = 0; !found && j < f_g.size();j++){
for(unsigned int k = 0; !found && k < f_g.size();k++){
///Do Stuff
found = (/*Condition that's fulfilled after 2 iterations on k*/);
}
}
}
To avoid this you can write for example
int i;
for( i = 0; !found && i <f_i.size();){
for(unsigned int j = 0; !found && j < f_g.size();j++){
for(unsigned int k = 0; !found && k < f_g.size();k++){
///Do Stuff
found = (/*Condition that's fulfilled after 2 iterations on k*/);
}
}
i += !found;
}
Or instead of the expression statement
i += !found;
you can use the if statement like
if ( !found ) ++i;
Also the code will look more readable if the variable i will be initialized before the loops for example like
int i = 0;
while ( !found && i < f_i.size() ){
for(unsigned int j = 0; !found && j < f_g.size();j++){
for(unsigned int k = 0; !found && k < f_g.size();k++){
///Do Stuff
found = (/*Condition that's fulfilled after 2 iterations on k*/);
}
}
i += !found;
}

As others have said (or, at least, implied): once the (outermost) for loop is entered†, the variable, i, will be incremented at the end of that loop, before the condition is tested, to see if another loop should be run ...
... that is, unless you 'jump out' of the loop using a break statement!
So, the following, slightly modified, code will not increment i (at all) if found becomes true during the first iteration of the outermost loop:
int i;
for (i = 0; !found && i < f_i.size(); i++) {
for (unsigned int j = 0; !found && j < f_g.size(); j++) {
for (unsigned int k = 0; !found && k < f_g.size(); k++) {
///Do Stuff
found = (/*Condition that's fulfilled after 2 iterations on k*/);
}
}
// If "found" becomes true, exit the loop immediately, AVOIDING THE INCREMENT:
if (found) break;
}
So, while the other answers are very good, and the code solutions they offer are perfectly valid, the proposal here is a far more 'minimal' adjustment to your code. I hope it helps.
Note: You could, of course, add similar break statements to the inner loops; however, as your j and k variables are declared locally to those loops, it would appear that undesired increments to their values is not relevant. Furthermore, break cannot be used to jump out of multiple, nested loops.
† Also, be aware that if the found variable is true before the outermost for loop is encountered, that loop will not be executed (obviously) and, thus, the i variable will not be incremented in that case.

Related

Can I use 2 loop statement in one loop?

is this loop statement is correct?
if not correct then what alternative way?
I am trying to o(n) loop statement like this-
for(int i=0 ; i<n ; i++ , j=n ; j<n*2 ; j++){
continue;
}
The construct is wrong, you cannot you two loops in one construct, but you can have more than one variable controlling the iteration.
For example, you can have
Two (or more) variables, i and j, initialized with certain values.
A loop controlling statement, involving operation and condition check on i and j (and others, if defined).
Finally, you can control the increment or decrement of i and j (and others, if defined).
A sample construct can be:
for (int i = 0, j = n; i < n && j < n * 2; ++i, ++j)
|^^^^^^^| -------- variable modification
| | |^^^^^^^^^^^^^^^^^| ---------------- loop condition
|^^^^^^^^^^^^^^^|--------------------------------------- initialization
What you seem to want is something like:
for (int i = 0, j = n; i < n && j < n * 2; ++i, ++j)
{
continue;
}
To help you better understand what I did and why, and how you can do such transformations in the future, you need to understand how a for loop is really handled by the compiler: As a special while loop.
For example, if you have
for (a; b; c)
{
d;
}
then that's equivalent to this:
{
a;
while (b)
{
d;
c;
}
}
If we take what you (probably) want, in the form of a while loop then it would be
{
int i = 0, j = n; // a in my example above
while (i < n && j < n * 2) // b in my example above
{
continue; // d in my example above
++i, ++j; // c in my example above
}
}
Now it's easy to translate it to the for loop I showed initially.
As noted in a comment, the while loop shown here is a little misleading, as it won't actually do the increment. But then I assume your real loop doesn't have an unconditional continue statement as the only statement in the body. That would make the loop rather meaningless. However the principle is still valid, even if the example isn't.
for(int i=0 ; i<n ; i++ , j=n ; j<n*2 ; j++){
continue;
}
The above code is wrong
but it can be written as
for(int i = 0 ,j = n; i < n ,j < n * 2; i++ ,j++)
The above code is correct
i=0 and j=n is initialization
i<n and j<n*2 is loop condition
i++ and j++ is incrementation

User Input/If Statement keeping returning instead of continuing [duplicate]

Which statement will be executed after "continue" or "break" ?
for(int i = 0; i < count; ++i)
{
// statement1
for(int j = 0; j < count; ++j)
{
//statement2
if(someTest)
continue;
}
//statement3
}
for(int i = 0; i < count; ++i)
{
// statement1
for(int j = 0; j < count; ++j)
{
//statement2
if(someTest)
break;
}
//statement3
}
continue: ++j and then if j < count then statement2 otherwise statement3
break: statement3
Continue jumps straight to the top of the innermost loop, where the per-iteration code and continuance check will be carried out (sections 3 and 2 of the for loop).
Break jumps straight to immediately after the innermost loop without changing anything.
It may be easier to think of the former jumping to the closing brace of the innermost loop while the latter jumps just beyond it.
continue ends the current iteration, virtually it is the same as:
for(int i = 0; i < count; ++i)
{
// statement1
for(int j = 0; j < count; ++j)
{
//statement2
if(someTest)
goto end_of_loop;
end_of_loop:
}
//statement3
}
break exits the loop:
for(int i = 0; i < count; ++i)
{
// statement1
for(int j = 0; j < count; ++j)
{
//statement2
if(someTest)
goto after_loop;
}
after_loop:
//statement3
}
statement2 will execute after the continue, given that the loop was not in the last iteration.
statement3 will execute after the break.
'continue' (as the name suggests) continues the loop, while skipping the rest of the statements in the current iteration.
'break' breaks and exits from the loop.
Continue: It depends. The continue statement will execute the 'increment' part of the for-loop, then the 'test' part, and then decide whether to execute the next iteration or leave the loop.
So it could be statement 2 or 3.
Break: statement 3.
Btw, is this homework?
For continue, innerloop is executed with new i,j values of i,j+1
For break, innerloop is executed with new i,j values of i+1,0
ofcourse if boundary conditions are satisfied

C++ Tetris: A function that deletes lines

I've been studying this tetris tutorial and I've come across the function that deletes lines and brings the row/s down one level. I'm kind of understanding what is going on with these functions, but some parts are confusing me. I'll try and explain it best I can, but here is the link to the lesson if you need it: http://javilop.com/gamedev/tetris-tutorial-in-c-platform-independent-focused-in-game-logic-for-beginners/
This, to me, looks like a function to get the array to start at the last number of a line:
void Board::DeleteLine (int pY)
{
// Moves all the upper lines one row down
for (int j = pY; j > 0; j--)
{
for (int i = 0; i < BOARD_WIDTH; i++)
{
mBoard[i][j] = mBoard[i][j-1];
}
}
}
Then, there is the function that is causing me problems, which I will explain:
void Board::DeletePossibleLines ()
{
for (int j = 0; j < 20; j++)
{
int i = 0;
while (i < 10)
{
if (mBoard[i][j] != 1) break;
i++;
}
if (i == 10) DeleteLine (j);
}
}
In case you're not familiar, the idea here is to delete a row that consists entirely of 1. But if (mBoard[i][j] != 1) break; would stop the loop if the first line wasn't 1. How would the loop reach a 1 that is somewhere in the middle of the mBoard[][] array if break stops it from doing anything possible straight away?
Am I missing something here? This is my interpretation of it. Perhaps somebody sees something I do't?
Edit:
Thanks for the replies, appreciated.
You could structure the code like this aswell:
for (int j = 0; j < 20; j++)
{
int i = 0;
while (i < 10)
{
if (mBoard[i][j] != 1)
{
break; //only breaks the while loop and will continue with if (i == 10)
}
else
{
i++;
}
}
if (i == 10)
{
DeleteLine (j);
}
}
Now you can clearly see, that the break; is only interrupting your while loop but not your for loop.
The break will jump out of the while loop. So if you encounter a line which has a non-1 somewhere in the middle, i will be the index in the line, and the for loop will continue with the next line (j), starting with i=0 again.
break only interrupts one loop, the while loop in your case. The for loop continues happily.
On a side note, this while could easily (and should) be refactored into a for, and can be compacted according to its recognizable for-if-break pattern :
for (int j = 0; j < 20; ++j)
{
int i;
for(i = 0; i < 10 && mBoard[i][j] == 1; ++i);
if (i == 10) DeleteLine (j);
}

How to stop a nested for loop

I want both loops to stop as soon as I find an object that has the same position in x.
Here is my C++ code:
for(int i = 0; i < sizeArray; ++i){
for(int j = i; j > 0; --j){
if (s[i].positionX == s[j-1].positionX){
s[i].positionY = s[j-1].positionY;
}
}
}
If I use break; it only breaks out of the inner for loop. What is the best way to stop both?
Options:
Set the indexes of the loops to max value (or min value) to terminate the loop.
Put all this inside a function and use return.
Use a goto
Use a Lambda
Set a boolean stop code to true, break, then listen for break and break out of other loop?
?
To break out of the innermost for loop, use break.
To break out of the outermost one, either use goto or use a combination of break and a "should stop" flag.
I would suggest lambda:
auto do_work = [&] {
for(int i = 0; i < sizeArray; ++i){
for(int j = i; j > 0; --j){
if (s[i].positionX == s[i-1].positionX){
s[i].positionY = s[i-1].positionY;
return;
}
}
}
};
do_work(); //you can call this multiple times if you need to!
No break, no goto. :-)
It serves the same purpose as break and goto in this case, but the technique seems to be clean, at least to me. Also, once you have the lambda with a name (a good name), you can use it multiple times if you need to — so this technique increases the code readability and encourages code-reuse.
Of course, if you don't need to call this multiple times, then probably you don't need a name. You just could do this:
[&]
{
//your code with the added return statement.
}();
But as I said, name increases readability even if you don't call it multiple times.
If you cannot use lambda for some reason, then you could still avoid using an extra variable such as stop and the extra work involving it (as #ssantos's answer suggested):
for(int i = 0; i < sizeArray; ++i){
for(int j = i; j > 0; --j){
if (s[i].positionX == s[i-1].positionX){
s[i].positionY = s[i-1].positionY;
i = sizeArray; //it will break the outer loop!
break;
}
}
}
Hope that helps.
I'm guessing you ask for stopping a for loop. The keyword you're looking for is break. However, if you want to exit both for loops, you'll need to add a variable to your code.-
bool stop = false;
for(int i = 0; i < sizeArray; ++i){
for(int j = i; j > 0; --j){
if (s[i].positionX == s[i-1].positionX){
s[i].positionY = s[i-1].positionY;
stop = true;
break;
}
}
if (stop) {
break;
}
}
Put the code you posted in its own function and return out of it after the assignment.
You can stop a for loop with break.
With nested for loops, things are not so easy. You can achieve your goal
either with setting a flag (done = 1; and use it with for(int j = i; j > 0 && !done; --j))
or with goto. Although goto is frowned upon by some people, it can, if used correctly and with care, be a legitimate solution for some problems, such as error handling, or in general, "finished handling".
Try the following
bool match = false;
for(int i = 0; i < sizeArray && !match; ++i){
for(int j = i; j > 0 && !match; --j){
if ( match = ( s[i].positionX == s[i-1].positionX ) ){
s[i].positionY = s[i-1].positionY;
}
}
}
Another way is the following
for(int i = 0; i < sizeArray; ++i){
int j = i;
while ( j != 0 && s[i].positionX != s[i-1].positionX ) --j;
if ( j != 0 ) {
s[i].positionY = s[i-1].positionY;
break;
}
}

What does it mean when the first "for" parameter is blank?

I have been looking through some code and I have seen several examples where the first element of a for cycle is omitted.
An example:
for ( ; hole*2 <= currentSize; hole = child)
What does this mean?
Thanks.
It just means that the user chose not to set a variable to their own starting value.
for(int i = 0; i < x; i++)
is equivalent to...
int i = 0;
for( ; i < x; i++)
EDIT (in response to comments): These aren't exactly equivalent. the scope of the variable i is different.
Sometimes the latter is used to break up the code. You can also drop out the third statement if your indexing variable is modified within the for loop itself...
int i = 0;
for(; i < x;)
{
...
i++
...
}
And if you drop out the second statement then you have an infinite loop.
for(;;)
{
runs indefinitely
}
The for construct is basically ( pre-loop initialisation; loop termination test; end of loop iteration), so this just means there is no initialisation of anything in this for loop.
You could refactor any for loop thusly:
pre-loop initialisation
while (loop termination test) {
...
end of loop iteration
}
Some people have been getting it wrong so I just wanted to clear it up.
int i = 0;
for (; i < 10; i++)
is not the same as
for (int i = 0; i < 10; i++)
Variables declared inside the for keyword are only valid in that scope.
To put it simply.
Valid ("i" was declared outside of the loops scope)
int i = 0;
for (; i < 10; i++)
{
//Code
}
std::cout << i;
InValid ("i" does not exist outside the loop scope)
for (int i = 0; i < 10; i++)
{
//Code
}
std::cout << i;
It means that the initial value of hole was set before we got to the loop
That means loop control variable is initialized before the for loop .
For C code,
int i=0;
for( ; i <10 ; i++) { } //since it does not allow variable declaration in loop
For C++ code,
for(int i=0 ; i <10 ; i++) { }
You could omit any of the parameters of a for loop.
ie: for(;;) {} is about the same as while(true) {}
It means that the initial value of hole was set before we got to the loop.
Looks like a list traversal of some kind.
Suppose you wanted to
for (hole=1 ; hole*2 <= currentSize; hole = child)
But the value of hole just before the for loop was already 1, then you can slip this initilization part of the loop:
/* value of hole now is 1.*/
for ( ; hole*2 <= currentSize; hole = child)