Two-iteration loop

Discussion in 'C Programming' started by Christopher Benson-Manica, Nov 10, 2003.

  1. 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?

    --
    Christopher Benson-Manica | I *should* know what I'm talking about - if I
    ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
     
    Christopher Benson-Manica, Nov 10, 2003
    #1
    1. Advertising

  2. In article <boodf0$sta$>,
    Christopher Benson-Manica <> wrote:
    >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
    >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
     
    Dave Vandervies, Nov 10, 2003
    #2
    1. Advertising

  3. Christopher Benson-Manica

    Ian Woods Guest

    Christopher Benson-Manica <> wrote in
    news:boodf0$sta$:

    > 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
     
    Ian Woods, Nov 10, 2003
    #3
  4. Christopher Benson-Manica

    Ed Morton Guest

    On 11/10/2003 10:13 AM, Christopher Benson-Manica wrote:
    > 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.
     
    Ed Morton, Nov 10, 2003
    #4
  5. Christopher Benson-Manica

    Ben Pfaff Guest

    Christopher Benson-Manica <> writes:

    > 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 */
    }
    --
    int main(void){char p[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.\
    \n",*q="kl BIcNBFr.NKEzjwCIxNJC";int i=sizeof p/2;char *strchr();int putchar(\
    );while(*q){i+=strchr(p,*q++)-p;if(i>=(int)sizeof p)i-=sizeof p-1;putchar(p\
    );}return 0;}
     
    Ben Pfaff, Nov 10, 2003
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. dwerdna
    Replies:
    5
    Views:
    5,609
    Ajeetha
    Mar 31, 2005
  2. Danny Anderson

    open new file each loop iteration

    Danny Anderson, Jan 21, 2004, in forum: C++
    Replies:
    0
    Views:
    444
    Danny Anderson
    Jan 21, 2004
  3. Rudi
    Replies:
    5
    Views:
    5,120
  4. Nene
    Replies:
    6
    Views:
    355
    John W. Krahn
    Dec 13, 2008
  5. Isaac Won
    Replies:
    9
    Views:
    397
    Ulrich Eckhardt
    Mar 4, 2013
Loading...

Share This Page