Skip to Content
Course content

98: String Searching: strchr, strstr, strtok

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I see this all the time when developers move from languages like Python or JavaScript to C: they treat strtok as if it's a "split" function that returns a neat array of substrings. They assume the original string stays intact and that the function just gives them pointers to the pieces. It's a dangerous assumption that leads to some of the most frustrating "heisenbugs" in C.

strtok Doesn't Split Strings; It Mutilates Them

Let me show you exactly why that thinking is wrong. Imagine you have a configuration string that you want to process twice—perhaps once to log the original and once to parse the values.

char config[] = "timeout=30,retry=5,mode=async";
char *token = strtok(config, ",");
// Now you think config is still "timeout=30,retry=5,mode=async"
printf("Original: %s\n", config); 

If you run this, you won't see the whole string. You'll see "timeout=30". Why? Because strtok doesn't just find the comma; it replaces that comma with a null terminator (\0). It literally chops your string into pieces in place. If you need the original string later, you're out of luck unless you made a copy with strdup or strcpy first. I've spent way too many hours debugging programs where a string "randomly" got shortened because some utility function called strtok under the hood.

Finding Needles in Haystacks with strchr and strstr

If you just need to find something without destroying your data, strchr and strstr are your best friends. They are "read-only" operations.

strchr looks for a single character. It's incredibly useful for finding the end of a prefix or a specific delimiter. For example, if you're parsing a file path and need to find the first slash:

char path[] = "/usr/local/bin/gcc";
char *first_slash = strchr(path, '/');
if (first_slash) {
    // first_slash points to the first '/'
}

Then there's strstr, which searches for an entire substring. I use this constantly for basic protocol parsing. If you're looking for a specific header in an HTTP response, strstr(buffer, "Content-Type:") is the way to go. It returns a pointer to the start of the first occurrence of the needle in the haystack, or NULL if it's not there. Just remember: both of these return pointers into the original string. Don't try to free those pointers; you can only free the pointer returned by malloc.

Managing the Internal State of strtok

Now, back to strtok. You've probably noticed that the first call takes the string, but subsequent calls to get the rest of the tokens use NULL as the first argument. This is where it gets weird.

strtok maintains a static internal pointer to remember where it left off. This makes it "stateful." While it feels convenient, it means strtok is not thread-safe. If two different threads try to tokenize two different strings at the same time using strtok, they'll overwrite each other's internal state and your program will crash or produce garbage. (In a real-world production environment, I'd tell you to use strtok_r—the reentrant version—but let's master the basics first).

Here is the correct pattern for using it: you prime the pump with the string, then loop until you hit NULL.

char data[] = "Apple,Orange,Banana,Grape";
char *token = strtok(data, ",");

while (token != NULL) {
    printf("Fruit: %s\n", token);
    token = strtok(NULL, ","); // Tell it to keep going from where it stopped
}



📋 Practical Task

CSV Log Entry Parser

You are building a tool to analyze server logs. Each log entry is a single string in the format: "TIMESTAMP|LEVEL|MESSAGE" (e.g., "2023-10-11 10:00:01|ERROR|Database connection failed").

Write a program that does the following:

  • Defines a character array containing a log entry.
  • Uses strstr to verify that the string contains the word "ERROR".
  • If it is an error, uses strtok to split the string by the '| delimiter.
  • Prints the extracted Timestamp and the Message separately.

Constraint: Ensure you handle the original string carefully, as strtok will modify it. Your output should look like:
Timestamp: 2023-10-11 10:00:01
Message: Database connection failed

Rating
0 0

There are no comments for now.

to be the first to leave a comment.