user1439114
user1439114

Reputation: 31

C-language strstr segmentation fault

i'm a beginner,tracks.c:

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

char tracks[][5] = {
    "one",
    "two",
    "three",
    "four",
    "five",
    "six",
};

void track_search(char search_for[]) {

    int i;
    puts(search_for);
    puts(strstr(tracks[0], search_for));

    /*
    for (i = 0; i < 6; i++) {
        if (strstr(tracks[i], search_for)) {
            printf("tracks %i: %s\n", i,tracks[i]);
        } else {
            puts("Nothing found");
        }
    }
    */
}

int main() {

    char search_for[5];

    printf("enter your word: ");
    fgets(search_for, 5, stdin);
    track_search(search_for);

    return 0;
}

$ gcc tracks.c && ./a.out

enter your word: on

on

Segmentation fault

but if I use puts(strstr(tracks[0], "on")); instead of puts(strstr(tracks[0], search_for)); it will works wine,anyone knows where is wrong?

Upvotes: 3

Views: 7461

Answers (3)

WhozCraig
WhozCraig

Reputation: 66234

There are several things wrong with this.

First, your constant array is not declared correctly.

char tracks[][5] = {
    "one",
    "two",
    "three",
    "four",
    "five",
    "six",
};

This says "declare an array of arbitrary length of char[5]. Stare at that array content very closely, and consider that the length of those strings is actually its character count plus one for the zero-terminator. Anything pop out at you? Perhaps the word "three" ? That would be 5+1, or six chars wide, not five.

Try this:

const char *tracks[] = 
{
    "one",
    "two",
    "three",
    "four",
    "five",
    "six"
};

And also modify your for loop like so:

for (i = 0; i < sizeof(tracks)/sizeof(tracks[0]); ++i) 
{
    if (strstr(tracks[i], search_for))
        printf("track[%d]: %s\n", i, tracks[i]);
}

Note: I pulled the redundant "Nothing found" from the loop for my own sanity.

Finally, the string fetched will likely have an end-of-line ('\n') tacked on to the end, and you should check and null it if so. I would significantly lengthen the size of your input buffer, then trim the endl out if it is there:

int main()
{
    char search_for[64] = {0};

    printf("enter your word: ");
    if (fgets(search_for, sizeof(search_for), stdin))
    {
        size_t len = strlen(search_for);
        if (len && search_for[len-1] == '\n')
            search_for[len-1] = 0;
        track_search(search_for);
    }
    else
    {
        perror("fgets failed.");
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

Upvotes: 3

jkozera
jkozera

Reputation: 3066

It's because fgets reads a newline, so "on\n" is not found in "one", thus strstr returns NULL which causes segmentation fault if it's passed to puts.

You probably want to remove newline and other whitespace first after reading the input, for example by setting first occurence of newline/space to 0, like

char *p;
if(p = strchr(search_for, '\n')) *p = 0;
if(p = strchr(search_for, ' ')) *p = 0;

(Also char[5] is not enough for "three", because you need additional place for null terminator.)

Upvotes: 3

nos
nos

Reputation: 229158

There's 2 things you must consider:

If the words is not in the list, strstr() returns a NULL pointer and you can't pass that to puts(), so do e.g.

 char *found = strstr(tracks[0], search_for);
if (found)
    puts(found);
else
    puts("The word '%s' was not found\n",search_for);

Once you do that you will realize that fgets also reads the newline you type. So if you input four and hit enter, you will search for "four\n" So you should erase that \n character, e.g. do

char *p;
if ((p = strrchr(search_for, '\n')) != NULL) {
   *p = 0;
}

After you read the input with fgets.

Upvotes: 2

Related Questions