1

I'm pretty new to C but I'm experienced in python, I'm trying to check whether an input string contains a certain word in it for a example a mood checker

char str[20];
    printf("How are you feeling right now");
    scanf("%c", str); 

this is how I receive the input. I want to be able to tell if the string contains either the words "good" or "tired" and return an output accordingly

so for example in python

 If "good" in str:
        print("I'm glad to hear that")
 elif "tired" in str:
        print("Don't worry, today will end soon and you'll get to bed and sleep well.")

I succeeded in checking for a single character but not for a whole word\substring.

I cant seem to find a way to do this in C Thanks in advance for any help

I tried using the strstr(word, string) function and didnt realize how the syntax works I also tried using switch() and case() expected both to work but nothing did

6
  • 2
    strstr is the correct way, but what was your difficulty to use it? Commented Nov 5, 2024 at 16:21
  • 1
    It sounds like you already found the function you want, strstr. You want to check strstr(str, "good") != NULL. If that doesn't work it's probably becuse scanf("%c") reads a single character, not a string. You probably want to use getline for that. Commented Nov 5, 2024 at 16:22
  • this is my code: Commented Nov 5, 2024 at 16:22
  • 2
    scanf("%c", str); will write no more than a single character into str. After that, str may not be null terminated, and any attempt to pass str to a function that expects a null terminated string results in undefined behavior. Commented Nov 5, 2024 at 16:49
  • @GiacomoCatenazzi they simply used the parameters the wrong way. strstr(word, string) should be strstr(string, word) Commented Nov 5, 2024 at 17:56

3 Answers 3

4

You'll need #include <string.h> to use strstr().
fgets() can read string value with spaces so you can try that.

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

int main() {
    char str[100];
    printf("How are you feeling right now? ");
    fgets(str, sizeof(str), stdin);

    if (strstr(str, "good") != NULL)
        printf("I'm glad to hear that!\n");
    else if (strstr(str, "tired") != NULL)
        printf("Take some rest!\n");
    else
        printf("Thank you for sharing.\n");

    return 0;
}
Sign up to request clarification or add additional context in comments.

Comments

2

strstr is the easy, obvious answer, though you probably want to lowercase your input string first to do a case-insensitive search.

You may also want to consider checking to see if a word matches one of those terms. Otherwise a word like "retired" would trigger a response. That is somewhat more difficult since you need to take word boundaries into account.

A reasonably straightforward way to accomplish this would be to tokenize on whitespace and iterate over those tokens. You'll also want to remove punctuation (from the beginning and end of each word) and lowercase each word.

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

int main(void) {
    char input[1024] = "";
    
    printf("How are you feeling right now? ");
    if (!fgets(input, sizeof(input), stdin)) {
        fprintf(stderr, "Oops. I didn't hear from you.\n");
        return 1;
    }

    char *tok;
    for (tok = strtok(input, " "); tok; tok = strtok(NULL, " ")) {
        // Downcase token
        for (char *ch = tok; *ch; ch++) {
            *ch = tolower(*ch);
        }

        // Remove leading punctuation
        for (char *ch = tok; *ch; ch++) {
            if (isalpha(*ch) || isdigit(*ch)) {
                tok = ch;
                break;
            }
        }

        // Remove trailing punctuation
        for (char *ch = tok + strlen(tok) - 1; ch >= tok; ch--) {
            if (isalpha(*ch) || isdigit(*ch)) {
                ch[1] = '\0';
                break;   
            }
        } 

        if (strcmp(tok, "good") == 0) {
            printf("I'm glad to hear that!\n");
            break;
        }
        else if (strcmp(tok, "tired") == 0) {
            printf("Take some rest!\n");
            break;
        }
    }

    / tok will be NULL if we reached the end of the input
    // without finding a match.
    if (tok == NULL) {
        printf("Thank you for sharing.\n");
    }
}

Testing:

% ./a.out                            
How are you feeling right now? Hello! Good!
I'm glad to hear that!

For the sake of flexibility, we could take this and replace the hard-coded tests for "good" and "tired" with a lookup table. This readily allows us to add other tests without having to rewrite later code.

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

typedef struct Response {
    char *word;
    char *response;
} Response;

int main(void) {
    Response responses[] = {
        {"good", "I'm glad to hear that!"},
        {"tired", "Take some rest!"}
    };
    size_t num_responses = sizeof(responses) / sizeof(responses[0]);

    char input[1024] = "";
    
    printf("How are you feeling right now? ");
    if (!fgets(input, sizeof(input), stdin)) {
        fprintf(stderr, "Oops. I didn't hear from you.\n");
        return 1;
    }

    char *tok;
    for (tok = strtok(input, " "); tok; tok = strtok(NULL, " ")) {
        // Downcase token
        for (char *ch = tok; *ch; ch++) {
            *ch = tolower(*ch);
        }

        // Remove leading punctuation
        for (char *ch = tok; *ch; ch++) {
            if (isalpha(*ch) || isdigit(*ch)) {
                tok = ch;
                break;
            }
        }

        // Remove trailing punctuation
        for (char *ch = tok + strlen(tok) - 1; ch >= tok; ch--) {
            if (isalpha(*ch) || isdigit(*ch)) {
                ch[1] = '\0';
                break;   
            }
        } 

        size_t i;
        for (i = 0; i < num_responses; i++) {
            if (strcmp(tok, responses[i].word) == 0) {
                printf("%s\n", responses[i].response);
                break;
            }
        }

        // Test to see if a match was found.
        if (i < num_responses) {
            break;
        }
    }

    if (tok == NULL) {
        printf("Thank you for sharing.\n");
    }
}

A further refinement would be to break some of the logic cluttering your loop out into functions.

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

typedef struct Response {
    char *word;
    char *response;
} Response;

void downcase(char *str);
void strip_leading(char *str);
void strip_trailing(char *str);
char *lookup_response(char *word, Response *responses, size_t n);

int main(void) {
    Response responses[] = {
        {"good", "I'm glad to hear that!"},
        {"tired", "Take some rest!"}
    };
    size_t num_responses = sizeof(responses) / sizeof(responses[0]);

    char input[1024] = "";
    
    printf("How are you feeling right now? ");
    if (!fgets(input, sizeof(input), stdin)) {
        fprintf(stderr, "Oops. I didn't hear from you.\n");
        return 1;
    }

    char *tok;
    for (tok = strtok(input, " "); tok; tok = strtok(NULL, " ")) {
        downcase(tok);
        strip_leading(tok);
        strip_trailing(tok);
        char *response = lookup_response(tok, responses, num_responses);

        if (response) {
            printf("%s\n", response);
            break;
        }
    }

    if (tok == NULL) {
        printf("Thank you for sharing.\n");
    }
}

void downcase(char *str) {
    for (char *ch = str; *ch; ch++) {
        *ch = tolower(*ch);
    }
}

void strip_leading(char *str) {
    for (char *ch = str; *ch; ch++) {
        if (isalpha(*ch) || isdigit(*ch)) {
            tok = ch;
            break;
        }
    }
}

void strip_trailing(char *str) {
    for (char *ch = str + strlen(str) - 1; ch >= str; ch--) {
        if (isalpha(*ch) || isdigit(*ch)) {
            ch[1] = '\0';
            break;   
        }
    }
}

char *lookup_response(char *word, Response *responses, size_t n) {
    for (i = 0; i < n; i++) {
        if (strcmp(word, responses[i].word) == 0) {
            return responses[i].response;
        }
    }

    return NULL;
}

You could also look at including a regular expression library, but that seems like overkill in this kind of case.

1 Comment

Calling tolower, isalpha or isdigit with a negative argument will invoke undefined behavior (unless that argument is equal to EOF). Therefore, it would be safer to cast the argument to unsigned char or to change the type of the pointer to unsigned char *.
1

You can use the strstr function, a standard library function that searches for a substring within a string.

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

int main() {
    char str[100];
    printf("Please say to me 'hello'!");
    fgets(str, sizeof(str), stdin);

    // Check for the presence of the words "hello"
    if (strstr(str, "hello") != NULL) {
        printf("I'm glad to hear that.\n");
    } else {
        printf("say again 'hello'.\n");
    }

    return 0;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.