Search code examples
cscanffgets

What am I missing in this use of fgets?


If I run the below code with scanf, it returns a string if it's in the tracks array. According to the book Head First C, this should work with fgets but returns nothing for me:

#include <stdio.h>
#include <string.h>

#define MAX 80

char tracks[][MAX] = {
    "The Girl from Ipanema",
    "Here Comes the Sun",
    "Wonderwall",
    "You Belong To Me",
    "Everlong",
};

void find_track(char search_for[])
{
    int i = 0;
    for(i = 0; i < 5; i++) {
        if(strstr(tracks[i], search_for)) {
            printf("Track %d: %s\n", i, tracks[i]);
        }
    }
}

int main()
{
    char search_for[MAX];
    printf("Search for: ");
    //scanf("%79s", search_for);
    fgets(search_for, MAX, stdin);
    find_track(search_for);
    return 0;
}

Input looks like the following:

./tracks
Search for: 
Here

Nothing happens


Solution

  • It's probably because fgets will also read the newline, i.e. '\n'. In more details:

    If you type Girl<enter> then search_forwill contain the characters: 'G' 'i' 'r' 'l' '\n' However, your tracks only contain 'G' 'i' 'r' 'l' without the '\n'.

    Consequently you will not find a matching substring.

    Try changing:

    fgets(search_for, MAX, stdin);
    

    into

    fgets(search_for, MAX, stdin);
    if (strlen(search_for) > 0) search_for[strlen(search_for)-1] = '\0';
    

    to remove the trailing newline

    Edit based on comments

    It's true that (depending on your OS/environment) the input stream can be terminated without a newline (ctrl-z, ctrl-d on some systems). If that is done the above code is insufficient. It needs an extra check like:

    if (strlen(search_for) > 0 && search_for[strlen(search_for)-1] == '\n')
        search_for[strlen(search_for)-1] = '\0';
    

    to make sure that only a "newline" is converted to a string termination.