2

In this code, scanf works only once. What am I doing wrong?

#include <stdio.h>
#include <unistd.h>

int main()
{
    int i = 1;
    if (! fork())
    {
        while(i)
        {
            printf("Enter i");
            scanf("%d", &i);
            fflush(stdin);
            fflush(stdout);
        }
    }
    else
    {
        printf("Parent\n");
    }
    return(0);
}
Dan Lowe
  • 51,713
  • 20
  • 123
  • 112
user277773
  • 51
  • 1
  • 3
  • 1
    scanf() is evil. Don't use it. – Andreas Bonini Feb 20 '10 at 19:40
  • 1
    Why on earth are you using `fork()` in this? It doesn't directly affect the logic, but...your child process is reading standard input while your parent process prints and exits (without waiting for the child). The child is orphaned. Are you sure it isn't just sitting there in the background, arguing with the shell over who gets to read the next line of data (and losing)? – Jonathan Leffler Feb 20 '10 at 21:44
  • Minus the 'fork()', the code shows interesting behaviour. The prompt appears (no space before where the data is typed). It loops; repeat a few times. The read value is not shown. Type EOF and the program goes into an indefinite loop. Not good. Always check the return from scanf()! – Jonathan Leffler Feb 20 '10 at 21:46
  • From the POSIX documentation (Consequences of Process Termination): "Termination of a process does not directly terminate its children. The sending of a SIGHUP signal as described below indirectly terminates children in some circumstances. [...] If the process is a controlling process, the SIGHUP signal shall be sent to each process in the foreground process group of the controlling terminal belonging to the calling process." – Jonathan Leffler Feb 21 '10 at 04:30

5 Answers5

3

It has already been recommended that you not use scanf. If you feel you must use scanf, you really should be checking the return value to determine if an input error occurred prior to the conversion.

It has also been noted that you should not be flushing stdin via fflush as it invokes undefined behavior. If you feel that you must flush stdin, you may want to refer to the answers to this question.

If an invalid value such as "1,234" is entered, scanf will accept the '1' and the ",234/n" will be left in the input stream. Since fflush(stdin) is not guaranteed to work, subsequent calls to scanf will keep rejecting the same ',' over and over again, never making any progress. If the return value is checked for zero (indicating an early matching failure), this infinite loop can be avoided. It is also necessary to remove the invalid character(s) from the input stream prior to another call to scanf.


See scanf() causing infinite loop as well.

Community
  • 1
  • 1
jschmier
  • 15,458
  • 6
  • 54
  • 72
1

try to check if i>0.

oneat
  • 10,778
  • 16
  • 52
  • 70
1

It's a bit hard to say without seeing what input you're providing. If it works without fork then it might be a clash as Amit described. Two other things, though:

  1. Don't use scanf.

  2. fflush(stdin) is undefined behavior. Don't do it.

From the comp.lang.c FAQ:

jamesdlin
  • 81,374
  • 13
  • 159
  • 204
1

After the parent process returns, it hands control back to the shell, which is free to close its stdin. Even if stdin remained valid and active, the user would receive a confusing shell prompt.

To retain the child's access to stdin/out, you need to stall the parent from terminating until the child is done. Use wait or a related function.

#include <sys/wait.h>

else {
    printf( "parent\n" );
    wait( NULL );
}

This fixes your bug on my machine. I'm not an expert on Unix file descriptor semantics, but it appears the resulting program might be portable. Why you want to do this is another matter…

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
0

First I tried to extract the simplest code that gives the problem (not used C/scanf for a long time). The code without the fork works fine. A little google search "fork scanf" gave me the answer.

After the fork, the input stream is closed. So the scanf gets into a bad state. The following program is a slight modification of yours. It prints "stream closed".

#include<stdio.h>
#include<unistd.h>
int main()
{
        int i = 1;
        if(!fork())
        {
                while(i)
                {
                        printf("Enter i");
                        int j = scanf("%d",&i); // changed
                        if(j == EOF) {             // added
                                printf("stream closed"); // added
                                return 1;       // added
                        }                       // added
                        fflush(stdin);
                        fflush(stdout);
                }
        }
        else
        {
                printf("Parent\n");
        }
        return(0);
}
amit kumar
  • 20,438
  • 23
  • 90
  • 126
  • 2
    When you 'fork()', the two processes are almost identical - and in particular, they have the same files open. The child's standard input is not closed. – Jonathan Leffler Feb 20 '10 at 21:51