Continue in a do while loop

142 Views Asked by At

I have a do-while loop designed to get a number from user input in the console. I included error checking and many optional variables to make it versatile (i.e. min and max allowed values, an array of values that must contain the input, and a params variable for any specific not allowed input values).

After redesigning the loop to use some continue statements (based on design constraints), the error checking no longer seems to be working.

public static int GetNumber(int min = int.MinValue, int max = int.MaxValue, string prompt = "Number", int[] permittedNums = null, params int[] exceptions)
{
    string? numString;
    int num;
    do
    {
        Console.Write($"{prompt}: ");
        numString = Console.ReadLine();
        ClearConsoleLine();
        if (!int.TryParse(numString, out num)) { continue; }
        if (permittedNums != null && !permittedNums.Contains(num)) { continue; }
    } while (num < min || num > max || exceptions.Contains(num));
    return num;
}

I checked to make sure that my logic was correct to make sure that at least the continue statement was hit, and as far as I could tell it should have worked, but it was allowing the input to go through without running the loop again.

I already tried looking at other questions but I couldn't find an answer.

3

There are 3 best solutions below

0
Iłya Bursov On BEST ANSWER

continue actually is simple goto, and in loops it works like this:

do {
    ...
    continue;
    ...
} while (condition)

is equivalent to:

do {
    ...
    goto LABEL;
    ...
    LABEL:
} while (condition)

so, even after continue condition is still evaluated (or in case of for loop - counter is increased and so on).

you have multiple options, for example you can put all your continuation conditions in while's condition (it works because of short circuit evaluation):

do
{
    Console.Write($"{prompt}: ");
    numString = Console.ReadLine();
} while (
    !int.TryParse(numString, out num) ||
    (permittedNums != null && !permittedNums.Contains(num)) ||
    num < min ||
    num > max ||
    exceptions.Contains(num)
    );

return num;

but it is hard to read and modify, I'd prefer to see something like this:

while (true)
{
    Console.Write($"{prompt}: ");
    var numString = Console.ReadLine();

    int num;
    if (!int.TryParse(numString, out num)) { continue; }
    if (permittedNums != null && !permittedNums.Contains(num)) { continue; }
    if (num < min || num > max || exceptions.Contains(num)) { continue; }

    return num;
}

so, every time you have failed check - you skip return and start loop from the beginning

1
teamol On

you didn't provide detailed inputs, but this condition, iirc, wants to loop until user enters a legal number:

while (num < min || num > max || exceptions.Contains(num));

Let's say a simple example case, all parameters default, empty collection for exceptions. Once prompt starts, user enters any non-nubmer text, and TryParse fails. Note that num would be 0 on fail. continue gets called. Loop checks condition. Because Int32.MinValue < 0 < Int32.MaxValue, no condition will be met and the loop ends, thus causing the illusion of loop not working properly. That's the catch of TryParses actually, you need to consider about the bool returned by it instead of using num to check.

I suggest you write down a list of different inputs first, and think what result each of these inputs should produce, then you'll come up with the logic more clearly.

0
Lajos Arpad On

continue jumps to the next iteration of the loop, but the condition is still checked. Therefore use a boolean value to see whether it makes sense to even est for the end-sign of the loop:

public static int GetNumber(int min = int.MinValue, int max = int.MaxValue, string prompt = "Number", int[] permittedNums = null, params int[] exceptions)
{
    string? numString;
    int num;
    bool ended;
    do
    {
        ended = false;
        Console.Write($"{prompt}: ");
        numString = Console.ReadLine();
        ClearConsoleLine();
        if (!int.TryParse(numString, out num)) { continue; }
        if (permittedNums != null && !permittedNums.Contains(num)) { continue; }
        ended = true;
    } while ((!ended) || (num < min || num > max || exceptions.Contains(num)));
    return num;
}