C String Functions: Complete Guide with Examples
C String Functions: A Comprehensive Tutorial
String functions in C are built-in library functions used to perform common operations on strings, such as copying, comparing, concatenating, and searching. These functions are declared in the <string.h> header file (except sprintf, which is in <stdio.h>). Understanding string functions is essential for efficient and safe string manipulation in C.
This tutorial provides an in-depth exploration of C string functions: their syntax, usage, return values, common pitfalls, and best practices for safe string handling.
Conceptual Introduction & Fundamentals
What are String Functions?
String functions are pre-written functions that operate on C strings (null-terminated character arrays). They provide standardized, efficient implementations of common string operations, eliminating the need to write manual loops for every string task.
Why Use String Functions?
- Efficiency: Optimized implementations by compiler/library vendors.
- Reliability: Well-tested and standardized.
- Readability: Code is cleaner and more maintainable.
- Portability: Available on all standard-compliant C implementations.
- Productivity: Write less code for common operations.
The <string.h> Header
Most string functions are declared in <string.h>. To use them:
c
#include <string.h>
Categories of String Functions
| Category | Functions |
|---|---|
| Length | strlen |
| Copy | strcpy, strncpy |
| Concatenate | strcat, strncat |
| Compare | strcmp, strncmp |
| Search | strchr, strrchr, strstr |
| Format | sprintf (from <stdio.h>) |
| Tokenize | strtok |
Safety Considerations
Many traditional string functions (strcpy, strcat, sprintf) do not check buffer sizes, making them prone to buffer overflows. Prefer safer alternatives:
| Unsafe | Safer Alternative |
|---|---|
strcpy | strncpy or snprintf |
strcat | strncat or snprintf |
sprintf | snprintf |
gets | fgets |
Syntax & Core Mechanics
strlen() — String Length
Returns the number of characters in a string, excluding the null terminator.
c
#include <stdio.h> #include <string.h> int main(void) { char s[] = "Gfg"; size_t length = strlen(s); printf("Length: %zu\n", length); printf("Array size: %zu\n", sizeof(s)); /* Includes null */ return 0; } Expected output:
text
Length: 3 Array size: 4
strcpy() — String Copy
Copies the source string (including null terminator) to the destination.
c
#include <stdio.h> #include <string.h> int main(void) { char src[] = "Hello"; char dest[20]; strcpy(dest, src); printf("dest: %s\n", dest); return 0; } Expected output:
text
dest: Hello
strncpy() — Bounded String Copy
Copies at most n characters. If the source is shorter than n, pads with nulls.
c
#include <stdio.h> #include <string.h> int main(void) { char src[] = "Hello"; char dest[20] = "XXXXXXXXXX"; /* Pre-filled for demonstration */ strncpy(dest, src, 4); dest[4] = '\0'; /* Ensure null termination */ printf("dest: %s\n", dest); return 0; } Expected output:
text
dest: Hell
Note: strncpy does not guarantee null termination if n <= source length. Always add null manually.
strcat() — String Concatenate
Appends source to the end of destination.
c
#include <stdio.h> #include <string.h> int main(void) { char s1[30] = "Hello, "; char s2[] = "Geeks!"; strcat(s1, s2); printf("s1: %s\n", s1); return 0; } Expected output:
text
s1: Hello, Geeks!
strncat() — Bounded String Concatenate
Appends at most n characters from source to destination.
c
#include <stdio.h> #include <string.h> int main(void) { char s1[30] = "Hello, "; char s2[] = "Geeks!"; strncat(s1, s2, 4); printf("s1: %s\n", s1); return 0; } Expected output:
text
s1: Hello, Geek
strcmp() — String Compare
Compares two strings lexicographically. Returns:
- 0 if equal
- Negative if first < second
- Positive if first > second
c
#include <stdio.h> #include <string.h> int main(void) { char s1[] = "Apple"; char s2[] = "Applet"; int result = strcmp(s1, s2); if (result == 0) { printf("s1 and s2 are same\n"); } else if (result < 0) { printf("s1 is lexicographically smaller than s2\n"); } else { printf("s1 is lexicographically greater than s2\n"); } return 0; } Expected output:
text
s1 is lexicographically smaller than s2
strncmp() — Bounded String Compare
Compares first n characters.
c
#include <stdio.h> #include <string.h> int main(void) { char s1[] = "Apple"; char s2[] = "Applet"; int result = strncmp(s1, s2, 4); if (result == 0) { printf("First 4 characters are same\n"); } return 0; } Expected output:
text
First 4 characters are same
strchr() — Find First Character
Returns pointer to first occurrence of character, or NULL.
c
#include <stdio.h> #include <string.h> int main(void) { char s[] = "Hello, World!"; char *result = strchr(s, 'o'); if (result != NULL) { printf("Character found at index: %ld\n", result - s); } else { printf("Character not found\n"); } return 0; } Expected output:
text
Character found at index: 4
strrchr() — Find Last Character
Returns pointer to last occurrence of character.
c
#include <stdio.h> #include <string.h> int main(void) { char s[] = "Hello, World!"; char *result = strrchr(s, 'o'); if (result != NULL) { printf("Character found at index: %ld\n", result - s); } return 0; } Expected output:
text
Character found at index: 8
strstr() — Find Substring
Returns pointer to first occurrence of substring.
c
#include <stdio.h> #include <string.h> int main(void) { char s[] = "Hello, Geeks!"; char *pos = strstr(s, "Geeks"); if (pos != NULL) { printf("Found: %s\n", pos); } else { printf("Not Found\n"); } return 0; } Expected output:
text
Found: Geeks!
sprintf() — Format String to Buffer
Formats data into a string buffer. Declared in <stdio.h>.
c
#include <stdio.h> int main(void) { char buffer[50]; int n = 10; sprintf(buffer, "The value is %d", n); printf("%s\n", buffer); return 0; } Expected output:
text
The value is 10
Safer alternative: snprintf
c
char buffer[50]; snprintf(buffer, sizeof(buffer), "The value is %d", n);
strtok() — Tokenize String
Splits a string into tokens based on delimiters. Modifies the original string.
c
#include <stdio.h> #include <string.h> int main(void) { char s[] = "Hello, Geeks, C!"; char *token = strtok(s, ", "); while (token != NULL) { printf("%s\n", token); token = strtok(NULL, ", "); } return 0; } Expected output:
text
Hello Geeks C!
Note: strtok modifies the original string and is not thread-safe. Use strtok_r for reentrant version (POSIX).
Full Practical Code Example with Explanation
This program demonstrates all major string functions in a realistic scenario: a simple text processing and validation system.
Program: String Functions Demo
c
/** * string_functions_demo.c * Demonstrates all major C string functions. * Includes safe usage patterns and error handling. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <stdbool.h> #define MAX_LINE_LEN 200 #define MAX_STR_LEN 100 /* Function prototypes */ void demonstrateLength(void); void demonstrateCopy(void); void demonstrateConcatenate(void); void demonstrateCompare(void); void demonstrateSearch(void); void demonstrateFormat(void); void demonstrateTokenize(void); int readInteger(const char *prompt, int *outValue); int main(void) { int choice; char buffer[MAX_LINE_LEN]; printf("=== C String Functions Demo ===\n"); while (1) { printf("\n--- Menu ---\n"); printf("1. strlen - String Length\n"); printf("2. strcpy/strncpy - String Copy\n"); printf("3. strcat/strncat - String Concatenate\n"); printf("4. strcmp/strncmp - String Compare\n"); printf("5. strchr/strrchr/strstr - Search\n"); printf("6. sprintf - Format String\n"); printf("7. strtok - Tokenize String\n"); printf("8. Exit\n"); printf("Enter choice: "); fflush(stdout); if (fgets(buffer, sizeof(buffer), stdin) == NULL) { fprintf(stderr, "Error reading choice.\n"); return EXIT_FAILURE; } choice = atoi(buffer); switch (choice) { case 1: demonstrateLength(); break; case 2: demonstrateCopy(); break; case 3: demonstrateConcatenate(); break; case 4: demonstrateCompare(); break; case 5: demonstrateSearch(); break; case 6: demonstrateFormat(); break; case 7: demonstrateTokenize(); break; case 8: printf("Exiting.\n"); return EXIT_SUCCESS; default: printf("Invalid choice. Please try again.\n"); break; } } return EXIT_SUCCESS; } /* Demonstrates strlen */ void demonstrateLength(void) { printf("\n=== strlen ===\n"); char str1[] = "Hello"; char str2[] = ""; char str3[] = "A"; printf("strlen(\"%s\") = %zu\n", str1, strlen(str1)); printf("strlen(\"%s\") = %zu\n", str2, strlen(str2)); printf("strlen(\"%s\") = %zu\n", str3, strlen(str3)); printf("\nManual length calculation:\n"); size_t len = 0; while (str1[len] != '\0') { len++; } printf("Manual strlen(\"%s\") = %zu\n", str1, len); } /* Demonstrates strcpy and strncpy */ void demonstrateCopy(void) { printf("\n=== strcpy / strncpy ===\n"); char src[] = "Hello World"; char dest1[50]; char dest2[20] = "XXXXXXXXXXXXXXXX"; /* Pre-filled */ /* strcpy */ strcpy(dest1, src); printf("strcpy: dest1 = \"%s\"\n", dest1); /* strncpy with explicit null termination */ strncpy(dest2, src, 5); dest2[5] = '\0'; /* Ensure null termination */ printf("strncpy (5 chars): dest2 = \"%s\"\n", dest2); /* strncpy when source is shorter */ char shortSrc[] = "Hi"; char dest3[10] = "XXXXXXXXX"; strncpy(dest3, shortSrc, 5); /* Remaining characters are padded with nulls */ printf("strncpy (short source): dest3[0] = '%c', dest3[1] = '%c', dest3[2] = '%d'\n", dest3[0], dest3[1], dest3[2]); } /* Demonstrates strcat and strncat */ void demonstrateConcatenate(void) { printf("\n=== strcat / strncat ===\n"); char s1[50] = "Hello, "; char s2[] = "Geeks!"; char s3[50] = "Hello, "; /* strcat */ strcat(s1, s2); printf("strcat: \"%s\"\n", s1); /* strncat */ strncat(s3, s2, 4); printf("strncat (4 chars): \"%s\"\n", s3); /* Safe concatenation using snprintf */ char safe[50]; snprintf(safe, sizeof(safe), "%s%s", "Hello, ", "Geeks!"); printf("snprintf: \"%s\"\n", safe); } /* Demonstrates strcmp and strncmp */ void demonstrateCompare(void) { printf("\n=== strcmp / strncmp ===\n"); char s1[] = "Apple"; char s2[] = "Applet"; char s3[] = "apple"; printf("strcmp(\"%s\", \"%s\") = %d\n", s1, s2, strcmp(s1, s2)); printf("strcmp(\"%s\", \"%s\") = %d\n", s1, s3, strcmp(s1, s3)); printf("strcmp(\"%s\", \"%s\") = %d\n", s1, s1, strcmp(s1, s1)); printf("strncmp(\"%s\", \"%s\", 4) = %d\n", s1, s2, strncmp(s1, s2, 4)); printf("strncmp(\"%s\", \"%s\", 5) = %d\n", s1, s2, strncmp(s1, s2, 5)); } /* Demonstrates search functions */ void demonstrateSearch(void) { printf("\n=== Search Functions ===\n"); char s[] = "Hello, World! Hello again!"; /* strchr */ char *first_o = strchr(s, 'o'); if (first_o != NULL) { printf("strchr: first 'o' at index %ld\n", first_o - s); } /* strrchr */ char *last_o = strrchr(s, 'o'); if (last_o != NULL) { printf("strrchr: last 'o' at index %ld\n", last_o - s); } /* strstr */ char *substring = strstr(s, "World"); if (substring != NULL) { printf("strstr: \"World\" found at index %ld\n", substring - s); printf(" Remaining: \"%s\"\n", substring); } /* strchr with character not in string */ char *notFound = strchr(s, 'z'); if (notFound == NULL) { printf("strchr: 'z' not found (NULL returned)\n"); } } /* Demonstrates sprintf */ void demonstrateFormat(void) { printf("\n=== sprintf / snprintf ===\n"); char buffer[100]; int age = 25; double score = 95.5; char name[] = "Alice"; /* sprintf */ sprintf(buffer, "Name: %s, Age: %d, Score: %.2f", name, age, score); printf("sprintf: \"%s\"\n", buffer); /* snprintf (safer) */ snprintf(buffer, sizeof(buffer), "Name: %s, Age: %d, Score: %.2f", name, age, score); printf("snprintf: \"%s\"\n", buffer); /* snprintf with truncation */ snprintf(buffer, 10, "Name: %s", "VeryLongNameHere"); printf("snprintf (truncated): \"%s\"\n", buffer); } /* Demonstrates strtok */ void demonstrateTokenize(void) { printf("\n=== strtok ===\n"); char s[] = "Hello, Geeks, C, Programming!"; char *delimiter = ", "; printf("Original string: \"%s\"\n", s); printf("Tokens:\n"); char *token = strtok(s, delimiter); int tokenCount = 0; while (token != NULL) { printf(" Token %d: \"%s\"\n", ++tokenCount, token); token = strtok(NULL, delimiter); } printf("After strtok, original string: \"%s\"\n", s); printf("(Original string has been modified)\n"); } Explanation of String Functions
strlen: Counts characters until null.strcpy/strncpy: Copies strings;strncpyrequires manual null termination.strcat/strncat: Appends strings;strncatis safer.strcmp/strncmp: Lexicographic comparison.strchr/strrchr/strstr: Search for characters/substrings.sprintf/snprintf: Format strings into buffers.strtok: Tokenizes strings (modifies original).
Expected Output (sample run)
text
=== C String Functions Demo === --- Menu --- 1. strlen - String Length 2. strcpy/strncpy - String Copy 3. strcat/strncat - String Concatenate 4. strcmp/strncmp - String Compare 5. strchr/strrchr/strstr - Search 6. sprintf - Format String 7. strtok - Tokenize String 8. Exit Enter choice: 1 === strlen === strlen("Hello") = 5 strlen("") = 0 strlen("A") = 1 Manual length calculation: Manual strlen("Hello") = 5 --- Menu --- ... Enter choice: 7 === strtok === Original string: "Hello, Geeks, C, Programming!" Tokens: Token 1: "Hello" Token 2: "Geeks" Token 3: "C" Token 4: "Programming!" After strtok, original string: "Hello" (Original string has been modified) Common Pitfalls, Edge Cases & Memory Considerations
1. Buffer Overflow with strcpy and strcat
These functions don’t check destination size, causing buffer overflows.
c
char dest[5]; strcpy(dest, "Hello World"); // BUG: overflow (12 chars into 5-byte buffer)
Solution: Use strncpy with manual null termination, or snprintf.
2. strncpy Not Null-Terminating
If n is less than or equal to the source length, strncpy does not add null terminator.
c
char src[] = "Hello"; char dest[5]; strncpy(dest, src, 5); // dest is not null-terminated printf("%s\n", dest); // BUG: reads past buffer Solution: Always add null: dest[4] = '\0';
3. strlen on Uninitialized String
Calling strlen on an uninitialized string is undefined behavior.
c
char str[20]; strlen(str); // BUG: garbage data
Solution: Initialize strings: char str[20] = "";
4. strtok Modifies Original String
strtok replaces delimiters with null characters, destroying the original string.
c
char s[] = "Hello, World"; strtok(s, ", "); printf("%s\n", s); // Prints "Hello" (original modified) Solution: Make a copy before using strtok if you need the original.
5. strtok Not Thread-Safe
strtok uses a static internal buffer, making it unsafe in multi-threaded programs.
Solution: Use strtok_r (POSIX) for thread-safe tokenization.
6. sprintf Buffer Overflow
sprintf does not check buffer size.
c
char buffer[10]; sprintf(buffer, "Value: %d", 123456789); // BUG: overflow
Solution: Use snprintf(buffer, sizeof(buffer), ...).
7. strcmp with Non-String Data
strcmp expects null-terminated strings. Passing non-string data is undefined.
c
char data[5] = {'A', 'B', 'C', 'D', 'E'}; // No null strcmp(data, "ABCDE"); // BUG: data is not a string Solution: Ensure null termination: char data[6] = {'A', 'B', 'C', 'D', 'E', '\0'};
8. strchr Returning NULL
Dereferencing the result of strchr without checking for NULL causes crash.
c
char *result = strchr(s, 'z'); printf("%c\n", *result); // BUG: NULL dereference if not found Solution: Always check for NULL before dereferencing.
9. String Concatenation Overhead
Repeated strcat calls in loops are inefficient (O(n²) due to repeated scanning).
Solution: Track the end position and copy directly, or use snprintf for combined formatting.
10. Memory Considerations
strtokuses static memory (not thread-safe).strcpyandstrcatdo not allocate memory; they write to existing buffers.- Always ensure destination buffers are large enough.
- Consider using
strdup(POSIX) to create copies on the heap (remember tofree).
Summary & Best Practices
C string functions provide powerful tools for string manipulation. Understanding their behavior, limitations, and safe usage patterns is essential for writing robust programs.
Key Takeaways
strlenreturns length excluding null.strcpy/strncpycopy strings;strncpyneeds manual null termination.strcat/strncatconcatenate strings;strncatis safer.strcmp/strncmpcompare strings lexicographically.strchr/strrchr/strstrsearch for characters/substrings.sprintf/snprintfformat strings (prefersnprintf).strtoktokenizes strings (modifies original, not thread-safe).
Best Practices
- Prefer
snprintfoversprintffor safe formatting. - Use
strncpywith manual null termination orsnprintfinstead ofstrcpy. - Use
strncatinstead ofstrcatfor bounded concatenation. - Always check for
NULLfrom search functions before dereferencing. - Make a copy before using
strtokif the original string is needed. - Use
strtok_rin multi-threaded programs. - Ensure destination buffers are large enough for all operations.
- Initialize strings before using string functions.
- Use
sizeoffor buffer capacity when callingsnprintforfgets. - Enable compiler warnings (
-Wall -Wextra) to catch potential issues.
By mastering C string functions and following safe practices, you’ll write robust programs that handle text processing efficiently without buffer overflows or undefined behavior.



