efoekfoe efoekfoe - 2 months ago 8
C Question

Unexpected Behaviour when using strtok

So I'm given a string as such:

Hello6World66ABC


Where I'm told to replace single instances of the character '6' to be two asteric characters
"**"


And multiple instances of 6's to be two of these characters
"^^"
(Any combinations of the number 6 in a row would qualify.

I'm attempting to do this by passing through each character in a
char *
,then if I find the 6 character, I check if the next character is a 6, if not we have the first case, otherwise we have the second case (Multiple 6's).

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

int main(void) {
char * str;
int i;
str = malloc(17);

strcpy(str,"Hello6World66ABC");

for(i=0; i < strlen(str); i++) {
if(str[i] == '6') {
if(str[i+1] != '6') {
char * token = strtok(str,"6");
strcpy(str,token);
strcat(str,"**");
printf("String is now %s\n",str);

token = strtok(NULL,""); /*get the rest of the string*/ /* should be World66ABC */
printf("Rest of the string is %s\n",token);
str = (char *) realloc(str,strlen(str) + strlen(token) + 1);
strcat(str,token);
printf("String is now %s\n",str);
/* should be Hello**World66ABC */
}
else {
/*if the next characters are also (multiple ones in a row) 6's, replace it with two ^^ characters*/
char * token = strtok(str,"6");
token = strtok(NULL,"6");
printf("TOKEN IS %s\n",token);

strcpy(str,token);
strcat(str,"^^");

token = strtok(NULL,""); /*get the rest of the string*/ /* should be World66ABC */
printf("Rest of the string is %s\n",token);
str = (char *) realloc(str,strlen(str) + strlen(token) + 1);
strcat(str,token);
printf("String is now %s\n",str);


}
}
}

free(str);
return 0;
}


By the string given, My expected final string should be:

Hello**World^^ABC


However, my strtok calls don't work the way I intended.

In the second if statement, where I check
if (str[i+1] != '6')
, I'm checking if there is only a single 6, there is.

Then I call strtok and print everything before it:
it prints:
Hello**


Which is correct
I strcat the new characters on to it which works, however, on my second strtok call, to get the rest of the string, it just doesn't work.

It instead prints:

"Rest of the string is *"


So clearly it's not getting the rest of the string, even though I set the delimiter to be an empty string.

I tried to change the delimiter to be other characters, but each result in the same output. I'm also reallocating because the string gets longer, in the first case. Also the else statement seems to never run, even though I clearly have a case where there are multiple 6's.

I'm not sure where I've gone wrong here, any ideas?

Answer

This is untested, but it shows the general idea.

strcpy(str,"Hello6World66ABC");

// New string will be at most 2x as long
char *new_str = calloc(strlen(str) * 2 + 1, 1);
int new_str_index = 0;

for (int i = 0; 0 != str[i]; i++) {
    // Check for 6
    if ('6' == str[i]) {
        // Check for 2nd 6
        if ('6' == str[i+1]) {
            // Add chars
            new_str[new_str_index++] = '^';
            new_str[new_str_index++] = '^';
            // Consume remaining 6s - double check this for off-by-one
            while ('6' == str[i+1]) i += 1;
        }
        else {
            // Add chars
            new_str[new_str_index++] = '*';
            new_str[new_str_index++] = '*';
       }
    }
    // No 6s, just append text
    else {
        new_str[new_str_index++] = str[i];
    }
}
Comments