Two-iteration loop

  • Thread starter Christopher Benson-Manica
  • Start date
C

Christopher Benson-Manica

I have a situation something like this:

int foo;

for( foo=bar() ; foo <= bar()+1 ; foo++ ) {
if( !baz(foo) ) break;
/* do stuff with foo */
}

The idea is that the loop happens at most twice - once for foo=bar(), and once
for foo=bar()+1. If baz(foo) fails, I know I can stop. However, I don't
think this is the "elegant" way to get this behavior - there is a break (which
might be bad style, for some), and bar() may be called three times (which
doesn't seem optimal). I thought of

int foo=bar();

do {
if( !baz(foo) ) break;
/* doo stuff with foo */
} while( foo++ == bar() );

, but it's no better (and is somewhat more obfuscated, to boot). Any
thoughts?
 
D

Dave Vandervies

I have a situation something like this:

int foo;

for( foo=bar() ; foo <= bar()+1 ; foo++ ) {
if( !baz(foo) ) break;
/* do stuff with foo */
}

The idea is that the loop happens at most twice - once for foo=bar(), and once
for foo=bar()+1. If baz(foo) fails, I know I can stop. However, I don't
think this is the "elegant" way to get this behavior - there is a break (which
might be bad style, for some), and bar() may be called three times (which
doesn't seem optimal). I thought of

int foo=bar();

do {
if( !baz(foo) ) break;
/* doo stuff with foo */
} while( foo++ == bar() );

, but it's no better (and is somewhat more obfuscated, to boot). Any
thoughts?

How long is the chunk that "/*do stuff with foo*/" expands to?

If it's not too long, something like this might be a little bit cleaner
(for one thing, it makes it clear that it's a "do something again unless
baz() fails" and not a "loop until some condition is met"), though it's
not without its problems:
--------
foo=bar();
/*do stuff with foo*/
foo++;
if(baz(foo))
{
/*Note that this stuff is the same stuff we did above. If baz
returns nonzero we have to do it again.
*/
/*do stuff with foo*/
}
--------

Depending on how closely what you're doing with foo is tied to the rest
of the code there, it might be worth moving it to another function:
--------
foo=bar();
do_stuff_with(foo);
foo++;
if(baz(foo))
do_stuff_with(foo); /*again*/
--------


dave

--
Dave Vandervies (e-mail address removed)
You can quit emacs?
Yes, and after 12 weeks of rehab, you might even stay off the stuff.
--James Riden and Greg Andrews in the scary devil monastery
 
I

Ian Woods

I have a situation something like this:

int foo;

for( foo=bar() ; foo <= bar()+1 ; foo++ ) {
if( !baz(foo) ) break;
/* do stuff with foo */
}

The idea is that the loop happens at most twice - once for foo=bar(),
and once for foo=bar()+1. If baz(foo) fails, I know I can stop.
However, I don't think this is the "elegant" way to get this behavior
- there is a break (which might be bad style, for some), and bar() may
be called three times (which doesn't seem optimal). I thought of

int foo=bar();

do {
if( !baz(foo) ) break;
/* doo stuff with foo */
} while( foo++ == bar() );

, but it's no better (and is somewhat more obfuscated, to boot). Any
thoughts?

If the value returned by bar() is loop invarient, assign it to a
variable. If bar() is an expensive (but invarient) computation this will
be a nice gain, and performing a single unnecessary check is at no cost.

You might do this:

int foo, startpos;

startpos=bar();
for (foo=startpos;foo<startpos+2 && !baz(foo);foo++) {
/* do stuff */
}

if you don't like the break. Personally, I don't mind "if (cond) break;"
especially at the beginning of loops.

If bar() isn't loop invarient and expensive, then you can still do it
nicely. something like:

int foo;
for (foo=0;foo<2;foo++) {

int barval=bar()+foo;
if (!baz(barval)) break;

/* do stuff */
}

If bar() isn't expensive and loop invarient, it doesn't really matter if
it's invoked a third.

Ian Woods
 
E

Ed Morton

I have a situation something like this:

int foo;

for( foo=bar() ; foo <= bar()+1 ; foo++ ) {
if( !baz(foo) ) break;
/* do stuff with foo */
}

The idea is that the loop happens at most twice - once for foo=bar(), and once
for foo=bar()+1. If baz(foo) fails, I know I can stop. However, I don't
think this is the "elegant" way to get this behavior - there is a break (which
might be bad style, for some), and bar() may be called three times (which
doesn't seem optimal). I thought of

int foo=bar();

do {
if( !baz(foo) ) break;
/* doo stuff with foo */
} while( foo++ == bar() );

, but it's no better (and is somewhat more obfuscated, to boot). Any
thoughts?

If the value returned from bar() never changes, then of course you'd assign that
to a variable outside of the loop:

int foo;
int fooMin = bar();
int fooMax = fooMin + 1;

for( foo=fooMin ; foo <= fooMax ; foo++ ) {
if( !baz(foo) ) break;
/* do stuff with foo */
}

Instead of breaking out of the loop if baz() fails, the obvious change would be
to only do the work if baz() succeeds, e.g.:

int foo;
int fooMin = bar();
int fooMax = fooMin + 1;

for( foo=fooMin ; foo <= fooMax ; foo++ ) {
if( baz(foo) ) {
/* do stuff with foo */
}
}

or even:

int foo;
int fooMin = bar();
int fooMax = fooMin + 1;

for( foo=fooMin ; (foo <= fooMax) && baz(foo) ; foo++ ) {
/* do stuff with foo */
}

If the condition becomes complex, write a macro:

#define ISVALID(foo) ((foo) <= fooMax ? baz((foo)) : 0)

int foo;
int fooMin = bar();
int fooMax = fooMin + 1;

for( foo=fooMin ; ISVALID(foo) ; foo++ ) {
/* do stuff with foo */
}

Now, if bar() doesn't always return the same value, we can easily modify the
above to:

#define ISVALID(foo) ((foo) <= bar() + 1 ? baz((foo)) : 0)

int foo;

for( foo=bar() ; ISVALID(foo) ; foo++ ) {
/* do stuff with foo */
}

Regards,

Ed.
 
B

Ben Pfaff

Christopher Benson-Manica said:
int foo;

for( foo=bar() ; foo <= bar()+1 ; foo++ ) {
if( !baz(foo) ) break;
/* do stuff with foo */
}

The idea is that the loop happens at most twice - once for foo=bar(), and once
for foo=bar()+1. If baz(foo) fails, I know I can stop. However, I don't
think this is the "elegant" way to get this behavior - there is a break (which
might be bad style, for some), and bar() may be called three times (which
doesn't seem optimal).

If I understand the situation correctly, try this:

for (foo = bar(); baz(foo) && foo <= bar() + 1; foo++) {
/* do stuff with foo */
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top