7

I want to split a string into tokens and save data into variables. I have the following string:

John|Doe|Melbourne|6270|AU

I need to split it by | and every token keep as variable so I can use them in my program, like:

fname = "John"
lname = "Doe"
city = "Melbourne"
zip = "6270"
country = "AU"

tried this so far, I can access first token the rest I don't know how (besides a while loop that doesn't help me):

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

int main (void) {
char str[] = "John|Doe|Melbourne|6270|AU";

strtok(str, "|");

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

5 Answers 5

13
    char fname[32], lname[32], city[32], zip[32], country[32];

    strcpy(fname, strtok(str , "|"));
    strcpy(lname, strtok(NULL, "|"));
    strcpy(city , strtok(NULL, "|"));
    strcpy(zip , strtok(NULL, "|"));
    strcpy(country, strtok(NULL, "|"));

    printf("%s\n", fname);
    printf("%s\n", lname);
    printf("%s\n", city);
    printf("%s\n", zip);
    printf("%s\n", country);
3
  • I like this answer with strtok() so I can use multiple delimiters not just |
    – bsteo
    Jun 13, 2013 at 11:03
  • A good solution for the problem. There is no need for a loop in this case. One thing though, seen as you know the buffer lenght on all of the character variables it might be better to use strncpy.
    – Will
    Jun 13, 2013 at 11:33
  • 1
    Uh, how is this possible? After the first strcpy, there's no reference to str. .. wtf? Feb 5, 2019 at 20:57
6

If the format is constant, you can use sscanf():

char fname[32], lname[32], city[32], zip[16], country[8];

if(sscanf(str, "%31[^|]|%31[^|]|%31[^|]|%15[^|]%7s",
               fname, lname, city, zip, country) == 5)
{
}

This uses the %[] character set format specifier to grab "everything except a vertical bar". The width is included to prevent buffer overruns.

1
  • @collaborator Good point, I was under the impression that sscanf() will terminate the returned strings, though. My reading of the manual page supports that view.
    – unwind
    Jun 13, 2013 at 11:13
4

just keep on calling strtok

char* name = strtok(str, "|");
char* surname = strtok(NULL, "|");
...
3

strtok returns a pointer to the token; pass NULL as the first argument to retrieve successive tokens:

#define FIELD_LENGTH 20
#define NUM_FIELDS    5
...
char target[NUM_FIELDS][FIELD_LENGTH];
int field = 0;
...
while ( get_next_string( str )) // where get_next_string retrieves your next
{                                // delimited string
  char *token = strtok( str, "|" );
  while ( token )
  {
    strcpy( target[i++], token );
    token = strtok( NULL, "|" );
  }
}

Edit

To address Golgauth's comment, there are some important things to remember about using strtok:

  • It modifies the input string by replacing each occurrence of the delimiter with a 0, meaning it cannot be used on a string literal. If you want to preserve the original string, you will have to make a copy to pass to strtok;
  • It uses a single, static buffer to store the string it's modifying, making it non-reentrant - if multiple threads make calls to strtok to tokenize different strings, they'll wind up stepping on each other (this is known as a race condition, where the behavior of the program depends on which thread gets access to something first). Also, you can't nest calls to strtok (that is, get a token, then split it into subtokens, then get the next token);

The online 2011 standard mentions a safer (and IINM re-entrant) alternative, strtok_s, as part of Annex K (Bounds-checking interfaces); some implementations also provide a strtok_rfunction which is re-entrant.

2
  • strtok is deprecated, isn't it ? Jun 13, 2013 at 11:02
  • @Golgauth: not according to the [online 2011 draft](www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf).
    – John Bode
    Jun 13, 2013 at 13:15
2

You can use sscanf with that (it can scan strings up to a given delimiter)

int n; 
char fname[128]= "", lname[128]= "", city[128]= "", zipcode[128]= "", country[128]= "";
n= sscanf str("%127[^|]|%127[^|]|%127[^|]|%127[^|]|%127s", fname, lname, city, zipcode, country); 
if (n==5) {  // five fields scanned

}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.