0
votes

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.

2
You can copy str with char* copy = strdup(str); instead of using malloc incorrectly, and forgetting to actually perform the copy.pat
You shouldn't call printf with an unknown string as the first argument. The first argument is a format string that uses % delimited format specifiers to interpret subsequent arguments. If any of your unknown strings contain a %, bad things will happen. Use puts(str) , fputs(str, stdout), or printf("%s", str) instead.pat
strtok mutates the string it is scanning by replacing the delimiters with NUL terminators. If you print copy, after running strtok on it, you will only ever see the first token, since the NUL terminator is never removed after being inserted. However, each call to strtok with a NULL first argument will pick up where the previous call left off (just after the delimiter that is now a NUL), and scan forward from there, returning the token that started at that position.pat
strcmp and strcasecmp return the lexicographic difference between the two strings. When the strings are equal, it returns 0, which is a false value in C. If you want the body of the if to execute when tok is equal to "insert", then you should explicitly check the return value for 0. i.e. if(strcasecmp(tok, "insert") == 0).pat
The %s scanf format specifier reads a whitespace delimited string, so you're only going to get "insert" in your buffer. The rest of the input is still going to be sitting in the stdin buffer.pat

2 Answers

1
votes

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! ;)

0
votes

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