cwhile-loopeoffeof

Why does my program print something before it ends when I press ctrl + D?


So I wrote a simple program that converts a decimal to binary, that only accepts positive whole numbers. So numbers like -2 and 1.1 would output "Sorry, that's not a positive whole number." It infinitely asks the user to input a number until the user presses ctrl + D. However when I tested it it prints out the "Sorry..." statement before it ends the program.

Here is my code:

#include <stdio.h>
#include <stdlib.h>

void DecToBin(int userInput){
    int binary[32];
    int i = 0;
    while (userInput > 0) {
        binary[i] = userInput % 2;
        userInput /= 2;
        i++;
    }
    for (int j = i - 1; j >= 0; --j) {
        printf("%d", binary[j]);
    }
}

int main(void) {
    double userDec;
    int temp;

    printf("Starting the Decimal to Binary Converter!\n\n");

    while(!feof(stdin)) {
        printf("Please enter a positive whole number (or EOF to quit): ");
        scanf("%lf", &userDec);
        temp = (int)(userDec);
        if ((userDec > 0) && (temp / userDec == 1)) {
            printf("\n\t%.0lf (base-10) is equivalent to ", userDec);
            DecToBin(userDec);
            printf(" (base-2)!\n\n");
        }
        else {
            printf("\tSorry, that was not a positive whole number.\n");
        } 
    }
    printf("\n\tThank you for using the Decimal to Binary Generator.\n");
    printf("Goodbye!\n\n");
    return 0; 
}

(All the tab and newlines are just how it's supposed to be formatted so don't pay attention to that) So from what I'm understanding, my program reads ctrl + D as the else in my while loops. So, any idea why that is?


Solution

  • It seems like you think C-d would trigger some kind of break in the code. Like the keyword break. This is not true.

    Read this post to see what's happening when you press C-d: https://stackoverflow.com/a/21365313/6699433

    That does not cause anything special to happen in the C code. scanf will simply not read anything. After the scanf statement, the code will continue as usual, so the code WILL unconditionally enter the if statement.

    This is also a pretty severe thing, because you'll be using userDec uninitialized. scanf returns the number of successful assignments, and you should always check the return value. So in your case you want this:

    if(scanf("%lf", &userDec) != 1) { /* Handle error */ }
    

    Because if scanf does not return 1, userDec is unassigned.

    To achieve what you want, simply do this:

    if(scanf("%lf", &userDec) != 1)
        break;