botch
botch

Reputation: 167

C String parsing errors with strtok(),strcasecmp()

So I'm new to C and the whole string manipulation thing, but I can't seem to get strtok() to work. It seems everywhere everyone has the same template for strtok being:

char* tok = strtok(source,delim);
do
{
 {code}
 tok=strtok(NULL,delim);
}while(tok!=NULL);

So I try to do this with the delimiter being the space key, and it seems that strtok() no only reads NULL after the first run (the first entry into the while/do-while) no matter how big the string, but it also seems to wreck the source, turning the source string into the same thing as tok.

Here is a snippet of my code:

char* str;
scanf("%ms",&str);
char* copy = malloc(sizeof(str));
strcpy(copy,str);
char* tok = strtok(copy," ");
if(strcasecmp(tok,"insert"))
{
 printf(str);
 printf(copy);
 printf(tok);
}

Then, here is some output for the input "insert a b c d e f g"

aaabbbcccdddeeefffggg

"Insert" seems to disappear completely, which I think is the fault of strcasecmp(). Also, I would like to note that I realize strcasecmp() seems to all-lower-case my source string, and I do not mind. Anyhoo, input "insert insert insert" yields absolutely nothing in output. It's as if those functions just eat up the word "insert" no matter how many times it is present. I may* end up just using some of the C functions that read the string char by char but I would like to avoid this if possible. Thanks a million guys, i appreciate the help.

Upvotes: 1

Views: 912

Answers (2)

pat
pat

Reputation: 12749

It looks like you're trying to print space delimited tokens following the word "insert" 3 times. Does this do what you want?

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

int main(int argc, char **argv)
{
    char str[BUFSIZ] = {0};
    char *copy;
    char *tok;
    int i;

    // safely read a string and chop off any trailing newline
    if(fgets(str, sizeof(str), stdin)) {
        int n = strlen(str);
        if(n && str[n-1] == '\n')
            str[n-1] = '\0';
    }

    // copy the string so we can trash it with strtok
    copy = strdup(str);

    // look for the first space-delimited token
    tok = strtok(copy, " ");

    // check that we found a token and that it is equal to "insert"
    if(tok && strcasecmp(tok, "insert") == 0) {
        // iterate over all remaining space-delimited tokens
        while((tok = strtok(NULL, " "))) {
            // print the token 3 times
            for(i = 0; i < 3; i++) {
                fputs(tok, stdout);
            }
        }
        putchar('\n');
    }

    free(copy);

    return 0;
}

Upvotes: 0

Some programmer dude
Some programmer dude

Reputation: 409432

With the second snippet of code you have five problems: The first is that your format for the scanf function is non-standard, what's the 'm' supposed to do? (See e.g. here for a good reference of the standard function.)

The second problem is that you use the address-of operator on a pointer, which means that you pass a pointer to a pointer to a char (e.g. char**) to the scanf function. As you know, the scanf function want its arguments as pointers, but since strings (either in pointer to character form, or array form) already are pointer you don't have to use the address-of operator for string arguments.

The third problem, once you fix the previous problem, is that the pointer str is uninitialized. You have to remember that uninitialized local variables are truly uninitialized, and their values are indeterminate. In reality, it means that their values will be seemingly random. So str will point to some "random" memory.

The fourth problem is with the malloc call, where you use the sizeof operator on a pointer. This will return the size of the pointer and not what it points to.

The fifth problem, is that when you do strtok on the pointer copy the contents of the memory pointed to by copy is uninitialized. You allocate memory for it (typically 4 or 8 bytes depending on you're on a 32 or 64 bit platform, see the fourth problem) but you never initialize it.

So, five problems in only four lines of code. That's pretty good! ;)

Upvotes: 1

Related Questions