0

I'm having troubles with my program. The aim of it is to read an input of numbers from the user, and when they stop inputting numbers (ctrl-d) it collects the inputted numbers and prints out 'Odd numbers were: blah blah' and 'Even numbers were: blah blah'.

I'm having trouble with how to exit the program at EOF and when it feels like I have overcome that problem, another problem occurs which is my program doesn't print the numbers from the array. It only prints 'Odd numbers were:' and 'Even numbers were:'.

Any help is appreciated. Thanks

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
int main(void) {
int n, i, array[1000];
    i=0;
    while (i = getchar() !=EOF) {
        scanf("%d", &array[i]);
        i++;
    }   
    printf("Odd numbers were:");
    i=0 ;
    while(i = getchar() != EOF) { 
        if(array[i]%2!=0) {
            printf(" %d", array[i]);
            i++;
        }
    }
    printf("\nEven numbers were:");
    i=0 ;
    while(i = getchar() !=EOF) { 
        if (array[i]%2==0) {
            printf(" %d", array[i]);
            i++;
        } 
    }
        printf("\n");
return 0;
}
Michael
  • 139
  • 1
  • 12
  • `i=0 ; while(i = getchar() != EOF) { if(array[i]%2!=0) { printf(" %d", array[i]); i++; } }` --> `for(n = i, i = 0; i < n; ++i) { if(array[i]%2!=0) { printf(" %d", array[i]); } }` – BLUEPIXY May 04 '17 at 01:32
  • Check this out: http://stackoverflow.com/questions/10720821/im-trying-to-understand-getchar-eof – Eggsalad May 04 '17 at 01:35
  • `while (i = getchar() !=EOF) { scanf("%d", &array[i]); i++; }` --> `while (scanf("%d", &array[i]) == 1) { i++; }` – BLUEPIXY May 04 '17 at 01:36
  • 3
    `i = getchar() !=EOF` is like `i = (getchar() !=EOF)` – chux - Reinstate Monica May 04 '17 at 02:04
  • One you correct the grouping error chux pointed out, you'll also need to consider why you can't loop twice without rewinding the input. Your second while loop is never going to be executed. – William Pursell May 04 '17 at 02:21
  • Since you already stored the values entered in `array`, why are you calling `getchar()` in your second and third `while` loops instead of simply iterating over the values stored in `array`? Wouldn't `for (int j = 0; j < i; j++) { if(array[i]%2!=0) ... }` work just as well and eliminate the problem of not having any more input to read? – David C. Rankin May 04 '17 at 03:36
  • You might wanna check [operator precedence](https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence) ( and ignore (c++ only)) –  May 04 '17 at 05:51

2 Answers2

0

Change the input loop to:

n = 0;

while ( 1 == scanf("%d", &array[n]) )
    ++n;

What you actually want to do is keep reading numbers until the read attempt fails; this loop condition expresses that logic. Forget about EOF. (It would also be a good idea to add logic to stop when n reaches 1000, to avoid a buffer overflow).

In the output loops, you do not want to do any input, so it is not a good idea to call getchar(). Instead, use a "normal" loop, for (i = 0; i < n; ++i).

M.M
  • 138,810
  • 21
  • 208
  • 365
0

Performing Single-Digit Conversion to int

You may be making things a bit harder on yourself than it needs to be. While you can use while (scanf ("%d", &array[i]) == 1) to read whitespace separated integers and avoid having to perform a manual conversion, if your intent is to read single-digits, then using getchar() is fine. (for that matter, you can read any multi-digit integer with getchar(), it is simply up to you to provide a conversion from the ASCII characters to final numeric value)

The manual conversion for single-digit characters is straight forward? When you read digits as characters, you are not reading the integer value represented by the digit, you are reading the ASCII value for the character that represents each digit. See ASCII Table and Description. In order to convert a single ASCII character digit to it's integer value, you must subtract the ASCII value of '0'. (note: the single-quotes are significant)

For example if you read a digit with int c = getchar();, then you need to subtract '0' to obtain the single-digit integer value, e.g. int n = c - '0';

When filling an array, you must ALWAYS protect against writing beyond the bounds of your array. If you declare int array[1000] = {0}; (which has available zero-based array indexes of 0-999), then you must validate that you never write beyond index 999 or Undefined Behavior results. To protect your array bounds, simply keep track of the number of indexes filled and test it is always below the number of array elements available, e.g.

while (n < MAX && (c = getchar()) != EOF)   /* always protect array bounds */
    if ('0' <= c && c <= '9')               /* only handle digits */
        array[n++] = c - '0';               /* convert ASCII to int */

Next, while you are free to test n % 2 (using the modulo operator), there is no need (little endian). Since any odd number will have its ones-bit set to 1, all you need is a simple bitwise comparison, e.g (7 in binary is 0111).

    if (array[i] & 1)                       /* if ones-bit is 1, odd */
        printf (" %d", array[i]);

Of course, for even numbers, the ones-bit will be 0 (e.g. 8 in binary is 1000), so the corresponding test can be:

    if ((array[i] & 1) == 0)                /* if ones-bit is 0, even */
        printf (" %d", array[i]);

Putting all of the pieces together, you can store all single digits read in array and then segregate the even and odd numbers for printing in a very simple manner (note: neither stdlib.h or math.h are required),

#include <stdio.h>

#define MAX 1000   /* define a constant rather than use 'magic' numbers in code */

int main (void)
{
    int array[MAX] = {0},
        c, i, n = 0;

    while (n < MAX && (c = getchar()) != EOF)   /* always protect array bounds */
        if ('0' <= c && c <= '9')               /* only handle digits */
            array[n++] = c - '0';               /* convert ASCII to int */

    printf ("\narray        : ");               /* output array contents */
    for (i = 0; i < n; i++)
        printf (" %d", array[i]);

    printf ("\narray - odd  : ");
    for (i = 0; i < n; i++)
        if (array[i] & 1)                       /* if ones-bit is 1, odd */
            printf (" %d", array[i]);

    printf ("\narray - even : ");
    for (i = 0; i < n; i++)
        if ((array[i] & 1) == 0)                /* if ones-bit is 0, even */
            printf (" %d", array[i]);

    putchar ('\n');                             /* tidy up w/newline */

    return 0;
}

Example Compilation with Warnings Enabled

$ gcc -Wall -Wextra -pedantic-std=gnu11 -Ofast -o bin/arrayevenodd arrayevenodd.c

Example Use/Output

$ echo "01234567890123456789" | ./bin/arrayevenodd

array        :  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
array - odd  :  1 3 5 7 9 1 3 5 7 9
array - even :  0 2 4 6 8 0 2 4 6 8

Look things over and let me know if you have further questions.


Performing Manual Multi-Digit Conversion to int

If you are needing to convert multi-digit integers from characters, the easy way is to use a function that provides the conversion for you (e.g. the scanf family of functions or by using line oriented with fgets or getline and parsing and converting the strings of digits with strtok and then strtol, or parsing with sscanf, etc.)

However, performing a manual conversion of individual characters read by getchar() into a multi-digit integers is straight forward. You simply check for a valid character than can begin an integer (including the prefixes of +/-) and sum each digit providing a proper offset for the place of the digit by increasingly multiplying the sum by 10 before adding (or actually subtracting if building a the sum as a negative sum for coding efficiency purposes) each digit until you reach the next non-digit and then you add the final sum to your array and advance the array index.

While building the sum, it is up to you to check for integer Overflow before adding the final sum to your array. (you can handle the overflow condition however you like, the example below just throws the error and exits)

The manual conversion probably adds about 20 lines of code, e.g.

#include <stdio.h>
#include <stdint.h> /* exact length types */
#include <limits.h> /* INT_X constants */

#define MAX 1000    /* define constant rather than use 'magic' number in code */

int main (void)
{
    int array[MAX] = {0},
        c, i, start = 0, sign = 1, n = 0;
    int64_t sum = 0;

    while (n < MAX && (c = getchar()) != EOF) { /* always protect array bounds */
        if (!start) {                           /* flag to start building int  */
            start = 1;                          /* flag - working on int */
            if (c == '+')                       /* handle leading '+' sign */
                continue;
            else if (c == '-')                  /* handle leading '-' sign */
                sign = -1;
            else if ('0' <= c && c <= '9')      /* handle digits */
                sum = sum * 10 - (c - '0');     /* note: sum always computed */
            else                                /*       as negative value   */
                start = 0;                      /* reset - char not handled  */
        }
        else if ('0' <= c && c <= '9') {        /* handle digits */
            sum = sum * 10 - (c - '0');         /* convert ASCII to int */
            if (sum < INT_MIN || (sign != -1 && -sum > INT_MAX))
                goto err;               /* check for overflow, handle error */
        }
        else {                          /* non-digit ends conversion */
            if (sum)                    /* if sum has value, add to array */
                array[n++] = sign != -1 ? -sum : sum;
            sign = 1;                   /* reset values for next conversion */
            start = 0;
            sum = 0;
        }
    }
    if (sum)    /* add last element to array on EOF */
        array[n++] = sign != -1 ? -sum : sum;

    printf ("\narray        : ");               /* output array contents */
    for (i = 0; i < n; i++)
        printf (" %d", array[i]);

    printf ("\narray - odd  : ");
    for (i = 0; i < n; i++)
        if (array[i] & 1)                       /* if ones-bit is 1, odd */
            printf (" %d", array[i]);

    printf ("\narray - even : ");
    for (i = 0; i < n; i++)
        if ((array[i] & 1) == 0)                /* if ones-bit is 0, even */
            printf (" %d", array[i]);

    putchar ('\n');                             /* tidy up w/newline */

    return 0;

    err:

    fprintf (stderr, "error: overflow detected - array[%d]\n", n);
    return 1;
}

Example Use/Output

$ echo "1,2,3,5,76,435" | ./bin/arrayevenodd2

array        :  1 2 3 5 76 435
array - odd  :  1 3 5 435
array - even :  2 76

Example with '+/-' Prefixes

$ echo "1,2,-3,+5,-76,435" | ./bin/arrayevenodd2

array        :  1 2 -3 5 -76 435
array - odd  :  1 -3 5 435
array - even :  2 -76

Look over the new example and let me know if you have any more questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • Thanks for the help. The only problem with the code above though is that lets say i input 1,2,3,5,76,435 etc. The program reads that as me inputting 1,2,3,5,7,6,4,3,5 and then the output where there is the odd and even numbers, it outputs those single digits only. For example it would say, Odd: 1 3 5 7 3 5. and the same for even. I was looking more for a program where it recognises multi-digit integers. Thanks David – Michael May 04 '17 at 13:56
  • No problem. It wasn't clear, performing the manual multi-digit conversion isn't much more work, you just need to take care to protect against *Overflow*, I'll add an example. – David C. Rankin May 05 '17 at 04:24