C string algorithms
Write strlen and strcmp by hand, check palindromes, and count occurrences with strstr.
On this page
C char arrays and the string library.
- Write strlen and strcmp by hand, check palindromes, and count occurrences with strstr.
- Predict the sample output and explain the state changes.
- Complete the practice task and check the boundary cases.
The concept
A C string is an array of char ended by a zero byte. Functions such as strlen simply walk the array until they find that zero, so they take O(n) time, and calling strlen in a loop condition repeats that work on every pass. strcmp compares two strings byte by byte and returns a negative, zero, or positive number.
A palindrome check uses two indexes that move toward each other from both ends, skipping characters that are not letters or digits and comparing the rest without regard to case. strstr finds the first occurrence of one string inside another. Calling it repeatedly from just after each match counts every occurrence, including overlapping ones if the search restarts one character after the previous match.
Code example
#include <ctype.h>
#include <stdio.h>
#include <string.h>
static size_t my_strlen(const char *s) {
size_t n = 0;
while (s[n] != '\0') {
n++;
}
return n;
}
static int my_strcmp(const char *a, const char *b) {
while (*a != '\0' && *a == *b) {
a++;
b++;
}
return (unsigned char)*a - (unsigned char)*b;
}
static int is_palindrome(const char *s) {
int i = 0;
int j = (int)strlen(s) - 1;
while (i < j) {
if (!isalnum((unsigned char)s[i])) {
i++;
} else if (!isalnum((unsigned char)s[j])) {
j--;
} else if (tolower((unsigned char)s[i]) != tolower((unsigned char)s[j])) {
return 0;
} else {
i++;
j--;
}
}
return 1;
}
static int count_occurrences(const char *text, const char *pattern) {
int count = 0;
const char *p = text;
while ((p = strstr(p, pattern)) != NULL) {
count++;
p++;
}
return count;
}
int main(void) {
printf("%zu %zu\n", my_strlen("Programonic"), my_strlen(""));
printf("%d %d\n", my_strcmp("apple", "apple") == 0, my_strcmp("apple", "banana") < 0);
printf("%d %d\n", is_palindrome("A man, a plan, a canal: Panama"), is_palindrome("hello"));
printf("%d\n", count_occurrences("abababa", "aba"));
return 0;
}11 0 1 1 1 0 3
Follow the code
Open the walkthrough to inspect the example one step at a time.
Show guided walkthrough
#include <ctype.h>#include <stdio.h>#include <string.h> static size_t my_strlen(const char *s) { size_t n = 0; while (s[n] != '\0') { n++; } return n;} static int my_strcmp(const char *a, const char *b) { while (*a != '\0' && *a == *b) { a++; b++; } return (unsigned char)*a - (unsigned char)*b;} static int is_palindrome(const char *s) { int i = 0; int j = (int)strlen(s) - 1; while (i < j) { if (!isalnum((unsigned char)s[i])) { i++; } else if (!isalnum((unsigned char)s[j])) { j--; } else if (tolower((unsigned char)s[i]) != tolower((unsigned char)s[j])) { return 0; } else { i++; j--; } } return 1;} static int count_occurrences(const char *text, const char *pattern) { int count = 0; const char *p = text; while ((p = strstr(p, pattern)) != NULL) { count++; p++; } return count;} int main(void) { printf("%zu %zu\n", my_strlen("Programonic"), my_strlen("")); printf("%d %d\n", my_strcmp("apple", "apple") == 0, my_strcmp("apple", "banana") < 0); printf("%d %d\n", is_palindrome("A man, a plan, a canal: Panama"), is_palindrome("hello")); printf("%d\n", count_occurrences("abababa", "aba")); return 0;}Follow the example
Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.
View the complete dry-run table
| Step / line | What happens | State after step | Output so far |
|---|---|---|---|
| Walk until the terminating zero byte: the length is the number of steps. | — | — | |
| The first differing bytes decide the order. Cast to unsigned char so that values above 127 compare correctly. | — | — | |
| Programonic has 11 characters and the empty string has none. | — | 11 0 | |
| Equal strings compare as 0, and apple sorts before banana. | — | 11 0 1 1 | |
| Compare letters case-insensitively once both ends point at letters or digits. | — | 11 0 1 1 | |
| The famous sentence reads the same backwards when punctuation and case are ignored. | — | 11 0 1 1 1 0 | |
| Restart one character after the previous match, so overlapping matches are counted. | — | 11 0 1 1 1 0 | |
| aba appears at positions 0, 2, and 4, which overlap. | — | 11 0 1 1 1 0 3 |
Behind the scenes
How C processes this code
The C compiler produces a native program. Variables occupy memory, and execution enters main.
Cost and common mistakes
my_strlen and my_strcmp are O(n); count_occurrences is O(n·m) in the worst case.
- Calling strlen(s) in the condition of a loop over s makes the loop O(n²). Compute the length once.
- strcmp results should only be compared with 0, or tested for sign. Do not rely on the exact value.
- Passing a negative char to isalnum or tolower is undefined behaviour, so cast to unsigned char first.
Try it yourself
Why does the example print 1 for my_strcmp("apple", "apple") == 0?
Reveal answer and reasoning
The comparison expression is true, which C represents as the integer 1. The two strings are identical, so strcmp returns 0.