-2

Hello I'm currently doing a programming exercice and there is something I want to be sure about.

It is about the if statement negation like so : if(!(condition)), what's the difference between the if statement with negation and not ? Here an example of a program that has give me the result i want with if(!(condition)) and not with if(condition).

Here is the function, the pupose of this function is as you can see checking if a string is a number or not. this function works I've tested it.

bool check_key(char* key){
    for(int i =0; i <strlen(key); i++)
    {
        if(!isdigit(key[i]))
            return false;
    }
    return true;
}

But this version doesn't work why ?

bool check_key(char* key){
    for(int i =0; i <strlen(key); i++)
    {
        if(isdigit(key[i]))
            return true;
    }
    return false;
}

have I missed something ?

sorry if my english is bad I'm not native.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
dieri
  • 23
  • 6
  • for example if i put the string "4xx" it will be returned as true and being considered as a digit by the negation-less function, while the negation function will return the string as false and not considering the string as a digit. – dieri Aug 20 '21 at 17:03
  • Take a pen and a piece of paper and go over the program. For `"4xx"`, the condition is true on the first iteration, so `return true` is called immediately, so the function returns true. – HolyBlackCat Aug 20 '21 at 17:06
  • Depends on the return type, `isdigit()` returns an int, so with negation is equivalent to `if (isdigit(key[i]) == 0`... therefore it won't work as expected on the second case since you exit, if the condition is true while you probably have more characters to compare... – alex01011 Aug 20 '21 at 17:07
  • 1
    The first one stops checking and returns when it sees the first non-digit. The second one stops checking and returns when it sees the first digit. – Barmar Aug 20 '21 at 17:07
  • 1
    This is similar to [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws). This is like asking why `a || b` is not equal to `!(!a || !b)`. – HolyBlackCat Aug 20 '21 at 17:07
  • oh ok thanks, i kinda understand my mistake, indeed when i'm doing the loop when the condition of the if-statement is met it'll break out of the loop without checking the rest of the string right. – dieri Aug 20 '21 at 17:12
  • what would be the syntax to make the function go through all the char and check if they're number or not ? – dieri Aug 20 '21 at 17:13
  • @dieri Doesn't your first example already do that? – HolyBlackCat Aug 20 '21 at 17:17

3 Answers3

1

This function

bool check_key(char* key){
    for(int i =0; i <strlen(key);i++)
    {
        if(isdigit(key[i]))
            return true;
    }

    return false;
}

checks whether the string pointed to by the pointer key contains at least one symbol that represents a digit. As soon as such a symbol is found the function exits.

This function

bool check_key(char* key){
    for(int i =0; i <strlen(key);i++)
    {
        if(!isdigit(key[i]))
            return false;
        }
        return true;
    }

checks whether all symbols of the string pointed to by the pointer key represent digits.

That is in the first function the sub-statement of the if statement

        if(isdigit(key[i]))
            return true;

gets the control when the current symbol represents a digit and if so the function exits at once returning true though other symbols can represent non-digits.

In the second function the sub-statement of the if statement

        if(!isdigit(key[i]))
            return false;
        }

gets the control when the current symbol does not represent a digit and if so the function exits at once returning false. This means that the string pointed to by the pointer key contains at least one non-digit symbol.

Pay attention that the both functions are incorrect. The function that it seems for you is correct returns true for an empty string though an empty string contains neither digit.

Also it is inefficient to call the function strlen.

The function should be declared and defined at least the following way

bool check_key( const char *key )
{
    if ( *key == '\0' ) return false;

    while ( isdigit( ( unsigned char )*key ) ) ++key;

    return *key == '\0';
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • what is the meaning of ((unsigned char)*key) ? and where the return true ? and why return *key == '\0' – dieri Aug 20 '21 at 17:31
  • @dieri Passed to the function isdigit characters shall be converted to the type unsigned char. Otherwise the function can invoke undefined behavior. This return statement return *key == '\0'; means that if after the loop the current symbol is the terminating zero symbol '\0' then it means that all preceding symbols were digits. That is in this case the condition *key == '\0' evaluates to logical true. Otherwise it is evaluated to logical false. That is the result of the expression either 1 or 0 of the type int that is converted to the function returning type bool: true or false. – Vlad from Moscow Aug 20 '21 at 17:37
  • @dieri To say a little more about the `isdigit((unsigned char )*key)` part: Vlad is right, and this is a tragic and impossible-to-remember terrible nuisance. If type `char` is signed (as it is under many compilers), and if your input string contains non-ASCII characters, they may appear to be negative, meaning that you pass a negative number to `isdigit()`, and if `isdigit`'s implementation is simpleminded, it may crash on that, and according to the Standard it's allowed to. Explicitly casting every character you pass to any of the isxxx macros fixes that. – Steve Summit Aug 20 '21 at 17:46
  • ok thanks, do you any advices to give, i really need to improve my programmtion skill, any youtube channel ? book ? or website ? – dieri Aug 20 '21 at 17:47
  • @dieri You need to download a copy of the C Standard Draft from the internet. It is available. – Vlad from Moscow Aug 20 '21 at 17:49
0

You've stumbled on an important, deep, but sometimes easy-to-overlook issue of logic. When you wrote

for(i = 0; i < strlen(key); i++) {
    if(!isdigit(key[i]))
        return false;
}
return true;

you meant if any character is not a digit, return false.

But when you said

for(i = 0; i < strlen(key); i++) {
    if(isdigit(key[i]))
        return true;
}
return false;

you meant if any character is a digit, return true.

See the difference?

For the input "123", both functions return true.

For the input "abc", both functions return false.

But for the input "12x", the second function returns true, because at least one character is a digit. The first function, on the other hand, correctly returns false, because at least one character is not a digit.

This is related to De Morgan's Law.

You might also want to think about what the function should do if given inputs like "-123", " 123", "123 ", or "123\n".

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • read what the first one does again. You removed a { which changes it. – Garr Godfrey Aug 20 '21 at 17:12
  • thanks for your insight, i understand i have forgotten such a simple mechanism of if statement. i have tried the function with " 123" and it has been returned as a digit have to add other parameter to make it work ! – dieri Aug 20 '21 at 17:22
  • @dieri Another case that's easy to forget is `"-123"`. (Depending on your needs, you may also want to accept `"+123"`.) – Steve Summit Aug 20 '21 at 17:40
0

The first version returns false as soon as it finds a character that isn't a digit. If it reaches the end of the loop, it returns true. So it only returns true if every character is a digit, i.e. the string looks like a number.

The second version returns true as soon as it finds a character that is a digit. If it reaches the end of the loop, it returns false. So it returns true if any character is a digit, and only returns false if none of the characters is a digit.

So if key contains a mix of digits and non-digits, like "a1b", the first version will return false, but the second version will return true.

Barmar
  • 741,623
  • 53
  • 500
  • 612