How to split a string to 2 strings in C
Asked Answered
H

8

44

I was wondering how you could take 1 string, split it into 2 with a delimiter, such as space, and assign the 2 parts to 2 separate strings. I've tried using strtok() but to no avail.

Highpressure answered 26/3, 2010 at 13:17 Comment(5)
mostly because strings dont exist they are char arrays, you will find it difficult to split a string in CLipps
Show us your strtok() attempt.Slype
When you say, "I've tried using strtok(); but to no avail", why exactly didn't it work? What was the problem you ran into?Pin
Can you show your code using strtok()?Partnership
Duplicate: stackoverflow.com/questions/2523624Stephanystephen
L
65
#include <string.h>

char *token;
char line[] = "SEVERAL WORDS";
char *search = " ";


// Token will point to "SEVERAL".
token = strtok(line, search);


// Token will point to "WORDS".
token = strtok(NULL, search);

Update

Note that on some operating systems, strtok man page mentions:

This interface is obsoleted by strsep(3).

An example with strsep is shown below:

char* token;
char* string;
char* tofree;

string = strdup("abc,def,ghi");

if (string != NULL) {

  tofree = string;

  while ((token = strsep(&string, ",")) != NULL)
  {
    printf("%s\n", token);
  }

  free(tofree);
}
Liles answered 26/3, 2010 at 13:22 Comment(9)
strtok() modifies its input, so using it on a string literal is bad juju (a.k.a undefined behavior).Pin
@ereOn: Perhaps you missed the point. Your example is passing a pointer to a string literal, therefore strtok() will be modifying the string literal and invoking UB.Slype
My point was to demonstrate the basic use of strtok(). Well, I admit that using string literals in this situation is a bad pratice and should be avoided. Fun fact: if you look at cplusplus.com/reference/clibrary/cstring/strtok you can see the same "mistake" in the example.Liles
I think if you change char *line = "SEVERAL WORDS" to char line[] = "SEVERAL WORDS", you're all set.Slype
If this is true, I just learned something. I thought those two instructions had the same meaning. My bad.Liles
@ereOn: Pointers and arrays are different things in C, until you sneeze near an array, and then it turns into a pointer. That's how the array size expression sizeof(arr)/sizeof(arr[0]) works.Haplography
strtok() is obsoleted? WOW! strsep() is not even Standard C.Buyer
@Liles Is it normal that strtok and strsep are throwing error signals ? Is there a way to avoid errors ? None of the code above worked without errors for me.Dichlorodifluoromethane
@mini-me: I never heard of error signals using those functions. You probably should ask your own question (referring to this one, if it is relevant).Liles
A
13

For purposes such as this, I tend to use strtok_r() instead of strtok().

For example ...

int main (void) {
char str[128];
char *ptr;

strcpy (str, "123456 789asdf");
strtok_r (str, " ", &ptr);

printf ("'%s'  '%s'\n", str, ptr);
return 0;
}

This will output ...

'123456' '789asdf'

If more delimiters are needed, then loop.

Hope this helps.

Antimatter answered 26/3, 2010 at 13:25 Comment(2)
What's the difference betwen strtok_r() and strtok()?Inguinal
strtok_r() is the reentrant version of strtok(). More about reentrancy here: en.wikipedia.org/wiki/Reentrant_%28subroutine%29Liles
O
4
char *line = strdup("user name"); // don't do char *line = "user name"; see Note

char *first_part = strtok(line, " "); //first_part points to "user"
char *sec_part = strtok(NULL, " ");   //sec_part points to "name"

Note: strtok modifies the string, so don't hand it a pointer to string literal.

Ouachita answered 26/3, 2010 at 13:23 Comment(0)
P
3

You can use strtok() for that Example: it works for me

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

int main ()
{
    char str[] ="- This, a sample string.";
    char * pch;
    printf ("Splitting string \"%s\" into tokens:\n",str);
    pch = strtok (str," ,.-");
    while (pch != NULL)
    {
        printf ("%s\n",pch);
        pch = strtok (NULL, " ,.-");
    }
    return 0;
}
Pulsate answered 26/3, 2010 at 13:23 Comment(0)
M
2

If you have a char array allocated you can simply put a '\0' wherever you want. Then point a new char * pointer to the location just after the newly inserted '\0'.

This will destroy your original string though depending on where you put the '\0'

Mydriasis answered 26/3, 2010 at 13:22 Comment(0)
Y
1

If you're open to changing the original string, you can simply replace the delimiter with \0. The original pointer will point to the first string and the pointer to the character after the delimiter will point to the second string. The good thing is you can use both pointers at the same time without allocating any new string buffers.

Yeargain answered 26/3, 2010 at 13:21 Comment(1)
Although I seem to understand the answer, a simple example would help a lot. For example, a beginner may ask: how to get both these pointers?Latarsha
V
1

You can do:

char str[] ="Stackoverflow Serverfault";
char piece1[20] = ""
    ,piece2[20] = "";
char * p;

p = strtok (str," "); // call the strtok with str as 1st arg for the 1st time.
if (p != NULL) // check if we got a token.
{
    strcpy(piece1,p); // save the token.
    p = strtok (NULL, " "); // subsequent call should have NULL as 1st arg.
    if (p != NULL) // check if we got a token.
        strcpy(piece2,p); // save the token.
}
printf("%s :: %s\n",piece1,piece2); // prints Stackoverflow :: Serverfault

If you expect more than one token its better to call the 2nd and subsequent calls to strtok in a while loop until the return value of strtok becomes NULL.

Verbenaceous answered 26/3, 2010 at 13:27 Comment(1)
Looks good, except the second strtok() call is using a different delimiter.Pin
O
1

This is how you implement a strtok() like function (taken from a BSD licensed string processing library for C, called zString).

Below function differs from the standard strtok() in the way it recognizes consecutive delimiters, whereas the standard strtok() does not.

char *zstring_strtok(char *str, const char *delim) {
    static char *static_str=0;      /* var to store last address */
    int index=0, strlength=0;       /* integers for indexes */
    int found = 0;                  /* check if delim is found */

    /* delimiter cannot be NULL
    * if no more char left, return NULL as well
    */
    if (delim==0 || (str == 0 && static_str == 0))
        return 0;

    if (str == 0)
        str = static_str;

    /* get length of string */
    while(str[strlength])
        strlength++;

    /* find the first occurance of delim */
    for (index=0;index<strlength;index++)
        if (str[index]==delim[0]) {
            found=1;
            break;
        }

    /* if delim is not contained in str, return str */
    if (!found) {
        static_str = 0;
        return str;
    }

    /* check for consecutive delimiters
    *if first char is delim, return delim
    */
    if (str[0]==delim[0]) {
        static_str = (str + 1);
        return (char *)delim;
    }

    /* terminate the string
    * this assignmetn requires char[], so str has to
    * be char[] rather than *char
    */
    str[index] = '\0';

    /* save the rest of the string */
    if ((str + index + 1)!=0)
        static_str = (str + index + 1);
    else
        static_str = 0;

        return str;
}

Below is an example code that demonstrates the usage

  Example Usage
      char str[] = "A,B,,,C";
      printf("1 %s\n",zstring_strtok(s,","));
      printf("2 %s\n",zstring_strtok(NULL,","));
      printf("3 %s\n",zstring_strtok(NULL,","));
      printf("4 %s\n",zstring_strtok(NULL,","));
      printf("5 %s\n",zstring_strtok(NULL,","));
      printf("6 %s\n",zstring_strtok(NULL,","));

  Example Output
      1 A
      2 B
      3 ,
      4 ,
      5 C
      6 (null)

You can even use a while loop (standard library's strtok() would give the same result here)

char s[]="some text here;
do {
    printf("%s\n",zstring_strtok(s," "));
} while(zstring_strtok(NULL," "));
Overword answered 18/2, 2016 at 23:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.