End while loop by EOF only once

117 Views Asked by At

I am trying to solve this problem but unfortunately I can't find any solution.

I have this loop that I want to break with EOF but it always requires it twice instead once.

    do {
        int input = scanf("%d", &elements[count++]);
        if (input == EOF) {
            break;
        }
        if (input == 0) {
            wrongInput = true;
            return;
        }
    } while (1);

I also tried it like this but it didn't work either:

    while ((int input = scanf("%d", &elements[count++])) != EOF) {
        if (input == 0) {
            wrongInput = true;
            return;
        }
    }

I always had to press Ctrl-D twice. This is the whole code:

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

int count = 0;

int elements[1000000];

int diff = 0;
int optCount = 0;
int firstElement[1000000];
int secondElement[1000000];

bool wrongInput = false;

void inputArr() {

    bool emptyCheck = false;
    // Perform a do-while loop

    do {
        int input = scanf("%d", &elements[count++]);
        if (input == EOF) {
            break;
        }
        if (input == 0) {
            wrongInput = true;
            return;
        }
        if (input != 1) {
            emptyCheck = true;
        }
    } while (1);

    // Resize the array size to count
    elements[count];
    if (emptyCheck == true) {
        elements[count--];
    }
}

void farthestMax(int b[], int n) {
    // To store maximum element in the range i to n
    int suffix_max[n];
    suffix_max[n - 1] = b[n - 1];
    for (int i = n - 2; i >= 0; i--)
    {
        suffix_max[i] = (suffix_max[i + 1] > b[i]) ? suffix_max[i + 1] : b[i];
    }

    for (int i = 0; i < n; i++)
    {
        int low = i + 1, high = n - 1, ans = -1;

        while (low <= high)
        {
            int mid = (low + high) / 2;

            // If current element in the suffix_max is greater than b[i] then move right
            if (suffix_max[mid] > b[i])
            {
                ans = mid;
                low = mid + 1;
            }
            else
                high = mid - 1;
        }

        // Print the required answer
        int currentDiff = ans - i;
        if (ans != -1) {
            if (currentDiff == diff) {
                firstElement[optCount] = i;
                secondElement[optCount] = ans;

                optCount++;
            }
            if (currentDiff > diff) {
                diff = currentDiff;
                optCount = 1;
                firstElement[0] = i;
                secondElement[0] = ans;
            }
        }
    }
}

int main() {
    printf("Input numbers:\n");
    inputArr();
    if (wrongInput == true) {
        printf("Wrong input.\n");
        return EXIT_FAILURE;
    }
    printf("\n");
    farthestMax(elements, count);
    if (optCount == 0) {
        printf("Cant find.\n");
    } else {
        for (int i = optCount - 1; i >= 0; i--) {
            printf("%d: %d - %d\n", diff + 1, firstElement[i], secondElement[i]);
        }
        printf("Options: %d\n", optCount);
    }

    return EXIT_SUCCESS;
}
2

There are 2 best solutions below

0
chqrlie On

The behavior you observe is a side effect of the terminal handling of the special character Ctrl-D by default associated to the EOF terminal function as explained in the termios man page:

     EOF     Special character on input and is recognized if the ICANON flag
             is set.  When received, all the bytes waiting to be read are 
             immediately passed to the process, without waiting for a
             newline, and the EOF is discarded.  Thus, if there are no bytes
             waiting (that is, the EOF occurred at the beginning of a line),
             a byte count of zero is returned from the read(), representing
             an end-of-file indication.  If ICANON is set, the EOF character
             is discarded when processed.  NL Special character on input and 
             is recognized if the ICANON flag is set.  It is the line
             delimiter `\n'.

When you read input with scanf("%d", ...) in a loop, the scanf function reads the characters, skipping initial whitespace and converts the digits until it gets a non digit input or the end of file from the terminal. The terminal is line buffered by default, so user input is flushed to the caller when the user hits Enter or in some special circumstances. If you type Ctrl-D at the end of a non empty line, the line contents are flushed to the process. In this case, scanf will eventually try and continue reading from standard input because a short read count is not considered an end iof file, whereas if you type Ctrl-D at the beginning of an empty line, or just after a flush, the read request from the terminal will return 0, which the stream reading functions will interpret as the end of file.

Hence you may need to type Ctrl-D twice if you are not at the beginning of a line.

0
chux - Reinstate Monica On

want to break with EOF but it always requires it twice instead once.

The bolded it, a Ctrl-D, is not always an EOF.

In OP's case, 2 Ctrl-Ds only sent 1 end-of file signal.