Search code examples
cstringcharstdinfgets

fgets() not working in a function


I am writing a program which uses fgets() to scan a 3 Char long string as an Airport code for Departure and arrival. When I write the statement outside its method (in the main) it works fine however inside it does not wait for input and leaves the variables blank.

void newFlight ()
    {
        printf("\n");
        printf("============= CREATE A NEW FLIGHT ============= \n");
        printf("Type 0 at any point to exit to main menu. \n");
        printf("\n");

        printf("EnterFlight ID (0 to cancel) : ");
        scanf("%d", &flyList[curFly].flightID);

        char codeA [4];
        printf ("Enter Destination (Airport Code): ");
        fgets(codeA, 3, stdin);
        strcpy(codeA, flyList[curFly].arrive);
        printf("%s   %s \n", codeA, flyList[curFly].arrive);  //TEST

        printf("Enter Place Of Departure: ");
        char codeD[4];
        scanf("%s", codeD);
        strcpy(codeD, flyList[curFly].depart);
        printf("%s   %s \n", codeD, flyList[curFly].depart);  //TEST

        printf("Enter Date Of Departure (DD MM YYYY): ");
        scanf("%hd %hd %hd", &flyList[curFly].timeOfDep.day, &flyList[curFly].timeOfDep.month, &flyList[curFly].timeOfDep.year);

        printf("Enter Time Of Departure (HH MM)in 24Hr Format: ");
        scanf("%hd %hd", &flyList[curFly].timeOfDep.hour, &flyList[curFly].timeOfDep.minute);       

        curFly++;
    }

Solution

  • Mixing fgets() with scanf() is problematic.

    fgets() consumes the Enter (\n).
    scanf("%d", ... sees the \n, which stops the %d conversion, and puts \n back into stdin for the next IO operation - which happend to be OP's fgets() which returns promptly with a short string.

    Also need to check scanf() results. specifying a width with "%s is good, like "%3s.

    Quick solution: only using scanf()

     //  scanf("%d", &flyList[curFly].flightID);
    if (1 != scanf("%d", &flyList[curFly].flightID)) handle_error();
     ...
    char codeA [4];
    // fgets(codeA, 3, stdin);
    if (1 != scanf("%3s", codeA) handle_error();
    ...
    // Likely backwards
    // strcpy(codeA, flyList[curFly].arrive);
    strcpy(flyList[curFly].arrive, codeA);
    ...
    char codeD[4];
    // scanf("%3s", codeD);
    if (1 != scanf("%3s", codeD)) handle_error();
    ...
    // scanf("%hd %hd %hd", &flyList[curFly].timeOfDep.day, &flyList ...
    if (3 != scanf("%hd %hd %hd", &flyList[curFly].timeOfDep.day, &flyList[curFly].timeOfDep.month, &flyList[curFly].timeOfDep.year)) handle_error();
    ...
    // scanf("%hd %hd", &flyList[curFly].timeOfDep.hour, &flyList ...
    if (2 != scanf("%hd %hd", &flyList[curFly].timeOfDep.hour, &flyList[curFly].timeOfDep.minute)) handle_error();
    

    Better solution: use fgets()/sscanf()

     //  scanf("%d", &flyList[curFly].flightID);
    char buf[100];
    if (fgets(buf, sizeof buf, stdin) == NULL) Handle_EOForIOError();
    if (1 != sscanf(buf, "%d", &flyList[curFly].flightID)) handle_parse_error();
    ... 
    if (fgets(buf, sizeof buf, stdin) == NULL) Handle_EOForIOError();
    if (1 != sscanf(buf, "%3s", flyList[curFly].arrive) handle_parse_error();
    ...
    etc.
    

    BTW: scanf() format "%hd %hd" and "%hd%hd" do the same thing.