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/
