tags:

views:

648

answers:

14

[EDIT]Whoops there was a mistake in the code, and now all the responses to the question seem bizzare, but basically the for loop used to be, for(i=0; i<15; i++). I also edited to make the question more clear.[/EDIT]

I am trying to make a for loop, that checks a 16 element array, so it loops from 0 to 15. I then use the i variable later, however sometimes i == 16, which causes problems by being out of bounds.

I have a solution but it doesnt seem elegant, which makes me think I am missing something. I've tried while loops, but I can never get any loop to go from 0 to 15, and never end at a value greater than 15.

Is there any way to make a loop go and check all 16 elements of the array, while never being greater than 15 at the end of the loop?

int i;

for(i=0; i<16; i++)
{
    someClass.someMethod(i);

    if(someClass.Test())
    {
     break;
    }
}



if (i == 16)
{
    i = 15;
}
+3  A: 

Well for starters, your sample code loops from 0 to 14. But if you loop from 0 to 15, naturally i has to be 16 before the loop can end. What happens is it becomes 16, THEN your loop notices it's out of bounds and breaks out. If you want it to end at 15, honestly the easiest thing to do is just decrement just after the loop end.

Promit
Ahh the code was supposed to be (i=0; i<16; i++), was testing just before I posted.
LearningFast
A: 

You must have missed something.

In this loop it wouldn't even hit 15, you'd need to say i <= 15, as soon as i = 14 it'd run once and bail.

Joshua Belden
+3  A: 

i is incremented on last check to be 16, which is not less than 15, so loop exits with i being 16.

+6  A: 

I suggest using some other variable other than i after your loop is finished. The criteria of using a for loop instead of a while loop is that you know beforehand exactly how many times a for loop will execute. If you already know this, just set some other variable to the ending value of your loop and use it instead of giving i a dual purpose.

int j = 15;

for(int i=0; i <= j; i++)
{
    someClass.array[i];
}

// continue on using j, which value hasn't changed
Bill the Lizard
The second part of this answer is the real advice that you should take from the question, which is don't reuse an variable from a for loop unless you have a really good reason.
Andrew Cox
Edited to match the question edits.
Bill the Lizard
I understand your code is for demo purposes, and you are using the numerical values from the original question. To point out the obvious, I'm sure we would all initialize j to someClass.array.length-1 in real life.
digitaljoel
@stackoverdose: Yes, that's a good point to make. You'd initialize j based on whatever makes sense for the purpose of the loop. In this case the array.length-1 is the right choice.
Bill the Lizard
+1  A: 

So - if you're checking a 16 element array, normally you'd do this:

for(i=0; i<16; i++)

How for works, is it starts with the first statement of three:

i=0

Then it does your check, in the second statement:

i < 16 // True here, since 0 < 16

That happens before your loop. Then it runs the block of your loop with that set:

someClass.array[i]; //0

Finally, it does the final statement:

i++

Then it repeats the second and third statements, in a sequence.

Before the last run, i == 14, then it does i++, setting i to 15, and executes the block. Finally, it does i++, setting:

i==16

At this point, the condition is no longer true:

i < 16 // False, since i==16

At this point, your block does not execute, but i is still set to 16.

Reed Copsey
A: 

The for loop is equivalent to the following while loop:

i = 0;
while(i < 16) {
 someClass.array[i];

 i++;
} // while

i needs to reach 16 to get out of the loop correctly.

eed3si9n
+3  A: 

Maybe it's useful to know that:

for (before; check; after) { body }

it's the same as:

before 
while(check) { 
  body 
  after 
}

If you think at your for loop in that term, maybe you'll find out easily why i, at the exit, is 16.

akappa
A: 

Technically there are ways of writing the loop such that i is 15 on exiting the loop, but you shouldn't do them:

int i = 0;
while (1) {
    someclass.someMethod(i);
    if (i < 15) {
        i++;
    } else {
        break;
    }
}

Yes, it does what you ask. But the flow is horrible.

Alnitak
A: 

You cannot accomplish this with the built-in loop structures, and as Bill The Lizard said, you probably don't really want to reuse the for-loop variable.

But, if you really want to, here's a way to do it. The trick is to put the loop condition in the middle of the loop:

int i = 0;
while (true)
{
    someclass.array[i];
    if (i == 15)
        break;
    ++i;
}
tarmin
A: 

The key issue to understand here is that there are 17 different answers to the question "What value of i causes the test to succeed?". Either i can be in {0, 1, ..., 15}, or no value of i causes the test to succeed, which is denoted by i == 16 in this case. So if i is restricted to only 16 values, the question cannot be answered.

There are legitimate cases where you do not want to go past the last valid value. For instance, if you had 256 values and for some reason you only have one byte to count with. Or, as happened to me recently, you want to examine only every ith element of an array, and the last addition to your iterator takes you far beyond the end of the array. In these cases loop unrolling is necessary.

However, for this problem it would be cleaner to use a flag:

bool flag = false;
for (int i = 0; i < 15; ++i) 
{
    someClass.someMethod(i);

    if (someClass.Test())
    {
        flag = true;
        break;
    }
}

Then it's clear whether or not the test ever succeeded.

Mark Ruzon
A: 

If your loop terminates natuarally, rather than with a break, i will be 16. There's no way to avoid this. Your code is perfectly acceptable if what you want is for i to end up as 15 or less:

int i;
for (i=0; i<16; i++) {
    someClass.someMethod(i);
    if (someClass.Test())
        break;
}
if (i == 16)
    i = 15;

Anything that changes i from 16 to 15 after the loop body will do:

if (i == 16) i = 15;
i = (i == 16) ? 15 : i;
i = MAX (15,i); /* where MAX is defined :-) */

and so on.

However that assumes that i is going to be used for something meaningful as a post-condition with respect to that loop. I find that's rarely the case, people tend to re-initialize it before re-use (such as another for loop).

In addition, what you are doing makes it very difficult (impossible, even) to figure out as a post-condition, wheteher your loop terminated normally or whether it terminated prematurely because someClass.Test() returned true for i == 15. This means using i to make further decision is fraught with danger.

My question would be: Why do you think you need to leave i as 15 or less?

paxdiablo
A: 

I am trying to make a for loop, that checks a 16 element array, so it loops from 0 to 15. I then use the i variable later, however sometimes i == 16, which causes problems by being out of bounds.

You need to check for the case where your for loop didn't break, because this information determines whether or not whatever you wanted to do with i is valid.

There are a couple of ways to do this. One is to keep track of it in a bool, such as "foundClass" or "testSucceeded". Default it to false, then set it to true on your break. Enclose any uses of i later in the function in "if (foundClass) { }" blocks.

Another is to just do what you've done. Although your fallback doesn't look right at all. If you're setting i to 15, you're lying to your code and telling it that someClass.Test() succeeded for i == 15, which isn't true. Avoid setting the value to something that's wrong just so your code doesn't error later on. It's much better to put bounds checks around the actual usage of i later in the code.

Dan Olson
+3  A: 

There seems to be some fundamental flaws in your approach.

  1. You shouldn't really use an index variable outside the scope of the loop.
  2. You should use a variable or function to determine the limit of the loop.
  3. It would be better to use iterators instead of numeric indexes.
  4. Generic algorithms can remove the need for loops.

Just my $0.02.

chrish
A: 
for(int i=0; i<17; i++)
{    
  if(i<16)
  {
     someClass.someMethod(i); 
     if(someClass.Test())   
     {        
       break;    
     }
  }
  else if(i==16)
  {
     i=15;
  }
}
xoxo