The strstr() function finds the first occurrence of a substring within a larger string. It returns a pointer to the beginning of the found substring, or NULL if the substring is not found.
Basic Syntax
#include <string.h> char *strstr(const char *haystack, const char *needle);
| Parameter | Description |
|---|---|
haystack | The main string to search in |
needle | The substring to search for |
| Return value | Pointer to first occurrence, or NULL if not found |
Example 1: Basic Substring Search
#include <stdio.h>
#include <string.h>
int main() {
char text[] = "The quick brown fox jumps over the lazy dog";
char word[] = "fox";
char *result = strstr(text, word);
if(result != NULL) {
printf("Found '%s' at position: %ld\n", word, result - text);
printf("Remaining string: %s\n", result);
} else {
printf("Substring not found\n");
}
return 0;
}
Output:
Found 'fox' at position: 16 Remaining string: fox jumps over the lazy dog
Example 2: Substring Not Found
#include <stdio.h>
#include <string.h>
int main() {
char sentence[] = "Hello World";
char search[] = "xyz";
char *result = strstr(sentence, search);
if(result == NULL) {
printf("'%s' not found in '%s'\n", search, sentence);
}
return 0;
}
Output:
'xyz' not found in 'Hello World'
Example 3: Finding All Occurrences
#include <stdio.h>
#include <string.h>
int main() {
char text[] = "the cat in the hat sat on the mat";
char search[] = "the";
char *ptr = text;
int count = 0;
while((ptr = strstr(ptr, search)) != NULL) {
printf("Found '%s' at position: %ld\n", search, ptr - text);
ptr++; // Move past this occurrence
count++;
}
printf("Total occurrences: %d\n", count);
return 0;
}
Output:
Found 'the' at position: 0 Found 'the' at position: 11 Found 'the' at position: 23 Total occurrences: 3
Example 4: Extracting Text Before/After Substring
#include <stdio.h>
#include <string.h>
int main() {
char data[] = "username=john123&password=secret";
char delimiter[] = "=";
char *equal_sign = strstr(data, delimiter);
if(equal_sign != NULL) {
// Extract key (before =)
int key_len = equal_sign - data;
char key[50];
strncpy(key, data, key_len);
key[key_len] = '\0';
// Extract value (after =)
char *value = equal_sign + 1;
char val[50];
strcpy(val, value);
printf("Key: %s\n", key);
printf("Value: %s\n", val);
}
return 0;
}
Output:
Key: username Value: john123&password=secret
Example 5: Finding File Extension
#include <stdio.h>
#include <string.h>
int main() {
char filename[] = "document.pdf";
char *dot = strstr(filename, ".");
if(dot != NULL) {
printf("Filename: %.*s\n", (int)(dot - filename), filename);
printf("Extension: %s\n", dot + 1);
}
// Another example with multiple dots
char file2[] = "backup.tar.gz";
char *last_dot = strrchr(file2, '.'); // strrchr finds last occurrence
if(last_dot != NULL) {
printf("\nFile: %s\n", file2);
printf("Extension: %s\n", last_dot + 1);
}
return 0;
}
Output:
Filename: document Extension: pdf File: backup.tar.gz Extension: gz
Example 6: Case-Sensitive vs Case-Insensitive
#include <stdio.h>
#include <string.h>
#include <ctype.h>
// Custom case-insensitive version
char *stristr(const char *haystack, const char *needle) {
if(!*needle) return (char*)haystack;
for(; *haystack; haystack++) {
if(tolower(*haystack) == tolower(*needle)) {
const char *h = haystack;
const char *n = needle;
while(*h && *n && tolower(*h) == tolower(*n)) {
h++;
n++;
}
if(!*n) return (char*)haystack;
}
}
return NULL;
}
int main() {
char text[] = "Hello WORLD, world is beautiful";
// strstr is case-sensitive
char *result1 = strstr(text, "world");
printf("strstr('world'): %s\n", result1 ? "Found" : "Not found");
char *result2 = strstr(text, "WORLD");
printf("strstr('WORLD'): %s\n", result2 ? result2 : "Not found");
// Case-insensitive version
char *result3 = stristr(text, "world");
printf("stristr('world'): %s\n", result3);
return 0;
}
Output:
strstr('world'): Found
strstr('WORLD'): WORLD, world is beautiful
stristr('world'): Hello WORLD, world is beautiful
Example 7: Replacing Substring
#include <stdio.h>
#include <string.h>
void replaceFirst(char *text, const char *find, const char *replace) {
char *pos = strstr(text, find);
if(pos != NULL) {
char temp[200];
int prefix_len = pos - text;
int find_len = strlen(find);
// Build new string
strncpy(temp, text, prefix_len);
temp[prefix_len] = '\0';
strcat(temp, replace);
strcat(temp, pos + find_len);
// Copy back
strcpy(text, temp);
}
}
int main() {
char message[200] = "I like apples and apples are tasty";
printf("Original: %s\n", message);
replaceFirst(message, "apples", "oranges");
printf("After replace: %s\n", message);
return 0;
}
Output:
Original: I like apples and apples are tasty After replace: I like oranges and apples are tasty
Example 8: Validating String Format
#include <stdio.h>
#include <string.h>
int isValidEmail(const char *email) {
// Check for @ symbol
char *at = strstr(email, "@");
if(at == NULL) return 0;
// Check for dot after @
char *dot = strstr(at, ".");
if(dot == NULL) return 0;
// Check minimal length
if(at - email < 1) return 0;
if(strlen(dot + 1) < 2) return 0;
return 1;
}
int main() {
char emails[][50] = {
"[email protected]",
"invalid.email",
"test@domain",
"[email protected]"
};
for(int i = 0; i < 4; i++) {
printf("%s: %s\n", emails[i],
isValidEmail(emails[i]) ? "Valid" : "Invalid");
}
return 0;
}
Output:
[email protected]: Valid invalid.email: Invalid test@domain: Invalid [email protected]: Valid
Common Mistakes
#include <stdio.h>
#include <string.h>
int main() {
char text[] = "Hello World";
// ❌ WRONG - Checking wrong way
if(strstr(text, "World") > 0) { // Comparing pointer to int
printf("This comparison is wrong\n");
}
// ✅ CORRECT - Check against NULL
if(strstr(text, "World") != NULL) {
printf("Found correctly\n");
}
// ❌ WRONG - Empty needle (returns haystack always)
char *result = strstr(text, "");
printf("Empty needle returns: %s\n", result); // Returns whole string
// ❌ WRONG - Modifying string literal with result
char *literal = "Constant string";
char *found = strstr(literal, "stant");
// found[0] = 'X'; // CRASH - String literal is read-only
// ✅ CORRECT - Use modifiable array
char modifiable[] = "Constant string";
char *found2 = strstr(modifiable, "stant");
if(found2) found2[0] = 'X'; // Works fine
printf("Modified: %s\n", modifiable);
return 0;
}
Output:
Found correctly Empty needle returns: Hello World Modified: ConXtant string
strstr vs Other Search Functions
| Function | Description | Return Value |
|---|---|---|
strstr(haystack, needle) | Find first substring | Pointer or NULL |
strchr(str, char) | Find first character | Pointer or NULL |
strrchr(str, char) | Find last character | Pointer or NULL |
strpbrk(str, chars) | Find any character from set | Pointer or NULL |
strspn(str, chars) | Length of initial segment | Length (size_t) |
strcspn(str, chars) | Length before any match | Length (size_t) |
Performance Considerations
#include <stdio.h>
#include <string.h>
#include <time.h>
// Simple naive search (similar to strstr)
char *naive_search(const char *haystack, const char *needle) {
size_t hlen = strlen(haystack);
size_t nlen = strlen(needle);
if(nlen == 0) return (char*)haystack;
for(size_t i = 0; i <= hlen - nlen; i++) {
if(memcmp(haystack + i, needle, nlen) == 0) {
return (char*)(haystack + i);
}
}
return NULL;
}
int main() {
char text[1000] = "This is a test string for searching patterns";
char pattern[] = "searching";
// strstr is highly optimized (often uses advanced algorithms)
clock_t start = clock();
for(int i = 0; i < 1000000; i++) {
strstr(text, pattern);
}
clock_t end = clock();
printf("strstr time: %f seconds\n", (double)(end - start) / CLOCKS_PER_SEC);
return 0;
}
Practical Example: Simple HTML Parser
#include <stdio.h>
#include <string.h>
void extractLinks(const char *html) {
const char *ptr = html;
char *link_start, *link_end;
while((link_start = strstr(ptr, "href=\"")) != NULL) {
link_start += 6; // Skip 'href="'
link_end = strstr(link_start, "\"");
if(link_end != NULL) {
int len = link_end - link_start;
printf("Found link: %.*s\n", len, link_start);
ptr = link_end;
} else {
break;
}
}
}
int main() {
char html[] =
"<a href=\"https://example.com\">Example</a> "
"<a href=\"/page.html\">Page</a> "
"<img src=\"image.jpg\">";
extractLinks(html);
return 0;
}
Output:
Found link: https://example.com Found link: /page.html
Quick Reference
| Operation | Code | Result |
|---|---|---|
| Find substring | strstr(text, "word") | Pointer or NULL |
| Get position | pos = strstr(text, "word") - text | Index or -1 if not found |
| Check exists | if(strstr(text, "word")) | True if found |
| Find after position | strstr(ptr + 1, "word") | Search after current |
| Extract before | strncpy(buf, text, pos - text) | Text before match |
| Extract after | strcpy(buf, pos + len) | Text after match |
Best Practices
- Always check if result is NULL before using the pointer
- Don't modify string literals returned by strstr
- Use pointer arithmetic to get position indices
- Remember it's case-sensitive - convert both strings to same case if needed
- Empty needle returns haystack - handle this case if problematic
- For single characters, use strchr (more efficient than strstr)
Complete Guide to Core & Advanced C Programming Concepts (Functions, Strings, Arrays, Loops, I/O, Control Flow)
https://macronepal.com/bash/building-blocks-of-c-a-complete-guide-to-functions/
Explains how functions in C work as reusable blocks of code, including declaration, definition, parameters, return values, and modular programming structure.
https://macronepal.com/bash/the-heart-of-text-processing-a-complete-guide-to-strings-in-c-2/
Explains how strings are handled in C using character arrays, string manipulation techniques, and common library functions for text processing.
https://macronepal.com/bash/the-cornerstone-of-data-organization-a-complete-guide-to-arrays-in-c/
Explains arrays in C as structured memory storage for multiple values, including indexing, initialization, and efficient data organization.
https://macronepal.com/bash/guaranteed-execution-a-complete-guide-to-the-do-while-loop-in-c/
Explains the do-while loop in C, where the loop body executes at least once before checking the condition.
https://macronepal.com/bash/mastering-iteration-a-complete-guide-to-the-for-loop-in-c/
Explains the for loop in C, including initialization, condition checking, and increment/decrement for controlled iteration.
https://macronepal.com/bash/mastering-iteration-a-complete-guide-to-while-loops-in-c/
Explains the while loop in C, focusing on condition-based repetition and proper loop control mechanisms.
https://macronepal.com/bash/beyond-if-else-a-complete-guide-to-switch-case-in-c/
Explains switch-case statements in C, enabling multi-branch decision-making based on variable values.
https://macronepal.com/bash/mastering-conditional-logic-a-complete-guide-to-if-else-statements-in-c/
Explains if-else statements in C for decision-making and controlling program flow based on conditions.
https://macronepal.com/bash/mastering-the-fundamentals-a-complete-guide-to-arithmetic-operations-in-c/
Explains arithmetic operations in C such as addition, subtraction, multiplication, division, and operator precedence.
https://macronepal.com/bash/foundation-of-c-programming-a-complete-guide-to-basic-input-output/
Explains basic input and output in C using scanf and printf for interacting with users and displaying results.
Online C Code Compiler
https://macronepal.com/free-online-c-code-compiler-2/