strtok() returning null when it shouldn´t

86 views Asked by At

I made a function that receives a string and it should return the element after "-e". For example, "show -e LENA" should return "LENA".

char *getElementAfterE(char *str) {
  const char *delimiter = " ";
  const char *flag = "-e";
  char *result = NULL;

  char *token = strtok(str, delimiter); // Get the first token

  while (token != NULL) {
    if (strcmp(token, flag) == 0) {
      token = strtok(NULL, delimiter); // Get the next token
      printf("next token: %s\n", token);
      if (token != NULL) {
        result = token;
      }
      break;
    }

    token = strtok(NULL, delimiter); // Get the next token
  }
  return result;
}

The problem is that the strtok after the if allways returns null even when the string still has tokens left.

Aparently it has to do with the string i give to the function. If i use a pointer it doesnt work:

char *str = "show -e LENA";
char *result = getElementAfterE(str);

If i use a char array it works:

char str[] = "show -e LENA";
char *result = getElementAfterE(str);

The problem is that in my program i'm giving it a pointer. Do i need to copy my pointer into a char array before giving it to the function?

2

There are 2 answers

0
ikegami On

strtok modifies the provided string. It basically replaces the delimiters with NULs in order to create a proper string to return without allocating any memory.

You are passing a string literal. Modifying a string literal is Undefined Behaviour.

Using char str[] = "show -e LENA"; instead creates an modifiable array.

The string does not need to be in an array, but it does need to be modifiable.

0
John Bollinger On

If i use a pointer it doesnt work [, but] If i use a char array it works

It's not about pointer vs. array. It's about modifiable objects vs. unmodifiable ones.

strtok() modifies the source string as it works, and the tokens it returns share storage with the original string. This works fine when the source pointer you provide to it is derived from a declared array of type char. It also works fine with a pointer to a string stored in dynamically-allocated space. In principle, it works with a pointer to the representation of any modifiable object whose representation contains a null byte.

But for historical reasons, even though string literals represent arrays of (non-const) char, programs are forbidden from attempting to modify them. This means that a pointer (in)to a string literal is not an acceptable first argument to strtok(), even though it may be type-correct. Attempting to use one in that way evokes undefined behavior, and you have observed an effect of that.

To avoid issues such as this, it helps to be avoid associating string literals with pointers to char. Instead, associate them with pointers to const char:

const char *str = "show -e LENA";

This is better reflective of the actual semantics, and it will help your compiler help you detect misuse of string literals.

Do i need to copy my pointer into a char array before giving it to the function?

If you receive the string to parse as a string literal, and you want to parse the contents via strtok(), then yes, you need to copy them into a declared or dynamically allocated array first. The same would apply to an array of const char.