Introduction to String Functions
In C, strings are arrays of characters terminated by a null character (\0). The C standard library provides a rich set of functions for string manipulation through the <string.h> header. Understanding these functions is crucial for effective C programming.
String Functions Overview
String Functions Categories ├── String Length │ └── strlen() ├── String Copy │ ├── strcpy() │ ├── strncpy() │ └── memcpy() ├── String Concatenation │ ├── strcat() │ └── strncat() ├── String Comparison │ ├── strcmp() │ ├── strncmp() │ └── strcasecmp() / stricmp() ├── String Search │ ├── strchr() │ ├── strrchr() │ ├── strstr() │ └── strpbrk() ├── String Tokenization │ └── strtok() └── Memory Operations ├── memcpy() ├── memmove() ├── memset() └── memcmp()
String Length Functions
strlen() - Get String Length
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "Hello";
char str2[] = "Hello, World!";
char str3[] = "";
printf("String: \"%s\"\n", str1);
printf("Length: %zu\n\n", strlen(str1));
printf("String: \"%s\"\n", str2);
printf("Length: %zu\n\n", strlen(str2));
printf("String: \"%s\" (empty)\n", str3);
printf("Length: %zu\n\n", strlen(str3));
// Manual implementation of strlen
size_t myStrlen(const char *s) {
const char *p = s;
while (*p) p++;
return p - s;
}
printf("Using custom strlen: %zu\n", myStrlen("Test"));
return 0;
}
Output:
String: "Hello" Length: 5 String: "Hello, World!" Length: 13 String: "" (empty) Length: 0 Using custom strlen: 4
String Copy Functions
strcpy() - Copy String
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest[20]; // Make sure destination is large enough
printf("Source: \"%s\"\n", src);
strcpy(dest, src);
printf("Destination after strcpy: \"%s\"\n", dest);
// Warning: strcpy doesn't check buffer size
char small[5];
// strcpy(small, src); // BUFFER OVERFLOW! Don't do this
// Safe alternative using strncpy
char safe[10];
strncpy(safe, src, sizeof(safe) - 1);
safe[sizeof(safe) - 1] = '\0'; // Ensure null termination
printf("Safe copy (truncated): \"%s\"\n", safe);
return 0;
}
Output:
Source: "Hello, World!" Destination after strcpy: "Hello, World!" Safe copy (truncated): "Hello, Wo"
strncpy() - Copy with Length Limit
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest1[10];
char dest2[20];
printf("Source: \"%s\" (length: %zu)\n\n", src, strlen(src));
// Copy with limit
strncpy(dest1, src, sizeof(dest1) - 1);
dest1[sizeof(dest1) - 1] = '\0';
printf("dest1 (size 10): \"%s\"\n", dest1);
// Copy full string
strncpy(dest2, src, sizeof(dest2) - 1);
dest2[sizeof(dest2) - 1] = '\0';
printf("dest2 (size 20): \"%s\"\n", dest2);
// Note: strncpy doesn't add null terminator if limit reached
char dest3[5];
strncpy(dest3, "Hello", 5); // No null terminator!
dest3[4] = '\0'; // Must add manually
printf("dest3 (exact fit): \"%s\"\n", dest3);
return 0;
}
Output:
Source: "Hello, World!" (length: 13) dest1 (size 10): "Hello, Wo" dest2 (size 20): "Hello, World!" dest3 (exact fit): "Hell"
String Concatenation Functions
strcat() - Concatenate Strings
#include <stdio.h>
#include <string.h>
int main() {
char str1[50] = "Hello";
char str2[] = ", ";
char str3[] = "World";
char str4[] = "!";
printf("Initial: \"%s\"\n", str1);
strcat(str1, str2);
printf("After strcat(str2): \"%s\"\n", str1);
strcat(str1, str3);
printf("After strcat(str3): \"%s\"\n", str1);
strcat(str1, str4);
printf("After strcat(str4): \"%s\"\n", str1);
// Safe concatenation with strncat
char safe[20] = "Hello";
strncat(safe, ", World!", sizeof(safe) - strlen(safe) - 1);
printf("Safe concatenation: \"%s\"\n", safe);
return 0;
}
Output:
Initial: "Hello" After strcat(str2): "Hello, " After strcat(str3): "Hello, World" After strcat(str4): "Hello, World!" Safe concatenation: "Hello, World!"
Building Strings with strncat()
#include <stdio.h>
#include <string.h>
int main() {
char buffer[50] = "";
char *words[] = {"The", "quick", "brown", "fox", "jumps"};
int wordCount = sizeof(words) / sizeof(words[0]);
printf("Building a sentence:\n");
for (int i = 0; i < wordCount; i++) {
// Add space before each word except first
if (i > 0) {
strncat(buffer, " ", sizeof(buffer) - strlen(buffer) - 1);
}
strncat(buffer, words[i], sizeof(buffer) - strlen(buffer) - 1);
printf("Step %d: \"%s\"\n", i + 1, buffer);
}
// Add period
strncat(buffer, ".", sizeof(buffer) - strlen(buffer) - 1);
printf("\nFinal: \"%s\"\n", buffer);
return 0;
}
String Comparison Functions
strcmp() - Compare Strings
#include <stdio.h>
#include <string.h>
void compareStrings(const char *s1, const char *s2) {
int result = strcmp(s1, s2);
printf("\"%s\" vs \"%s\": ", s1, s2);
if (result < 0) {
printf("\"%s\" comes before \"%s\"\n", s1, s2);
} else if (result > 0) {
printf("\"%s\" comes after \"%s\"\n", s1, s2);
} else {
printf("Strings are equal\n");
}
}
int main() {
compareStrings("apple", "banana");
compareStrings("banana", "apple");
compareStrings("hello", "hello");
compareStrings("Hello", "hello"); // Case sensitive
printf("\nUsing strncmp (compare first n characters):\n");
printf("strncmp(\"Hello\", \"Help\", 3) = %d\n", strncmp("Hello", "Help", 3));
printf("strncmp(\"Hello\", \"Help\", 4) = %d\n", strncmp("Hello", "Help", 4));
return 0;
}
Output:
"apple" vs "banana": "apple" comes before "banana"
"banana" vs "apple": "banana" comes after "apple"
"hello" vs "hello": Strings are equal
"Hello" vs "hello": "Hello" comes before "hello"
Using strncmp (compare first n characters):
strncmp("Hello", "Help", 3) = 0
strncmp("Hello", "Help", 4) = -1
Case-Insensitive Comparison
#include <stdio.h>
#include <string.h>
#include <ctype.h>
// Case-insensitive string comparison (not standard)
int strcasecmp_custom(const char *s1, const char *s2) {
while (*s1 && *s2) {
int c1 = tolower(*s1);
int c2 = tolower(*s2);
if (c1 != c2) {
return c1 - c2;
}
s1++;
s2++;
}
return tolower(*s1) - tolower(*s2);
}
int main() {
char *str1 = "Hello World";
char *str2 = "HELLO WORLD";
char *str3 = "Hello There";
printf("Case-sensitive comparison:\n");
printf("strcmp(\"%s\", \"%s\") = %d\n", str1, str2, strcmp(str1, str2));
printf("strcmp(\"%s\", \"%s\") = %d\n\n", str1, str3, strcmp(str1, str3));
printf("Case-insensitive comparison:\n");
printf("strcasecmp_custom(\"%s\", \"%s\") = %d\n",
str1, str2, strcasecmp_custom(str1, str2));
printf("strcasecmp_custom(\"%s\", \"%s\") = %d\n",
str1, str3, strcasecmp_custom(str1, str3));
return 0;
}
String Search Functions
strchr() and strrchr() - Find Character
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello, World! Welcome to C programming.";
char ch = 'o';
printf("String: \"%s\"\n", str);
printf("Searching for character: '%c'\n\n", ch);
// Find first occurrence
char *first = strchr(str, ch);
if (first) {
printf("First occurrence at position: %ld\n", first - str);
printf("From first occurrence: \"%s\"\n", first);
}
// Find last occurrence
char *last = strrchr(str, ch);
if (last) {
printf("Last occurrence at position: %ld\n", last - str);
printf("From last occurrence: \"%s\"\n", last);
}
// Find all occurrences
printf("\nAll occurrences of '%c' at positions: ", ch);
char *ptr = str;
while ((ptr = strchr(ptr, ch)) != NULL) {
printf("%ld ", ptr - str);
ptr++;
}
printf("\n");
return 0;
}
Output:
String: "Hello, World! Welcome to C programming." Searching for character: 'o' First occurrence at position: 4 From first occurrence: "o, World! Welcome to C programming." Last occurrence at position: 28 From last occurrence: "ogramming." All occurrences of 'o' at positions: 4 8 18 25 28
strstr() - Find Substring
#include <stdio.h>
#include <string.h>
int main() {
char text[] = "The quick brown fox jumps over the lazy dog.";
char search[] = "fox";
char replace[] = "cat";
printf("Text: \"%s\"\n", text);
printf("Searching for: \"%s\"\n\n", search);
char *found = strstr(text, search);
if (found) {
printf("Found at position: %ld\n", found - text);
printf("Context: ...%s\n", found);
// Simple replacement (not safe for different lengths)
char result[100];
strncpy(result, text, found - text);
result[found - text] = '\0';
strcat(result, replace);
strcat(result, found + strlen(search));
printf("After replacement: \"%s\"\n", result);
} else {
printf("Substring not found\n");
}
// Find all occurrences
printf("\nAll occurrences of 'the' (case-sensitive):\n");
char *ptr = text;
while ((ptr = strstr(ptr, "the")) != NULL) {
printf("Found at position: %ld\n", ptr - text);
ptr++;
}
return 0;
}
Output:
Text: "The quick brown fox jumps over the lazy dog." Searching for: "fox" Found at position: 16 Context: ...fox jumps over the lazy dog. After replacement: "The quick brown cat jumps over the lazy dog." All occurrences of 'the' (case-sensitive): Found at position: 31
strpbrk() - Find Any of Multiple Characters
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello, World! How are you? 123";
char vowels[] = "aeiouAEIOU";
char punctuation[] = ".,!?;:";
char digits[] = "0123456789";
printf("String: \"%s\"\n\n", str);
// Find first vowel
char *vowel = strpbrk(str, vowels);
if (vowel) {
printf("First vowel: '%c' at position %ld\n", *vowel, vowel - str);
}
// Find first punctuation
char *punct = strpbrk(str, punctuation);
if (punct) {
printf("First punctuation: '%c' at position %ld\n", *punct, punct - str);
}
// Find first digit
char *digit = strpbrk(str, digits);
if (digit) {
printf("First digit: '%c' at position %ld\n", *digit, digit - str);
}
// Find all punctuation
printf("\nAll punctuation marks:\n");
char *ptr = str;
while ((ptr = strpbrk(ptr, punctuation)) != NULL) {
printf("Found '%c' at position %ld\n", *ptr, ptr - str);
ptr++;
}
return 0;
}
String Tokenization
strtok() - Split String into Tokens
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "apple,banana,orange,grape,kiwi";
char str2[] = "Hello|World|How|Are|You";
char str3[] = "one,two,three;four:five";
printf("=== Basic Tokenization ===\n");
printf("Original: \"%s\"\n", str);
// strtok modifies the original string - make a copy if needed
char *token = strtok(str, ",");
int count = 1;
while (token != NULL) {
printf("Token %d: \"%s\"\n", count++, token);
token = strtok(NULL, ",");
}
printf("\n=== Multiple Delimiters ===\n");
printf("Original: \"%s\"\n", str3);
char copy[100];
strcpy(copy, str3);
token = strtok(copy, ",;:");
count = 1;
while (token != NULL) {
printf("Token %d: \"%s\"\n", count++, token);
token = strtok(NULL, ",;:");
}
return 0;
}
Output:
=== Basic Tokenization === Original: "apple,banana,orange,grape,kiwi" Token 1: "apple" Token 2: "banana" Token 3: "orange" Token 4: "grape" Token 5: "kiwi" === Multiple Delimiters === Original: "one,two,three;four:five" Token 1: "one" Token 2: "two" Token 3: "three" Token 4: "four" Token 5: "five"
Advanced Tokenization Example
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// Function to count tokens
int countTokens(char *str, const char *delim) {
char copy[256];
strcpy(copy, str);
int count = 0;
char *token = strtok(copy, delim);
while (token != NULL) {
count++;
token = strtok(NULL, delim);
}
return count;
}
// Function to extract tokens into array
char** tokenize(char *str, const char *delim, int *tokenCount) {
*tokenCount = countTokens(str, delim);
char **tokens = malloc(*tokenCount * sizeof(char*));
if (tokens == NULL) return NULL;
char copy[256];
strcpy(copy, str);
int i = 0;
char *token = strtok(copy, delim);
while (token != NULL) {
tokens[i] = malloc(strlen(token) + 1);
strcpy(tokens[i], token);
i++;
token = strtok(NULL, delim);
}
return tokens;
}
void freeTokens(char **tokens, int count) {
for (int i = 0; i < count; i++) {
free(tokens[i]);
}
free(tokens);
}
int main() {
char input[] = "user:password@host:port/database?param=value";
printf("Parsing connection string: \"%s\"\n\n", input);
char *copy = malloc(strlen(input) + 1);
strcpy(copy, input);
// Parse different parts
char *userInfo = strtok(copy, "@");
char *hostPart = strtok(NULL, "/");
char *dbPart = strtok(NULL, "?");
char *params = strtok(NULL, "");
if (userInfo) {
char *user = strtok(userInfo, ":");
char *pass = strtok(NULL, ":");
printf("User: %s\n", user);
printf("Password: %s\n", pass);
}
if (hostPart) {
char *host = strtok(hostPart, ":");
char *port = strtok(NULL, ":");
printf("Host: %s\n", host);
if (port) printf("Port: %s\n", port);
}
if (dbPart) printf("Database: %s\n", dbPart);
if (params) printf("Parameters: %s\n", params);
free(copy);
return 0;
}
Memory Operations
memcpy() and memmove() - Copy Memory
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest1[20];
char dest2[20];
printf("memcpy - copies memory (no overlap allowed):\n");
memcpy(dest1, src, strlen(src) + 1); // +1 for null terminator
printf("dest1: \"%s\"\n\n", dest1);
printf("memmove - handles overlapping regions:\n");
char overlap[20] = "123456789";
printf("Original: \"%s\"\n", overlap);
// Copy overlapping regions (memcpy would fail)
memmove(overlap + 2, overlap, 5);
printf("After memmove: \"%s\"\n", overlap);
return 0;
}
Output:
memcpy - copies memory (no overlap allowed): dest1: "Hello, World!" memmove - handles overlapping regions: Original: "123456789" After memmove: "121234589"
memset() - Set Memory
#include <stdio.h>
#include <string.h>
int main() {
char buffer[50];
// Fill with zeros
memset(buffer, 0, sizeof(buffer));
printf("After memset zero: \"%s\"\n", buffer);
// Fill with 'A'
memset(buffer, 'A', 10);
buffer[10] = '\0';
printf("After memset 'A'x10: \"%s\"\n", buffer);
// Fill with '-'
memset(buffer, '-', 20);
buffer[20] = '\0';
printf("After memset '-'x20: \"%s\"\n", buffer);
// Practical use: zero out sensitive data
char password[20] = "secret123";
printf("\nPassword: \"%s\"\n", password);
// Clear password from memory
memset(password, 0, sizeof(password));
printf("After clearing: \"%s\"\n", password);
return 0;
}
memcmp() - Compare Memory
#include <stdio.h>
#include <string.h>
int main() {
char arr1[] = {1, 2, 3, 4, 5};
char arr2[] = {1, 2, 3, 4, 5};
char arr3[] = {1, 2, 3, 4, 6};
int result1 = memcmp(arr1, arr2, sizeof(arr1));
int result2 = memcmp(arr1, arr3, sizeof(arr1));
printf("arr1 vs arr2: %d (", result1);
if (result1 == 0) printf("equal");
printf(")\n");
printf("arr1 vs arr3: %d (", result2);
if (result2 < 0) printf("arr1 < arr3");
else if (result2 > 0) printf("arr1 > arr3");
printf(")\n");
// Compare first 4 bytes
int result3 = memcmp(arr1, arr3, 4);
printf("First 4 bytes: %d\n", result3);
return 0;
}
Practical String Examples
1. String Reversal
#include <stdio.h>
#include <string.h>
void reverseString(char *str) {
int length = strlen(str);
int start = 0;
int end = length - 1;
while (start < end) {
char temp = str[start];
str[start] = str[end];
str[end] = temp;
start++;
end--;
}
}
void reverseWords(char *str) {
// First reverse the entire string
reverseString(str);
// Then reverse each word
char *wordStart = str;
char *wordEnd = str;
while (*wordEnd) {
if (*wordEnd == ' ') {
char temp = *wordEnd;
*wordEnd = '\0';
reverseString(wordStart);
*wordEnd = temp;
wordStart = wordEnd + 1;
}
wordEnd++;
}
// Reverse last word
reverseString(wordStart);
}
int main() {
char str1[] = "Hello, World!";
char str2[] = "The quick brown fox";
printf("Original: \"%s\"\n", str1);
reverseString(str1);
printf("Reversed: \"%s\"\n\n", str1);
printf("Original: \"%s\"\n", str2);
reverseWords(str2);
printf("Words reversed: \"%s\"\n", str2);
return 0;
}
2. Palindrome Checker
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int isPalindrome(const char *str) {
int left = 0;
int right = strlen(str) - 1;
while (left < right) {
// Skip non-alphanumeric characters
while (left < right && !isalnum(str[left])) left++;
while (left < right && !isalnum(str[right])) right--;
if (tolower(str[left]) != tolower(str[right])) {
return 0;
}
left++;
right--;
}
return 1;
}
int main() {
char *testStrings[] = {
"racecar",
"A man, a plan, a canal: Panama",
"Hello World",
"Madam",
"Was it a car or a cat I saw?"
};
int count = sizeof(testStrings) / sizeof(testStrings[0]);
for (int i = 0; i < count; i++) {
printf("\"%s\"\n", testStrings[i]);
printf(" -> %s\n\n", isPalindrome(testStrings[i]) ? "Palindrome" : "Not a palindrome");
}
return 0;
}
3. String Compression
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* compressString(const char *str) {
int len = strlen(str);
char *compressed = malloc(2 * len + 1); // Worst case
int index = 0;
for (int i = 0; i < len; i++) {
int count = 1;
// Count consecutive characters
while (i + 1 < len && str[i] == str[i + 1]) {
count++;
i++;
}
// Append character and count
compressed[index++] = str[i];
if (count > 1) {
index += sprintf(compressed + index, "%d", count);
}
}
compressed[index] = '\0';
// Return original if compression doesn't help
if (strlen(compressed) >= len) {
free(compressed);
return strdup(str);
}
return compressed;
}
int main() {
char *testStrings[] = {
"aabcccccaaa",
"abcdef",
"aaabbbccc",
"aabbcc"
};
int count = sizeof(testStrings) / sizeof(testStrings[0]);
for (int i = 0; i < count; i++) {
char *compressed = compressString(testStrings[i]);
printf("Original: \"%s\" (%zu chars)\n",
testStrings[i], strlen(testStrings[i]));
printf("Compressed: \"%s\" (%zu chars)\n",
compressed, strlen(compressed));
printf("\n");
if (compressed != testStrings[i]) {
free(compressed);
}
}
return 0;
}
4. String Formatting
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
// Custom string formatter (simplified)
char* formatString(const char *format, ...) {
static char buffer[1024];
va_list args;
va_start(args, format);
vsprintf(buffer, format, args); // vsnprintf would be safer
va_end(args);
return buffer;
}
int main() {
char name[] = "Alice";
int age = 25;
double salary = 54321.50;
char *result = formatString("Name: %s, Age: %d, Salary: $%.2f",
name, age, salary);
printf("%s\n", result);
// Building formatted strings with sprintf
char logEntry[200];
sprintf(logEntry, "[%s] User %s logged in at %d",
"INFO", "bob", 123456);
printf("Log entry: %s\n", logEntry);
// Using snprintf for safety
char safeBuffer[50];
int written = snprintf(safeBuffer, sizeof(safeBuffer),
"This is a very long string that might overflow");
printf("Safe buffer: \"%s\" (wrote %d chars)\n", safeBuffer, written);
return 0;
}
String Utilities Library
string_utils.h
#ifndef STRING_UTILS_H #define STRING_UTILS_H #include <stdbool.h> // String utilities int string_length(const char *str); void string_copy(char *dest, const char *src, int max_len); void string_concat(char *dest, const char *src, int max_len); int string_compare(const char *s1, const char *s2); int string_compare_ignore_case(const char *s1, const char *s2); char* string_find_char(const char *str, char ch); char* string_find_substring(const char *str, const char *sub); void string_reverse(char *str); void string_to_upper(char *str); void string_to_lower(char *str); bool string_starts_with(const char *str, const char *prefix); bool string_ends_with(const char *str, const char *suffix); char* string_trim(char *str); char** string_split(const char *str, const char *delimiter, int *count); void string_free_split(char **tokens, int count); char* string_replace(const char *str, const char *old, const char *new); #endif
string_utils.c
#include "string_utils.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int string_length(const char *str) {
const char *s = str;
while (*s) s++;
return s - str;
}
void string_copy(char *dest, const char *src, int max_len) {
int i = 0;
while (src[i] && i < max_len - 1) {
dest[i] = src[i];
i++;
}
dest[i] = '\0';
}
void string_concat(char *dest, const char *src, int max_len) {
int dest_len = string_length(dest);
int i = 0;
while (src[i] && dest_len + i < max_len - 1) {
dest[dest_len + i] = src[i];
i++;
}
dest[dest_len + i] = '\0';
}
int string_compare(const char *s1, const char *s2) {
while (*s1 && *s2 && *s1 == *s2) {
s1++;
s2++;
}
return *s1 - *s2;
}
int string_compare_ignore_case(const char *s1, const char *s2) {
while (*s1 && *s2) {
int c1 = tolower(*s1);
int c2 = tolower(*s2);
if (c1 != c2) {
return c1 - c2;
}
s1++;
s2++;
}
return tolower(*s1) - tolower(*s2);
}
char* string_find_char(const char *str, char ch) {
while (*str) {
if (*str == ch) {
return (char*)str;
}
str++;
}
return NULL;
}
char* string_find_substring(const char *str, const char *sub) {
int sub_len = string_length(sub);
if (sub_len == 0) return (char*)str;
while (*str) {
if (string_compare_n(str, sub, sub_len) == 0) {
return (char*)str;
}
str++;
}
return NULL;
}
void string_reverse(char *str) {
int len = string_length(str);
int start = 0;
int end = len - 1;
while (start < end) {
char temp = str[start];
str[start] = str[end];
str[end] = temp;
start++;
end--;
}
}
void string_to_upper(char *str) {
while (*str) {
*str = toupper(*str);
str++;
}
}
void string_to_lower(char *str) {
while (*str) {
*str = tolower(*str);
str++;
}
}
bool string_starts_with(const char *str, const char *prefix) {
while (*prefix) {
if (*str != *prefix) {
return false;
}
str++;
prefix++;
}
return true;
}
bool string_ends_with(const char *str, const char *suffix) {
int str_len = string_length(str);
int suffix_len = string_length(suffix);
if (suffix_len > str_len) {
return false;
}
str += str_len - suffix_len;
while (*suffix) {
if (*str != *suffix) {
return false;
}
str++;
suffix++;
}
return true;
}
char* string_trim(char *str) {
char *end;
// Trim leading space
while (isspace((unsigned char)*str)) str++;
if (*str == 0) return str;
// Trim trailing space
end = str + string_length(str) - 1;
while (end > str && isspace((unsigned char)*end)) end--;
// Write new null terminator
*(end + 1) = '\0';
return str;
}
char** string_split(const char *str, const char *delimiter, int *count) {
char *copy = strdup(str);
char **result = NULL;
char *token;
int tokens = 0;
// First pass: count tokens
char *temp = strdup(str);
token = strtok(temp, delimiter);
while (token) {
tokens++;
token = strtok(NULL, delimiter);
}
free(temp);
if (tokens == 0) {
free(copy);
*count = 0;
return NULL;
}
// Allocate result array
result = malloc((tokens + 1) * sizeof(char*));
// Second pass: store tokens
int i = 0;
token = strtok(copy, delimiter);
while (token) {
result[i] = strdup(token);
i++;
token = strtok(NULL, delimiter);
}
result[i] = NULL;
*count = tokens;
return result;
}
void string_free_split(char **tokens, int count) {
for (int i = 0; i < count; i++) {
free(tokens[i]);
}
free(tokens);
}
char* string_replace(const char *str, const char *old, const char *new) {
char *result;
int i, count = 0;
int new_len = string_length(new);
int old_len = string_length(old);
// Count occurrences
for (i = 0; str[i] != '\0'; i++) {
if (strstr(&str[i], old) == &str[i]) {
count++;
i += old_len - 1;
}
}
// Allocate memory for new string
result = malloc(i + count * (new_len - old_len) + 1);
i = 0;
while (*str) {
if (strstr(str, old) == str) {
strcpy(&result[i], new);
i += new_len;
str += old_len;
} else {
result[i++] = *str++;
}
}
result[i] = '\0';
return result;
}
String Functions Comparison Table
| Function | Purpose | Return Value | Safety |
|---|---|---|---|
strlen(s) | Length of s | Number of chars | Safe |
strcpy(d,s) | Copy s to d | Pointer to d | Unsafe (no bounds check) |
strncpy(d,s,n) | Copy up to n chars | Pointer to d | Safer (may not null-terminate) |
strcat(d,s) | Append s to d | Pointer to d | Unsafe |
strncat(d,s,n) | Append up to n chars | Pointer to d | Safer |
strcmp(s1,s2) | Compare s1 and s2 | <0,0,>0 | Safe |
strncmp(s1,s2,n) | Compare first n chars | <0,0,>0 | Safe |
strchr(s,c) | Find first c | Pointer or NULL | Safe |
strrchr(s,c) | Find last c | Pointer or NULL | Safe |
strstr(s,sub) | Find substring | Pointer or NULL | Safe |
strtok(s,d) | Tokenize string | Token pointer | Modifies string |
memcpy(d,s,n) | Copy memory | Pointer to d | No overlap |
memmove(d,s,n) | Copy memory | Pointer to d | Handles overlap |
memset(s,c,n) | Set memory | Pointer to s | Safe |
memcmp(s1,s2,n) | Compare memory | <0,0,>0 | Safe |
Best Practices
Do's and Don'ts
// DO: Check buffer sizes
char dest[10];
if (strlen(src) < sizeof(dest)) {
strcpy(dest, src);
} else {
// Handle error
}
// DON'T: Ignore buffer sizes
strcpy(dest, src); // Potential buffer overflow
// DO: Use strncpy with explicit null termination
strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0';
// DON'T: Assume strncpy null-terminates
strncpy(dest, src, sizeof(dest)); // May not be null-terminated
// DO: Use snprintf for safe formatting
snprintf(buffer, sizeof(buffer), "%s %d", name, age);
// DON'T: Use sprintf without bounds
sprintf(buffer, "%s %d", name, age); // Potential overflow
// DO: Check for NULL pointers
if (str != NULL) {
process(str);
}
// DON'T: Pass NULL to string functions
process(str); // Crashes if str is NULL
Common Pitfalls
// 1. Forgetting null terminator
char str[5] = {'H', 'e', 'l', 'l', 'o'}; // No null terminator!
printf("%s\n", str); // Undefined behavior
// 2. Using strcpy with insufficient space
char small[5];
strcpy(small, "Hello, World!"); // Buffer overflow
// 3. Assuming strncpy always null-terminates
char buf[10];
strncpy(buf, "Hello", 10); // OK - room for null
strncpy(buf, "Hello, World!", 10); // No null terminator!
// 4. Modifying string literals
char *str = "Hello";
str[0] = 'h'; // Undefined behavior (string literal may be read-only)
// 5. Comparing strings with ==
char s1[] = "Hello";
char s2[] = "Hello";
if (s1 == s2) { // Compares addresses, not content!
// Won't execute
}
if (strcmp(s1, s2) == 0) { // Correct way
// Executes
}
Performance Considerations
#include <stdio.h>
#include <string.h>
#include <time.h>
#define ITERATIONS 1000000
int main() {
char str[100] = "Hello, World!";
clock_t start, end;
// strlen called repeatedly (inefficient)
start = clock();
for (int i = 0; i < ITERATIONS; i++) {
for (int j = 0; j < strlen(str); j++) { // strlen called each iteration
// Do nothing
}
}
end = clock();
printf("strlen in loop: %ld ticks\n", end - start);
// strlen called once (efficient)
start = clock();
int len = strlen(str);
for (int i = 0; i < ITERATIONS; i++) {
for (int j = 0; j < len; j++) {
// Do nothing
}
}
end = clock();
printf("strlen outside: %ld ticks\n", end - start);
return 0;
}
Conclusion
String functions in C provide powerful tools for text manipulation:
Key Takeaways
- Always check buffer sizes to prevent overflow
- Use safer alternatives like
strncpy,strncat,snprintf - Remember null termination when using bounded functions
- Check return values especially for search functions
- Be careful with string literals (read-only)
- Use
strcmp()not==for string comparison - strtok() modifies the original string
- Consider performance for repeated operations
When to Use Which Function
- Copying:
strcpy(safe size),strncpy(bounded) - Concatenation:
strcat(safe size),strncat(bounded) - Comparison:
strcmp(full),strncmp(partial) - Search:
strchr(character),strstr(substring) - Tokenization:
strtok(simple), custom parser (complex) - Memory:
memcpy(no overlap),memmove(with overlap)
Mastering string functions is essential for C programming, as strings are used in virtually every application.
Complete C Programming Guide + Compilers Collection
1. C srand() Function – Understanding Seed Initialization
https://macronepal.com/understanding-the-c-srand-function
Explains how srand() initializes the pseudo-random number generator in C by setting a seed value. Using the same seed produces the same sequence, while time(NULL) gives different results each run.
2. C rand() Function Mechanics and Limitations
https://macronepal.com/c-rand-function-mechanics-and-limitations
Explains how rand() generates pseudo-random numbers between 0 and RAND_MAX, its deterministic nature, and limitations for security use cases.
3. C log() Function
https://macronepal.com/c-log-function-2
Covers natural logarithm calculation using <math.h> and its applications.
4. Mastering Date and Time in C
https://macronepal.com/mastering-date-and-time-in-c
Explains <time.h> functions like time(), clock(), difftime(), and struct tm.
5. Mastering time_t Type in C
https://macronepal.com/mastering-the-c-time_t-type-for-time-management
Explains time representation as seconds since Unix epoch and conversion functions.
6. C exp() Function
https://macronepal.com/c-exp-function-mechanics-and-implementation
Explains exponential function exp(x) and its scientific applications.
7. C log() Function (Alternate Guide)
https://macronepal.com/c-log-function
Comparison of log() and log10() with usage examples.
8. C log10() Function
https://macronepal.com/mastering-the-log10-function-in-c
Explains base-10 logarithm for engineering and scientific applications.
9. C tan() Function
https://macronepal.com/understanding-the-c-tan-function
Explains tangent function and radian-based calculations.
10. Random Numbers in C (Secure vs Predictable)
https://macronepal.com/mastering-c-random-numbers-for-secure-and-predictable-applications
Explains difference between rand() and secure randomness methods.
11. Free Online C Compiler
https://macronepal.com/free-online-c-code-compiler-2
Browser-based compiler for testing C programs instantly.
C Functions, Arguments, Parameters & Flow
Mastering Functions in C – Complete Guide
https://macronepal.com/c/mastering-functions-in-c-a-complete-guide/
Covers function structure, modular programming, and real-world usage.
Function Arguments in C
https://macronepal.com/c-function-arguments/
Explains how arguments are passed and used in function calls.
Function Parameters in C
https://macronepal.com/c-function-parameters/
Explains defining inputs for functions and matching them with arguments.
Function Declarations in C
https://macronepal.com/c-function-declarations-syntax-rules-and-best-practices/
Covers prototypes, syntax rules, and best practices.
Function Calls in C
https://macronepal.com/understanding-function-calls-in-c-syntax-mechanics-and-best-practices/
Explains execution flow and parameter handling during function calls.
Void Functions in C
https://macronepal.com/understanding-void-functions-in-c-syntax-patterns-and-best-practices/
Explains functions that do not return values.
Return Values in C
https://macronepal.com/c-return-values-mechanics-types-and-best-practices/
Explains different return types and how functions return results.
Pass-by-Value in C
https://macronepal.com/aws/understanding-pass-by-value-in-c-mechanics-implications-and-best-practices/
Explains how copies of variables are passed into functions.
Pass-by-Reference in C
https://macronepal.com/c/understanding-pass-by-reference-in-c-pointers-semantics-and-safe-practices/
Explains using pointers to modify original variables.
C strstr() Function
https://macronepal.com/aws/c-strstr-function/
Explains substring search inside strings in C.
C Preprocessor & Macros
https://macronepal.com/mastering-c-variadic-macros-for-flexible-debugging/
https://macronepal.com/mastering-the-stdc-macro-in-c/
https://macronepal.com/c-time-macro-mechanics-and-usage/
https://macronepal.com/understanding-the-c-date-macro/
https://macronepal.com/c-file-type/
https://macronepal.com/mastering-c-line-macro-for-debugging-and-diagnostics/
https://macronepal.com/mastering-predefined-macros-in-c/
https://macronepal.com/c-error-directive-mechanics-and-usage/
https://macronepal.com/understanding-the-c-pragma-directive/
https://macronepal.com/c-include-directive/
C Structures, Memory, Scope & Linkage
https://macronepal.com/mastering-structures-in-c/
https://macronepal.com/c-structure-declaration-mechanics-and-usage/
https://macronepal.com/c-structure-initialization-mechanics-and-best-practices/
https://macronepal.com/mastering-c-structure-member-access-for-reliable-data-handling/
https://macronepal.com/c-nested-structures/
https://macronepal.com/mastering-arrays-of-structures-in-c/
https://macronepal.com/c-structure-pointers-mechanics-and-implementation/
https://macronepal.com/understanding-c-structure-parameter-passing-mechanics/
https://macronepal.com/mastering-c-returning-structures-for-efficient-data-flow/
https://macronepal.com/c-self-referential-structures/
https://macronepal.com/mastering-structure-alignment-in-c/
https://macronepal.com/c-structure-padding-mechanics-and-optimization/
https://macronepal.com/understanding-c-flexible-array-members-mechanics-and-usage/
https://macronepal.com/mastering-c-anonymous-structures-for-flattened-data-layouts/
https://macronepal.com/c-unions/
https://macronepal.com/mastering-c-name-mangling-and-symbol-decoration/
https://macronepal.com/c-no-linkage-mechanics-and-scope-isolation/
https://macronepal.com/understanding-c-internal-linkage-mechanics-and-architecture/
C Scope, Storage Classes & Typedef
https://macronepal.com/mastering-function-prototype-scope-in-c/
https://macronepal.com/c-function-scope-mechanics-and-visibility/
https://macronepal.com/understanding-c-file-scope-mechanics-and-architecture/
https://macronepal.com/mastering-c-scope-rules-for-predictable-name-resolution/
https://macronepal.com/c-scope-rules/
https://macronepal.com/mastering-c-register-storage-class-for-historical-context-and-modern-alternatives/
https://macronepal.com/mastering-_thread_local-in-c/
https://macronepal.com/c-extern-storage-class-mechanics-and-usage/
https://macronepal.com/understanding-the-c-static-storage-class-mechanics-and-usage/
https://macronepal.com/c-auto-storage-class/
https://macronepal.com/c-typedef-with-pointers/
Extra Articles
https://macronepal.com/13757-2/
https://macronepal.com/13748-2/
https://macronepal.com/13747-2/
https://macronepal.com/13746-2/
https://macronepal.com/13745-2/
https://macronepal.com/13708-2/
https://macronepal.com/13707-2/
https://macronepal.com/13702-2/
Online Compilers
https://macronepal.com/free-html-online-code-compiler/
https://macronepal.com/free-online-python-code-compiler/
https://macronepal.com/free-online-python2-code-compiler/
https://macronepal.com/free-online-java-code-compiler/
https://macronepal.com/free-online-javascript-code-compiler/
https://macronepal.com/free-online-node-js-code-compiler/
https://macronepal.com/free-online-c-code-compiler/
https://macronepal.com/free-online-c-code-compiler-2/
https://macronepal.com/free-online-c-code-compiler-3/
https://macronepal.com/free-online-php-code-compiler/
https://macronepal.com/free-online-ruby-code-compiler/
https://macronepal.com/free-online-perl-code-compiler/
https://macronepal.com/free-online-lua-code-compiler/
https://macronepal.com/free-online-tcl-code-compiler/
https://macronepal.com/free-online-groovy-code-compiler/
https://macronepal.com/free-online-j-shell-code-compiler/
https://macronepal.com/free-online-haskell-code-compiler/
https://macronepal.com/free-online-scala-code-compiler/
https://macronepal.com/free-online-common-lisp-code-compiler/
https://macronepal.com/free-online-d-code-compiler/
https://macronepal.com/free-online-ada-code-compiler/
https://macronepal.com/free-erlang-code-compiler/
https://macronepal.com/free-online-assembly-code-compiler/
