Šarūnas Rakauskas
Šarūnas Rakauskas

Reputation: 168

Why strtok() splits string that i didn't even passed to it?

I need to separate string from file. String = "21:12:36 14:45:25 08:17:24" When i do strtok() and put all tokens to array everything works fine, but when I do strtok() second time, it messes everything. Example:

char *p = strtok (code, " ");
while (p != NULL){
    dal[i++] = p;
    p = strtok (NULL, " ");
}

Output:

dal[0] = 21:12:36
dal[1] = 14:45:25
dal[2] = 08:17:24

I do copy of dal array, and when I do strtok for second time i changes my original string(code) and my copy of dal even I pass dal array only to strtok(). I tried to send dal to LinkedList, but after second strtok even LinkedList is changed.

Declaration:

char *dal[20], *dalcopy[20];
//copying below
for(int k = 0; k<i; k++){
    dalcopy[v] = dal[k];
    v = v+1;
}

Example:

for (int j = 0; j<i; j++){
    char *o = strtok(dal[j], ":");
    while (o != NULL){
        for(int h = 0; h<3; h++){
            if(h == 0){vienas[b].Hour = atoi(o);}
            if(h == 1){vienas[b].Min = atoi(o);}
            if(h == 2){vienas[b].Sec = atoi(o);}
            o = strtok (NULL, ":");
        }            
        b = b+1;
    }

LinkedList example:

char *p = strtok (code, " ");
while (p != NULL){
    dal[i++] = p;
    put(head, p); //puts each element to list end
    p = strtok (NULL, " ");
}
printf("%s\n", show_by_index(&head, 0)); **Output == 21 after second strtok**

Output:

original string = 21
dal[0] = 21
dal[1] = 14
dal[2] = 08
dalcopy[0] = 21
etc...

Why this is happening?

Upvotes: 1

Views: 68

Answers (2)

Spikatrix
Spikatrix

Reputation: 20244

The two main things you've fo keep in mind are:

  1. strtok is a destrutive function as said by @JohnColeman in the comments. This means that strtok modifies the string (first argument) passed to it.
  2. strtok gives you pointers that point to different parts of the string and you store them in the array dal. Now, you create another similar array of pointers dalcopy (assuming you fixed what @David told you) and make them point to the same parts of the string code as dal does.

dal and dalcopy point to the same tokens of the string code. So, any change you make to them will also affect code as they point to it.

Before strtok and everything:

+--------+--------+--------+--------+
| dal[0] | dal[1] | dal[2] | dal[3] | ... = dal
+--------+--------+--------+--------+

+------------------------------+
| "21:12:36 14:45:25 08:17:24" | = code
+------------------------------+

After strtok and "copying":

+--------+--------+--------+--------+
| dal[0] | dal[1] | dal[2] | dal[3] | ... = dal
+--------+--------+--------+--------+
   ↓         ↓          ↓
+---------------------------------+
| "21:12:36\0014:45:25\008:17:24" | = code
+---------------------------------+
   ↑         ↑          ↑
   |          \         \----\
+------------+------------+------------+------------+
| dalcopy[0] | dalcopy[1] | dalcopy[2] | dalcopy[3] | ... = dalcopy
+------------+------------+------------+------------+

As you can see, you were not copying it, but merely creating an alias.

The solution would be to strdup/malloc+strcpy the tokens.

Upvotes: 2

David Schwartz
David Schwartz

Reputation: 182769

char *dal[20], dalcopy[20];
//copying below
for(int k = 0; k<i; k++){
    dalcopy[v] = dal[k];
    v = v+1;
 }

This can't be right. Since dalcopy is an array of characters, dalcopy[v] is a character. But dal[k] is not a character (since dal is an array of pointers to characters), so this assignment makes no sense at all.

Upvotes: 1

Related Questions