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

void find_track(char *search_for);
char tracks[][80] = {
    "I left my heart in Harvard Med School",
    "Newark, Newark - a wonderful town",
    "Dancing with a Dork",
    "From here to maternity",
    "The girl from Iwo Jima"
};

int main() {
    char *to_search_str;
    printf("Search for: ");
    fgets(to_search_str, 80, stdin);
    find_track(to_search_str);
    return 0;
}

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

The program is supposed to search for a string in every string in the tracks multi dimensional array but the strstr() function in the find_track is always returning null no matter the input (even if we input the a sub string of a string from tracks multi dimensional array). I don't know why this is happening?

EDIT: After correction

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

void find_track(char *search_for);
char tracks[][80] = {
    "I left my heart in Harvard Med School",
    "Newark, Newark - a wonderful town",
    "Dancing with a Dork",
    "From here to maternity",
    "The girl from Iwo Jima"
};

int main() {
    char to_search_str[80];
    printf("Search for: ");
    fgets(to_search_str, 80, stdin);
    to_search_str[strlen(to_search_str)-1] = '\0';
    find_track(to_search_str);
    return 0;
}

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

Output enter image description here

Anonymous
  • 75
  • 1
  • 8
  • What does the sample input file look like? Please _edit_ your question and post a representative amount. After fixing the bugs that others have mentioned below, you may need to reverse the order of the args to `strstr`. For example, you'd need to do this to get a match if the input line was: `My favorite song is: "Dancing with a Dork" but I also like: "The girl from Iwo Jima" as well.` – Craig Estey Sep 15 '20 at 15:30
  • I am just starting to learn C. The input i assume to give is just a single word like `Dancing` or 'Harvard' – Anonymous Sep 15 '20 at 15:35
  • @CraigEstey I do not have to reverse the order of args it works fine – Anonymous Sep 15 '20 at 15:35
  • That's fine. There are two types of search: (1) In a [long] input sentence, look for a match to one of the song lyric lines. (2) In a file that has a list of words, one per line, see which words are in a given song lyric. It wasn't clear from your question which was the desired result [because the sample input wasn't provided]. – Craig Estey Sep 15 '20 at 15:43
  • Your edited code is [still] incorrect. You are clipping one too many chars with `to_search_str[strlen(to_search_str)-2] = '\0';`--it should be only `-1`. As you have it, an input line of `Harvard` --> `Harvar`. Also, a line like `wonderfuls` --> `wonderful` and would match even though it shouldn't. Also, even with the `-1` fix, some input files leave off the final newline, so the code would chop the last line. A surer way to get rid of newline: `*strchrnul(to_search_str,'\n') = 0;` [this is similar to what Vlad suggested with `strcspn` but is faster] – Craig Estey Sep 15 '20 at 16:01

4 Answers4

1

Most likely the issue with input via fgets().

  • You are reading into an uninitialized pointer to_search_str, which does not point to a valid memory location. In this case, you can simply change this to an array, like char to_search_str[80] = {0}; and get done with it.

  • You need to trim the trailing newline that's stored in the input buffer.

    From the man page, (emphasis mine)

fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte ('\0') is stored after the last character in the buffer.

A quick way of getting that done is to_search_str[strcspn(to_search_str, "\n")] = 0;, but there are more robust ways mentioned in this other answer

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
1

You aren't allocating to_search_str pointer, the char * pointer you pass to fgets as the destination buffer. Being it actually uninitialized, this causes undefined behavior that normally ends with a program crash.

You just need to allocate it, statically or dynamically.

The simplest solution consists in just defining a static array in the stack:

#include <string.h>

#define LEN 80

int main() {
    char to_search_str[LEN];

    printf("Search for: ");
    fgets(to_search_str, LEN, stdin);

    /* Remove trailing newline from the string to search */
    to_search_str[strcspn(to_search_str, "\n")] = 0;

    find_track(to_search_str);
    return 0;
}

The size of the array is 80 because you use this number as the size parameter in fgets. Please note the use of a #define for the constant 80, making possible to change it in a easier way.

The dynamic allocation in the heap involves the use of malloc() function (and free() as soon as the array is not needed anymore):

#include <string.h>

#define LEN 80

int main() {
    char * to_search_str = malloc(LEN);

    printf("Search for: ");
    fgets(to_search_str, LEN, stdin);

    /* Remove trailing newline from the string to search */
    to_search_str[strcspn(to_search_str, "\n")] = 0;

    find_track(to_search_str);

    free(to_search_str);
    return 0;
}

Note: since fgets retains trailing newline ``\n'` in the output buffer, we have to remove it. I used the clever oneliner solution described here.

Roberto Caboni
  • 7,252
  • 10
  • 25
  • 39
  • I'm _not_ your DVer, but two things. (1) I'd do (e.g.): `#define LEN 80` and then `char *to_search_str = malloc(LEN); fgets(to_search_str,LEN,stdin);` Or, just: `char to_search_str[80]; fgets(to_search_str,sizeof(to_search_str),stdin);` (2) But, the real issue may be that the code _needs_ to chop off the newline. IMO, DVing without explanation is not the way to go. Usually, a comment to allow the responder to fix is sufficient. Only if responder does _not_ fix an _egregiously_ wrong answer, should DV be used. – Craig Estey Sep 15 '20 at 16:40
  • @CraigEstey thanks for your comment. I can sure add the `#define LEN 80`; I would use it in my actual code but I didn't include it in my answer. I'm not sure about the trailing newline issue as: 1) there's no mention in the question about this requirement (one could actually want to retain it) - 2) OP's test syrings don't contain a newline. – Roberto Caboni Sep 15 '20 at 17:49
  • @CraigEstey I added also a note about getting rid of the trailing newline. – Roberto Caboni Sep 15 '20 at 17:57
  • Strip of newline _is_ required. If you run a corrected [e.g. your] version that does _not_ have a newline strip, the search will fail for a prompted string of `Harvard\n`. With strip, the `to_search_for` string will be `Harvard` which _will_ succeed. – Craig Estey Sep 15 '20 at 19:39
  • I used another way of getting rid of the newline is it the correct way? `to_search_str[strlen(to_search_str)-1] = '\0';` – Anonymous Sep 16 '20 at 05:03
  • I think you have to do `to_search_str[strcspn(to_search_str, "\n")] = '\0';` to remove the trailing new line. – Anonymous Sep 16 '20 at 05:15
  • @Anonymous Yes, of course you are right...^_^ it seems that yesyerday I wasn't able to write an accurate answer... – Roberto Caboni Sep 16 '20 at 05:50
  • @Anonymous `to_search_str[strlen(to_search_str)-1] = '\0';` is wrong because in case you have an empty string you write at index -1, which is undefined behavior. – Roberto Caboni Sep 16 '20 at 05:52
  • 1
    @RobertoCaboni Thanks for clarification from now on i make sure to never uses that method for removing the newline character – Anonymous Sep 16 '20 at 09:15
0

char *to_search_str; is an uninitialized pointer, writing to it will result in undefined behavior. You have to allocate memory or use an array instead char to_search_str[100]; for example.

Also don't forget that fgets will also read the newline into the buffer, which you have to remove.

mch
  • 9,424
  • 2
  • 28
  • 42
0

This code snippet in main

char *to_search_str;
printf("Search for: ");
fgets(to_search_str, 80, stdin);

invokes undefined behavior because the pointer to_search_str is not initialized and has indeterminate value.

It seems you at least mean

char to_search_str[80];
printf("Search for: ");
fgets(to_search_str, 80, stdin);

The function fgets can append the new line character '\n' to the entered string.

You need to remove it for example the following way

to_search_str[ strcspn( to_search_str, "\n" ) ] = '\0';

The function find_track should be declared at least like

void find_track( const char *search_for);

Though it is a bad idea when a function definition relies on global variables.

Also the approach of finding relevant strings is not good. For example the user can enter a string that contains only one character 'a'. In this case all records will satisfy the condition. You should check that the searched string forms a word (a sequence of characters separated by spaces) in a string in the array.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335