Part of C in 100s

C in 100 Seconds: String Functions — strcat, strchr, strstr

Celest KimCelest Kim

Video: C in 100 Seconds: String Functions — strcat, strchr, strstr | Episode 32 by Taught by Celeste AI - AI Coding Coach

Take the quiz on the full lesson page
Test what you've read · interactive walkthrough

C String Functions: strcat, strchr, strstr

strcat(dest, src) to append. strchr(s, c) to find a character. strstr(s, sub) to find a substring. Three more <string.h> essentials.

We covered strlen, strcpy, strcmp in episode 11. Today: three more — concatenation, char search, substring search.

The basic shape

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

int main() {
  char greeting[50] = "Hello";
  strcat(greeting, " World");
  printf("strcat:  %s\n", greeting);   // Hello World

  char buf[20] = "Hi";
  strncat(buf, " there, friend!", 6);
  printf("strncat: %s\n", buf);        // Hi there

  char path[] = "/home/user/docs/file.txt";
  char *dot = strchr(path, '.');
  printf("strchr:  %s\n", dot);        // .txt

  char sentence[] = "The quick brown fox";
  char *found = strstr(sentence, "brown");
  printf("strstr:  %s\n", found);      // brown fox

  return 0;
}

strcat — concatenate

char *strcat(char *dest, const char *src);

Appends src to dest. The destination must have enough space for both strings + null terminator.

char greeting[50] = "Hello";
strcat(greeting, " World");
// greeting is now "Hello World" (11 chars + \0 = 12 bytes used)

Buffer overflow risk: if src doesn't fit, strcat writes past the end of dest. Catastrophic — same security issue as strcpy.

strncat — bounded concatenate

char *strncat(char *dest, const char *src, size_t n);

Appends at most n chars from src. n is the chars from src, not the total buffer size.

char buf[20] = "Hi";
strncat(buf, " there, friend!", 6);   // appends " there"
// buf is now "Hi there"

The function appends min(n, strlen(src)) chars and adds a \0. The danger: the resulting string can be up to strlen(dest) + n bytes. Make sure dest has room.

For truly safe append, the modern idiom is snprintf:

char buf[20] = "Hi";
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s", " there, friend!");
// always null-terminated, never overflows

Verbose but bulletproof.

strchr — find first character

char *strchr(const char *s, int c);

Returns pointer to the first occurrence of c in s, or NULL if not found.

char path[] = "/home/user/docs/file.txt";
char *dot = strchr(path, '.');
// dot points to the '.' before "txt"
printf("%s\n", dot);   // ".txt" (from the dot to the end)

The returned pointer is into the original string — not a copy. Modifying through it modifies the original.

For finding the last occurrence, use strrchr (note the extra r):

char *last_dot = strrchr(path, '.');
// finds the final '.' if there are multiple

strchr(s, '\0') returns a pointer to the null terminator — useful for finding the end of a string.

strstr — find substring

char *strstr(const char *haystack, const char *needle);

Returns pointer to the first occurrence of needle in haystack, or NULL.

char sentence[] = "The quick brown fox";
char *found = strstr(sentence, "brown");
// found points to the 'b' in "brown"
printf("%s\n", found);   // "brown fox"

For empty needle, returns haystack (the whole string matches).

For case-insensitive search, strcasestr (POSIX, not standard C):

char *p = strcasestr(text, "hello");   // matches "Hello", "HELLO", etc.

Combining

// Get filename extension
char path[] = "/home/user/docs/file.txt";
char *ext = strrchr(path, '.');
if (ext != NULL) {
  ext++;   // skip the dot
  printf("Extension: %s\n", ext);   // "txt"
}

// Replace word in place (only if same length)
char text[] = "The quick brown fox";
char *p = strstr(text, "brown");
if (p) {
  memcpy(p, "gray ", 5);   // same length
}

Other string functions worth knowing

  • strdup(s) — malloc and copy a string. Free when done.
  • strspn(s, chars) / strcspn(s, chars) — count chars matching / not matching a set.
  • strpbrk(s, chars) — find any of several chars.
  • strtok(s, delim) — tokenize (covered in episode 33; has thread-safety quirks).

For Unicode, <string.h> is byte-oriented — it works for UTF-8 only because UTF-8's design avoids embedded zeros and lets ASCII operations work on ASCII subsets. For real multi-byte work, use ICU or roll your own.

strcat in a loop is O(n²)

char buf[1000] = "";
for (int i = 0; i < 100; i++) {
  strcat(buf, "x");   // strcat walks to the end each time
}

Each strcat does strlen(buf) to find the end, then copies. So 100 calls = 100 × O(len) = O(n²) total. For long strings, very slow.

The fix: track the length:

char buf[1000] = "";
size_t len = 0;
for (int i = 0; i < 100; i++) {
  buf[len++] = 'x';
}
buf[len] = '\0';

Or use snprintf which gives you the position:

char buf[1000] = "";
size_t pos = 0;
for (int i = 0; i < 100; i++) {
  pos += snprintf(buf + pos, sizeof(buf) - pos, "x");
}

Common mistakes

Buffer too small for strcat. Classic overflow. Always check sizes.

strncat's n is from src, not total. A common confusion. The actual total can exceed n.

Forgetting to check NULL from strchr/strstr. "Pointer to char not found" = NULL. Dereferencing crashes.

Modifying through const char *. strchr on const char * returns char * (legacy ABI quirk). The returned pointer is technically writable, but if the source was actually const, modifying is undefined.

strcat quadratic behaviour. Each call walks to the null terminator. For loops, track position manually or use snprintf.

What's next

Episode 33: strtok — string tokenizing. Split a string by delimiters. Has thread-safety surprises.

Recap

strcat(dest, src) — append, unsafe; use snprintf(dest+len, room, "%s", src) for safety. strncat(dest, src, n) — at most n chars from src; total still grows. strchr(s, c) — first occurrence of char (NULL if missing). strrchr — last occurrence. strstr(haystack, needle) — first occurrence of substring. All return pointers into the original string. Watch for buffer overflows on writes; check NULL on searches.

Next episode: strtok.

Ready? Take the quiz on the full lesson page →
Test what you've learned. Watch the lesson and try the interactive quiz on the same page.