0

I am using user input to control a program. I have two arrays.

The first is a 1-D char array called controlWord (this will store the users input).

The second is a 2-D array called promptWord (an array of char arrays containing words which correspond to actions the code will preform)

char controlWord[100]; //control word compare it to promptWord
char promptWord[5][100]={"Add","Subtract","Multiply","Divide","?"}; //for program control

When the user is prompted for input I use gets() to save the input into the first char array. Then I go and compare this char array to the second char array full of the potential prompt words the user might enter.

printf("\n\ncontrolword: ");
gets(controlWord);

if (strcmp(controlWord, promptWord[0]))//Add
{
  //stuff
}else if (strcmp(controlWord, promptWord[1]))//Listen
{
  //more stuff
}else 

I don't want to search for a substring. I only want exact matches. Even after carefully inputting strings that should work I am getting an error. (especially with '?')

Edit: As noted here "gets/fgets store the newline char, '\n' in the buffers also. If you compared the user input to a string literal such as "abc" it would never match"

So now I have a catch 22: I can use gets() which is considered bad practice, or I can use fgets() which will grab a new line character. I suppose I could go in and null out the last non-zero character, but what if my input is exactly 99 or 100 char long? I only have room for the first 100 char in my char array so how would I know if I had 99 char + a new line or 100 char and I lost the new line?

I'm looking for a solution which avoids gets but is more elegant than the fgets searching for a null character.

Community
  • 1
  • 1
  • 1
    First, read [man gets](https://linux.die.net/man/3/gets): "Never use gets()". Next, read your C text book or search for how to compare strings in C (hint: it's not with `==`). – kaylum Dec 12 '16 at 02:41
  • 2
    Possible duplicate of [How do I properly compare strings in C?](http://stackoverflow.com/questions/8004237/how-do-i-properly-compare-strings-in-c) – kaylum Dec 12 '16 at 02:44
  • @kaylum Thanks! This [answer](http://stackoverflow.com/a/8004271/7126924) from the question you linked helps but also explains that both gets()/fgets() is going to grab the new line character and thus fail when I try to compare to a string literal. I'm gonna edit my question – Andrew Myers Dec 12 '16 at 03:03
  • No, `gets` does not store the new line character. Only `fgets` does. – kaylum Dec 12 '16 at 03:04
  • @kaylum I don't have a c text book. Care to recommend a good one? – Andrew Myers Dec 12 '16 at 03:04
  • [The Definitive C Book Guide and List](http://stackoverflow.com/questionsa/562303/the-definitive-c-book-guide-and-list) – kaylum Dec 12 '16 at 03:05
  • @kalum Then its a catch 22. I shouldn't use `gets()` because its bad practice but `fgets()` causes another problem. Should I just null the last not empty character? – Andrew Myers Dec 12 '16 at 03:07
  • It's not really a problem. Yes, you can just NUL out the last character if you don't want that. Not really a show stopper is it? – kaylum Dec 12 '16 at 03:09
  • @kaylum its not that I don't want that. Its that it will always fail otherwise lol. And yea that's defiantly the least elegant solution, so I don't mind gritty solutions I'm all for what ever works, but then I'm still writing bad code which I don't want to do. – Andrew Myers Dec 12 '16 at 03:15
  • It's not bad code. It's pretty standard thing to do in C. You can always write a function that does that for you if you think that will be "nicer". – kaylum Dec 12 '16 at 03:26
  • @kaylum Well since it seems that a significant portion of this wasn't answered by the other question do you want to move all of your comments (including all the links) into an answer so I can accept it? (the stuff about searching for a new line is novel and isn't a duplicate from the other answer since this is comparing to a string literal ) – Andrew Myers Dec 12 '16 at 03:37
  • @AndrewMyers, have you used `getchar()` before? you can read one character at a time, but definetly requires more effort to parse user input. Although `fgets` is the better option. – RoadRunner Dec 12 '16 at 05:02
  • 3
    `str[strcspn(str, "\n")] = '\0';` will get rid of a trailing newline. – melpomene Dec 12 '16 at 05:02

1 Answers1

2

I suggest using fgets for this problem.

You can handle the \n issue like this:

if (controlWord[slen-1] == '\n') {
    controlWord[slen-1] = '\0';

Whereby you search for the \n, and then if it exists in the correct location, n-1, replace it with a null-terminating character \0, which marks the end of a string. If this is isn't the case, then there will be buffer overflow.

You can also use the clever way highlighted from @melpomene in the comments above:

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

Here is a basic example that will help you achieve your task:

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

#define CONTROL_LEN 100
#define NUM_COMMANDS 5

int
main(int argc, char *argv[]) {
    char controlWord[CONTROL_LEN+1]; 
    char promptWord[NUM_COMMANDS][CONTROL_LEN]={"Add","Subtract","Multiply","Divide","?"}; 
    size_t slen, i;
    int found = 0;

    printf("controlword: ");
    if (fgets(controlWord, CONTROL_LEN, stdin) == NULL) {
        printf("Error reading command.\n");
        return 1;
    }

    slen = strlen(controlWord);

    if (slen > 0) {
        if (controlWord[slen-1] == '\n') {
            controlWord[slen-1] = '\0';
        } else {
            printf("Error: Exceeded Buffer length of %d.\n", CONTROL_LEN);
            return 1;
        }
    }

    if (!*controlWord) {
        printf("Error: No command entered.\n");
        return 1;
    }

    for (i = 0; i < NUM_COMMANDS; i++) {
        if (strcmp(controlWord, promptWord[i]) == 0) {
            found = 1;
        } 
    }

    if (found) {
        printf("Match found for command: %s\n", controlWord);
    } else {
        printf("No match found for command: %s\n", controlWord);
    }

    return 0;
}
RoadRunner
  • 25,803
  • 6
  • 42
  • 75