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

int main(void) {

    char command[256];
    char *token;
    const char s[2] = " ";

    fprintf(stdout, "$ Please enter a command \n");
    fflush( stdout );

    fgets ( command, 256, stdin );
    token = strtok(command, s);

    if (strcmp(token, "loaddungeon") == 0){
        fprintf(stdout, "$ loaded successfully \n");
        fflush( stdout );
    }
}

I am trying to use strtok to get the second string of the input. For instance, if the input is "loaddungeon dfile.txt", what I want to get is the "dfile.txt". My function is able to get the string "loaddungeon". But I have no idea how to get the second string "dfile.txt". Can anyone tell me how to do it?

(Consider the input is always "loaddungeon dfile.txt".)

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
chenyinuo
  • 89
  • 1
  • 1
  • 6

2 Answers2

1

Every call to strtok will return a pointer to the last token found in the given string (or null if there is none left). To retrieve the second token with space as a delimiter, you need to call strtok for the second time.

int main()
{
    char command[256];
    char *token1 = NULL;
    char *token2 = NULL;
    const char s[2] = " ";
    fprintf(stdout, "$ Please enter a command \n");
    fflush(stdout);
    fgets(command, 256, stdin);
    token1 = strtok(command, s); // now points to first word
    if (NULL != token1) {
        token2 = strtok(NULL, s); // now points to second word
    }
    if (NULL != token2) {
        if (strcmp(token2, "loaddungeon") == 0){
           fprintf(stdout, "$ loaded successfully \n");
           fflush(stdout);
        }
    }
}
Pejman
  • 1,328
  • 1
  • 18
  • 26
  • You need to have two 'token pointers' — maybe `char *operation; char *operand;` — and then use `operation = strtok(command, " \n"); operand = strtok(NULL, " \n");`. I omitted the test; it isn't bad, but it isn't critical. If you continue invoking `strtok(NULL, "…")`, it continues returning null. (Standard says: _The `strtok` function then searches from there for a character that is contained in the current separator string. If no such character is found, the current token extends to the end of the string pointed to by `s1`, and subsequent searches for a token will return a null pointer._ – Jonathan Leffler Jan 18 '17 at 04:48
  • That is a totally valid point. Subsequent calls should almost always happen in a loop. OP however suggested he/she expects two tokens to be present and he/she is seeking only the second one. – Pejman Jan 18 '17 at 04:55
  • 1
    Well, the code compares the first token with `loaddungeon` and then wants to be able to use the second token for the file to be loaded as the dungeon. So I think both are needed. Note that the other answer is using `token1` and `token2` where I'm hypothesizing `operator` and `operand` might be appropriate — but the choice of name is 100% up to you and as long as they're different, it should work. (So, by all means use `z` and `fancy_pants_extra_long_name` — but I'd think you're nearly as weird as me.) – Jonathan Leffler Jan 18 '17 at 04:55
  • My bad. You are right. Sorry I did not pay attention. I just edited my answer. – Pejman Jan 18 '17 at 04:57
1

To read the second string, you need to pass NULL to strtok(). Keep in mind that fgets() retains the newline character from the input line, so you should change your delimiter definition from char s[2] = " "; to char s[] = " \r\n";, or char s* = " \r\n". This way the second token will not include any newline characters. Also note that strtok() returns a NULL pointer if no token is found, so the below code tests for this before printing the read tokens.

But, since you say that there are only two strings, I would consider just using sscanf() for this. Using the %s conversion specifier, sscanf() will read characters into a string until a whitespace character is encountered, but will not include this whitespace character in the string. When you use the %s specifier in a scanf() type function, you should specify a maximum field width to avoid buffer overflow. This maximum width should be one less than the size of the buffer to leave room for the '\0' string terminator, 255 in this case. The sscanf() function returns the number of successful assignments made, which should be 2 in this case. The sscanf() approach shown below (commented out) checks this return value before printing the strings.

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

#define BUFFER_MAX  256

int main(void) {

    char command[BUFFER_MAX];
    char *token1 = NULL;
    char *token2 = NULL;
    const char *s = " \r\n";

    fprintf(stdout, "$ Please enter a command \n");
    fflush( stdout );

    fgets ( command, BUFFER_MAX, stdin );

    token1 = strtok(command, s);
    token2 = strtok(NULL, s);

    if (token1 && token2 && strcmp(token1, "loaddungeon") == 0) {
        fprintf(stdout, "$ loaded successfully: %s\n", token2);
        fflush( stdout );
    }

    /* or instead do this */
/*
    char word1[BUFFER_MAX], word2[BUFFER_MAX];
    if (sscanf(command, "%255s %255s", word1, word2) == 2) {
        if (strcmp(word1, "loaddungeon") == 0){
            fprintf(stdout, "$ loaded successfully: %s\n", word2);
            fflush( stdout );
        }
    }
*/
    return 0;
}
ad absurdum
  • 19,498
  • 5
  • 37
  • 60