Home > Software design >  Why the function does not work when there are two zeros in the function?
Why the function does not work when there are two zeros in the function?

Time:09-08

I'm trying to write code that counts even digits (a typical beginner task)

What changes do I need to make in the code to get 2, for example, from the number 0011?

Is there a simple solution without additional libraries and complex loops?

#include <stdio.h>
int evensDigitsCount(int number);
int main()
{
    int res = evensDigitsCount(0011);
    printf("Counter: %d\n",res);
    return 0;
}

int evensDigitsCount(int number)
{
    int rem  = 0;
    int count = 0;
    
    do{
        rem = number % 10;
        if(rem % 2 == 0 )
        count  ;
        number = number / 10;
    }while(number != 0);
    return count;
}

CodePudding user response:

Your code is behaving correctly. 0011 is an octal literal for the decimal value 9, and your code is accurately reporting that, in base-10 (decimal), 9 has no even valued digits (the only digit is 9, and it's odd).

Your problem seems to be that you think 0011 remembers the digits it was typed with. It does not. In every way that matters, typing 0011 is the same as typing 9 in the same spot. If you want to preserve all the digits, including leading zeroes (which don't exist once the code is compiled), you need to work with strings (e.g. "0011"), not ints, and parse the digits as you go, rather than extracting them mathematically.

Alternatively, since you ignore odd digits, your existing code will work if you just shove an odd digit on the left side of any literal passed to it (preventing interpretation as octal and preserving the zeroes you expect to see), but that's only valid for literals you control, you couldn't reliably do it for data generate in other ways (which has no way of knowing how many leading zeroes "count").

CodePudding user response:

“0011” is not a number. It is a numeral, which is a string of characters that represents a number.

In common human notation, “0011” is in decimal and represents the number eleven. However, in C source code, numerals starting with “0” (but not “0x” or “0X”) use octal, so “0011” represents the number nine.

Calling evensDigitsCount(0011) gives the number parameter of evensDigitsCount the value nine. It is just that abstract mathematical entity of nine; it does not have any digits or other characters representing it. (It is represented inside the computer with a string of bits, but that does not matter here, because the C source code you show operates on its value, not the bits that represent it.)

When the program executes rem = number % 10, number has the value nine, and the remainder of nine modulo ten is nine, so rem is set to nine. This is not even, so count is not executed.

Then number = number / 10; calculates nine divided by ten, rounded down (since number is positive) to an integer. This produces zero, so number is set to zero, and the loop ends.

To count the digits in a numeral, you must pass the numeral as a string, not a number. You could rewrite evensDigitsCount to have a parameter of const char *numeral, and then you could call it with evensDigitCount("0011"). Then the function could examine each character in the string to check whether it is one of the even digits, “0”, “2”, “4”, “6”, or “8”.

CodePudding user response:

Numbers starting with 0 are octal constants. So 0011 is octal representation for decimal 9.

Just leave off the leading zeros if you want decimal.

CodePudding user response:

The other answers provided are all correct, explaining the "octal" interpretation of the digits in your OP.

This OP highlights the "unexpected" results when a beginner's knowledge is still growing. "Why does the compiler treat my values different from what I can clearly see in the source code?"

This suggests an interesting (and, perhaps, educational) digression; What if a program COULD examine its own source code?

Below is an attempt to provide an example of a program that does just that. The program reads lines from its own source code file until it finds "the interesting line", then, after some stepping closer to the interesting bit of that line (remembering that this is 'text'), a version of your function counts the number of even 'digits' until it reaches the end of those ASCII digits (the ')' of the function parameter list.)

The only "additional library" is the used everywhere C string library of functions. And these loops should not be too 'complex' to understand. This program makes use of "pointers to strings", a concept to be mastered early in one's learning.

#include <stdio.h> // FILE and printf()
#include <string.h> // str???() // additional library header

// function definitions ahead of "use" eliminates prototypes (for single sources)
// NB: function now "sees" value as a string, not a translated integer
int evensDigitsCount( char *str ) {
    char *dgts = "0123456789", *p = NULL; // some variables
    int count = 0;

    printf( "Examining str: '%s'\n", str );

    // step forward thru string as long as finding ASCII integers
    // pointer arithemetic converts ASCII digit
    // to index in ascending ASCII string of digits
    // If index mod 2 has no remaider, then digit is even
    // In C, true has the value 1 (false value is 0)
    // Add 1 (or 0) to accumulator
    for( ; ( p = strchr( dgts, *str ) ) != NULL; str   )
        count  = (p - dgts)%2 == 0;

    return count;
}

int main() {
    // compiler "knows" this source filename.
    // it replaces __FILE__ with the filename as a string
    char *fname = __FILE__;

    char buf[ 256 ]; // generous?

    // to remember where target string located in line buffer (when found)
    char *fncCall = NULL;

    printf( "Examining file '%s'\n", fname );

    // open THIS source file (text) for reading
    FILE *ifp = fopen( fname, "r" ); // brevity. omitting checks

    // read lines until target string found
    while( !fncCall && fgets( buf, sizeof buf, ifp ) )
        fncCall = strstr( buf, "= evensDigitsCount(0000121);" );

    // NB: For this version, it is the line above
    // that will be "found" as the 'target'
    // (looking for itself in the text of this source code)
    // Alternate processing could find the actual function invocation below
    // This is an example of "program introspection" for demonstration purposes

    fclose( ifp ); // no longer needed

    // target not found... should never happen!, but...
    if( !fncCall ) {
        printf( "Cannot locate target string\n" );
        return -1;
    }

    printf( "Found target: '%s'\n", fncCall );

    // invoke (adapted) version of your function
    // passing pointer to one-beyond the open parenthesis
    int nEven = evensDigitsCount( strchr( fncCall, '(' )   1 );

    printf( "Number of even digits found = %d\n", nEven );

    return 0;
}

Output: The "broken lines" arise because fgets() leaves the LF at the end of the string buffer.

Examining file '.../StackOver.c' // shortened full name
Found target: '= evensDigitsCount(0000121);" );
'
Examining str: '0000121);" );
'
Number of even digits found = 5 // expected result!

Although this answer departs from your OP somewhat, it does show how you may be able to write a program that sees things your way (when you need to.)

  •  Tags:  
  • c
  • Related