Standard idiom for executing a while loop one more time
Asked Answered
U

5

8

Is there a pattern in C to execute a while loop one more time. Currently I'm using

while(condition) {
    condition = process();
    // process() could be multiple lines instead of a function call
    // so while(process());process(); is not an option
}
process();

which is horrible if process is of multiple lines and not a single function call.

The alternative is

bool run_once_more = 1;
while(condition || run_once_more) {
    if (!condition) {
        run_once_more = 0;
    }
    condition = process();
    condition = condition && run_once_more;
}

Is there a better way?


Note: A do while loop is not a solution as it is equivalent to

process();
while(condition){condition=process();}

I want

while(condition){condition=process();}
process();

Per requests, a bit more specific code. I want to fill buffer from another_buffer and get (indexof(next_set_bit) + 1) into MSB while maintaining both masks and pointers.

uint16t buffer;
...
while((buffer & (1 << (8*sizeof(buffer) - 1))) == 0) { // get msb as 1
    buffer <<= 1;
    // fill LSB from another buffer
    buffer |= (uint16_t) (other_buffer[i] & other_buffer_mask);
    // maintain other_buffer pointers and masks
    other_buffer_mask >>= 1;
    if(!(other_buffer_mask)) { 
        other_buffer_mask = (1 << 8*sizeof(other_buffer[0]) -1)
        ++i;
    }
}
// Throw away the set MSB
buffer <<= 1;
buffer |= (uint16_t) (other_buffer[i] & other_buffer_mask);
other_buffer_mask >>= 1;
if(!(other_buffer_mask)) { 
    other_buffer_mask = (1 << 8*sizeof(other_buffer[0]) -1)
    ++i;
}
use_this_buffer(buffer);
Unlive answered 6/4, 2015 at 16:25 Comment(6)
process is of multiple lines and not a single function call Then make it (possibly inline) function call.Microbalance
A do ... while (condition); can also provide an additional iteration in some cases.Epileptoid
@chux It would be ok if condition was modified in the last call as well. Still, the do while loop would NOT make an additional iteration after the condition is false. see my note.Unlive
Can you tell use more about condition? Is it something numeric or what?Angio
@black added more info.Unlive
BTW, rather than 1 << (8*sizeof(buffer) - 1), use 1u << (8*sizeof buffer - 1) (add u). or even better 1u << (CHAR_BIT * sizeof buffer - 1).Cuttlebone
H
3

Because it's not a very typical thing to do, it's unlikely that there is a standard idiom for doing this. However, I'd write the code like this:

for (bool last = 0; condition || last; last = !(condition || last)) {
    condition = process();
}

The loop will execute as long as condition is true and then one more time, or zero times if condition is false when the loop begins. I interpret your question as meaning that that is the desired behavior. If not, and you always want the loop to execute at least once, then do...while is the idiom you seek.

Harless answered 6/4, 2015 at 18:54 Comment(1)
++0, This feels like the most elegant solution so far.Unlive
T
1

What about this:

int done, condition = 1;
for (;;) {
    ...
    done = !condition;
    condition = process();
    if (done) break;
    ...
}

I am not suggesting this is a standard idiom, just an ad hoc hack.

Transubstantiate answered 6/4, 2015 at 17:3 Comment(0)
A
0

I'd use this:

bool done = false;
do {
  if (!condition) done = true;
  condition = process();
} while (!done);

A much less readable hack, assuming condition is not predefined:

for (bool condition=true, done=false;
     !done && (condition || done = true);
    ) {
  condition = process();
}
Amado answered 6/4, 2015 at 17:4 Comment(2)
condition must be defined as something non 0 and there is a missing semicolon after the end of the do/while condition.Transubstantiate
@chqrlie: In the OP, condition is pre-existing. I assumed it came from some previous computation. If that is not the case, then it would have to defined, yes.Amado
H
0

I've had this same issue and my solution is:

Only if you know for sure you want to run process() at least once:

while(1){
    process();
    if(!condition()) break;
    /*The loop breaks before bad things happen*/
    things_you_want_to_happen_only_while_condition_is_true();
}

If you are not sure:

if(condition()){ /*Same as before, but it checks first*/
    while(1){
        process();
        if(!condition()) break;
        /*The loop breaks before bad things happen*/
        things_you_want_to_happen_only_while_condition_is_true();
    }
}

For example:

/*A pointer that goes over the string T from right to left.
It prints "Yes" when pointing at the character 'O' and "No" when not*/
char T[] = {'O', 'V', 'E', 'R', 'F', 'L', 'O', 'W', 0};
char *P = &T[strlen(T)-1]; /*We want the pointer to start at the last character of T*/
while(1){
    if(*P=='O') printf("Yes\n");
    else printf("No\n");
    if(P==&T[0]) break; /*When it reaches the beginning of T, it stops*/
    /*We only want the pointer to go further back if it is not in the beginning of T.
    That's because we don't know what's before in the memory.*/
    P--;
}
Hydrotherapy answered 21/10, 2018 at 6:41 Comment(0)
C
0

Your code is way more advanced than my level, but I came to this question as I had a similar difficulty on a problem set (I wanted the function to execute one last time) and I solved it like this:

define check_value as type_required;

while (check_value)
{
    check_value = additional_output_from_process;
    condition = process();
}

Would something like that work? In my problem I'm just taking a modulus so I can just run the process twice, system overhead really isn't a consideration.

This works in my example but it might just be a specific use case? I don't know, I'm literally only 6 months into coding.

I think what I'm trying to say is: introduce an additional value, and set the logical test so that the function output (operation) additional value = true. Then set the value of the additional value before you evalutate the function. The result function output (operation) additional value then will only be set to true after the loop has already run again.

Cindy answered 8/1, 2023 at 13:26 Comment(3)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Belonging
I don't see how this solves OP's problem. OP wants the loop to continue until process() returns false then execute process() one more timeSivas
I get that - I'm trying to not post part of a homework answer online so that it's really obvious.Cindy

© 2022 - 2024 — McMap. All rights reserved.