Search code examples
csegmentation-faulttokenize

How to tokenize input for variable amount of words


In here I am trying to tokenize the user input e.g. load sml.txt. The load command works fine because it has 2 tokens, but if I try to use a single word input like display, it crashes and gives me a segfault. I assume its because the second token is NULL, but I have no idea how to circumvent this issue. Can you help?

For your reference COMMAND_LOAD = "load" and COMMAND_DISPLAY = "display".

int main(int argc, char **argv)
{
    AddressBookList *addressBookList;
    char input[BUFSIZ];
    char load[BUFSIZ];
    char fileN[BUFSIZ];
    char *fileName;
    char *token;
    showStudentInformation();
    do
    {
        printf("Enter your command: \n");
        fgets(input, sizeof(input), stdin);
        input[strlen(input) - 1] = '\0';
        token = strtok(input, " ");
        strcpy(load, token);
        token = strtok(NULL, " ");
        strcpy(fileN, token);
        fileName = fileN;
        if (strcmp(load, COMMAND_LOAD) == 0)
        {
            addressBookList = commandLoad(fileName);
        }
        else if (strcmp(load, COMMAND_UNLOAD) == 0)
        {
            /*commandUnload(fileName);*/
        }
        else if (strcmp(load, COMMAND_DISPLAY) == 0)
        {
            if (fileN == NULL)
            {
                printf("> No file loaded");
            }
            else
            {
                commandDisplay(addressBookList);
            }
        }
        else
        {
            printf("> Invalid input\n\n");
        }
    } while (strcmp(load, COMMAND_QUIT) != 0);
    return EXIT_SUCCESS;
}

Solution

  • strtok() returns NULL when there's no more tokens, you can check for this. If there's no token, I empty the target string by assigning '\0' to the first character, instead of calling strcpy().

    do
    {
        printf("Enter your command: \n");
        fgets(input, sizeof(input), stdin);
        token = strtok(input, " \n");
        if (token) {
            strcpy(load, token);
        } else {
            load[0] = '\0';
        }
        token = strtok(NULL, " \n");
        if (token) {
            strcpy(fileN, token);
        } else {
            fileN[0] = '\0';
        }
        ...
    } while (strcmp(load, COMMAND_QUIT) != 0);
    

    There's also no need to replace the last character in the string with \0. Just include \n in the strtok() delimiters, so it won't include the newline at the end in the token.