user192936
user192936

Reputation:

Why is strtok causing a segmentation fault?

Why does the below code give Seg. Fault at last line?

char* m=ReadName();
printf("\nRead String %s\n",m); // Writes OK
char* token;
token=strtok(m,'-');

As said, read string prints w/o problem, but why cannot split to tokens?

Upvotes: 4

Views: 8506

Answers (5)

fnisi
fnisi

Reputation: 1223

Code below is taken from a BSD licensed string processing library for C, called zString.

https://github.com/fnoyanisi/zString

Looking at the implementation of the function, you can see that strtok() (or in this case zstring_strtok()) relies on a static *char to preserve the last location of the delimiter and actually modifies the original string.

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;
}

This post explains the deifference between char s[] and char *s quite well. So,

char s[]="Test to pass strtok()"; /* this can be passed to strtok() */
char *m="Test to pass strtok()"; /* passing this will result in SIGSEGV */

Upvotes: 0

bk1e
bk1e

Reputation: 24328

token=strtok(m,'-'); should generate a compiler warning because the second parameter of strtok() is a const char * pointing to multiple delimiters, not a single char delimiter:

char *strtok(char *str, const char *delim);

The ASCII code of '-' is 0x2D, so passing it as the second parameter of strtok() will cause strtok() to dereference the address 0x0000002D, which will cause a segfault or access violation on most modern operating systems. To fix this, use a string literal instead of a character literal: token=strtok(m,"-");

There's also the issue of how the return value of ReadName() is allocated, which others have addressed in their answers.

Upvotes: 2

N 1.1
N 1.1

Reputation: 12524

Its probably because ReadName() return string. So, the assignment makes m const char* and hence, you cannot alter any of its values (modify the string). So, when 'strtok' tries to modify 'm', Segmentation Fault is there

Remedy:

char *m = malloc(sizeof(char)*MAX);
strcpy(m, ReadName());

OR

char *m = strdup(ReadName());

Upvotes: 0

codaddict
codaddict

Reputation: 454940

strtok modifies its first argument, hence it should be modifiable.

Maybe ReadName() returns a pointer to a read-only char array.Can you show us your ReadName() function.

If that is the reason for seg-faullt, you can create a copy of the char array before you pass it to strtok using the strdup function like:

char *copy = strdup(m);
token = strtok(copy,'-');
....
....
free(copy); // free the copy once you are done using it.

Upvotes: 18

John Knoeller
John Knoeller

Reputation: 34128

It's impossible to know for sure without knowing what m points to. But the most likely reason is that m is pointing to readonly memory. So you can print it out, but you can't write to it.

strtok writes to the string, so it's faulting, but printf only reads from it, so it isn't.

Try this

char* m=ReadName();
printf("\nRead String %s\n",m); // Writes OK
char temp = m[0];
m[0] = temp; // I'll bet you segfault here.

Upvotes: 0

Related Questions