简体   繁体   中英

Refactoring with the ternary operator in C

I've made a function that checks the bounds of an array. Why isn't my second solution performing the same task as my first solution? Is this a matter of precedence, or improper usage of the ternary?

workaround #1:

bool check_bounds(double* score, int size)
{
    bool result=false;
    for(int i=0; i<size; i++)
    {
        if(score[i] < 0.0 || score[i] > 100.0) 
        {
            result=true;
        }
    }
    return result;
}

// usage
if(check_bounds(score, size) { i--; }

workaround #2:

bool check_bounds(double* score, int size)
{
    bool is_valid;
    for(int i=0; i<size; i++)
    {
        is_valid = (score[i] < 0.0 || score[i] > 100.0) ? true : false;
    }

    return is_valid;
}

Your second workaround is failing because on each iteration of the for loop, is_valid is assigned based on score[i] . This essentially causes the entire function to return score[size - 1] < 0 || score[size - 1] > 100 score[size - 1] < 0 || score[size - 1] > 100 .

A ternary operator isn't really appropriate here, since it will always be evaluated, and assign a new value to is_valid . The first version could be rewritten like this to demonstrate what it's actually doing:

bool check_bounds(double*score, int size)
{
    bool is_valid = false;
    for(int i=0; i<size; i++)
    {
        if (score[i] < 0.0 || score[i] > 100.0)
        {
            is_valid = true;
        }
    }
    return is_valid;
}

Your first example breaks away early:

for(int i=0; i<size; i++)   // loop until i = size
{
    if(score[i] < 0.0 || score[i] > 100.0) 
    {
        return true;   // but if we hit this condition, we leave now!
    }
}

Your second example only sets the variable in the if check:

for(int i=0; i<size; i++) // loop until i = size regardless
{
    is_valid = (score[i] < 0.0 || score[i] > 100.0) ? true : false;
}

return is_valid; // return whatever was last set.

The second version runs through the entire range of score[0] through score[size - 1] and then returns the last value of the test, while the first version exits the loop early if any member of the score array is out of bounds. You need to add a test of is_valid somewhere inside the second version's for loop.

Since you have to test is_valid to determine whether to return early or not anyway, IMHO you gain absolutely nothing from using the ternary operator here (neither increased readability, nor more concise code).

The second version (when corrected to return early) is probably going to be optimized by the compiler into virtually the same machine code as the first, so you gain nothing in terms of performance either.

In terms of style, I like the first version better, but that's a matter of personal preference. Some people (and managers!) think there should be only one return statement in any given function. If you're trying to stick to that standard, then here's another possible refactoring:

bool check_bounds(double* score, int size)
{
    bool is_valid;
    for (int i=0; i<size; i++)
    {
        is_valid = (score[i] < 0.0 || score[i] > 100.0) ? true : false;
        if (!is_valid)
            break;
    }

    return is_valid;
}

Workaround #1 returns true if the condition is satisfied on any iteration, and false if it's never satisfied. Workaround #2 repeatedly switches between true and false on every iteration, and returns whether the condition is satisfied on the last iteration, which is definitely not what you want. To get the functionality of #1, you can't really use the ternary conditional.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM