Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using strtok in c

Tags:

c

strtok

I need to use strtok to read in a first and last name and seperate it. How can I store the names where I can use them idependently in two seperate char arrays?

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

int main ()
{
  char str[] ="test string.";
  char * test;
  test = strtok (str," ");
  while (test != NULL)
  {
    printf ("%s\n",test);
    test= strtok (NULL, " ");
  }
  return 0;
}
like image 300
shinjuo Avatar asked Nov 12 '11 18:11

shinjuo


People also ask

What does strtok () do in C?

The C function strtok() is a string tokenization function that takes two arguments: an initial string to be parsed and a const -qualified character delimiter. It returns a pointer to the first character of a token or to a null pointer if there is no token.

Why is strtok used?

The strtok function is used to tokenize a string and thus separates it into multiple strings divided by a delimiter. The first call to strtok returns the pointer to the first substring. All the next calls with the first argument being NULL use the string passed at the first call and return the next substring.

Can strtok be used with string?

Splitting a string using strtok() in C In C, the strtok() function is used to split a string into a series of tokens based on a particular delimiter. A token is a substring extracted from the original string.

Why do we use null in strtok in C?

The first call to strtok must pass the C string to tokenize, and subsequent calls must specify NULL as the first argument, which tells the function to continue tokenizing the string you passed in first. The return value of the function returns a C string that is the current token retrieved.


2 Answers

Here is my take at a reasonably simple tokenize helper that

  • stores results in a dynamically growing array
  • null-terminating the array
  • keeps the input string safe (strtok modifies the input string, which is undefined behaviour on a literal char[], at least I think in C99)

To make the code re-entrant, use the non-standard strtok_r

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

char** tokenize(const char* input)
{
    char* str = strdup(input);
    int count = 0;
    int capacity = 10;
    char** result = malloc(capacity*sizeof(*result));

    char* tok=strtok(str," "); 

    while(1)
    {
        if (count >= capacity)
            result = realloc(result, (capacity*=2)*sizeof(*result));

        result[count++] = tok? strdup(tok) : tok;

        if (!tok) break;

        tok=strtok(NULL," ");
    } 

    free(str);
    return result;
}

int main ()
{
    char** tokens = tokenize("test string.");

    char** it;
    for(it=tokens; it && *it; ++it)
    {
        printf("%s\n", *it);
        free(*it);
    }

    free(tokens);
    return 0;
}

Here is a strtok-free reimplementation of that (uses strpbrk instead):

char** tokenize(const char* str)
{
    int count = 0;
    int capacity = 10;
    char** result = malloc(capacity*sizeof(*result));

    const char* e=str;

    if (e) do 
    {
        const char* s=e;
        e=strpbrk(s," ");

        if (count >= capacity)
            result = realloc(result, (capacity*=2)*sizeof(*result));

        result[count++] = e? strndup(s, e-s) : strdup(s);
    } while (e && *(++e));

    if (count >= capacity)
        result = realloc(result, (capacity+=1)*sizeof(*result));
    result[count++] = 0;

    return result;
}
like image 113
sehe Avatar answered Oct 02 '22 14:10

sehe


Do you need to store them separately? Two pointers into a modified char array will yield two separate perfectly usable strings.

That is we transform this:

char str[] ="test string.";

Into this:

char str[] ="test\0string.";
             ^     ^
             |     |
char *s1 -----     |
char *s2 -----------

.

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

int main ()
{
  char str[] ="test string.";
  char *firstname = strtok(str, " ");
  char *lastname = strtok(NULL, " ");
  if (!lastname)
    lastname = "";
  printf("%s, %s\n", lastname, firstname);
  return 0;
}
like image 42
u0b34a0f6ae Avatar answered Oct 02 '22 14:10

u0b34a0f6ae