fjidsanfklxingdwsf fjidsanfklxingdwsf - 11 months ago 45
C Question

how can I parse a string like this (6,8)

I want to parse a string in a format as (6,8), and I want to store 6 and 8 in different variable. I'm trying to use the "strtok". However it gives me a segfault

here is my code

int main()
char a[80]="(6,8)";

return 0;

int parsing(char* a)
char* word;
char temp[80] ;
char* new;
char **newendptr=NULL;
char **newnewendptr=NULL;

int u,v;
word= strtok(temp, "(");
word= strtok(NULL, ",");


new= strtok(NULL, ")");

printf("%d %d",u,v);
return 1;

Answer Source

It pays to read the specification of strtok() carefully.

This code works:

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

static int parsing(char *a)
    char temp[80];
    strcpy(temp, a);

    printf("temp 0 = %p [[%s]]\n", (void *)temp, temp);
    char *word1 = strtok(temp, "(,)");
    printf("word 1 = %p [[%s]]\n", (void *)word1, word1 == 0 ? "<nothing>" : word1);
    char *word2 = strtok(NULL, "(,)");
    printf("word 2 = %p [[%s]]\n", (void *)word2, word2 == 0 ? "<nothing>" : word2);

    int u = strtoumax(word1, 0, 0);
    int v = strtoumax(word2, 0, 0);
    printf("%d %d\n", u, v);
    return 1;

int main(void)
    char a[80] = "(6,8)";
    return 0;

The output on my machine is:

temp 0 = 0x7fff54844440 [[(6,8)]]
word 1 = 0x7fff54844441 [[6]]
word 2 = 0x7fff54844443 [[8]]
6 8

The problem is that the call to strtok() in the original with "(" as delimiter skips over the opening (, but then doesn't find another to mark the end of the token, so the rest of the string is consumed. The second call to strtok() therefore has nothing to process and returns NULL.

The fixed code avoids that problem. The initial delimiter must include ( to skip that, and must include , to stop there. The second delimiter should include ); the other characters are not strictly needed.

Since you aren't inspecting the output pointer that's the second argument to strtoumax(), it may as well be NULL (aka 0) each time. Using strtoumax() and assigning the result to an int is a little odd. With the given data, it is OK, but more generally, it risks losing important information. The strtoX() functions are quite powerful but also remarkably delicate in how they report out of bounds values, etc. This usage throws away all that information (and you'd need to set errno to 0 before calling it, and you'd have to save the values in uintmax_t variables, to get and preserve the information accurately).

In this context, a more succinct (but not necessarily simpler) way to parse the input string would be:

char c;
if (sscanf(a, " (%d ,%d %c", &u, &v, &c) != 3 || c != ')')
    …oops — malformatted data…

Make sure you know why the spaces are present and why they are where they are. That may require careful scrutiny of the POSIX specification for sscanf(). You can decide to do without the spaces; you need to know what the consequences of doing so are. If you want to be sure that the whole string was parsed, use:

char c;
int n;
if (sscanf(a, " (%d ,%d %c%n", &u, &v, &c, &n) != 3 || c != ')' || temp[n] != '\0')

Note that %n conversion specifications are not counted so the 3 does not change.