C Strings - Complete Guide
Master C strings with detailed syntax, built-in functions, practical examples, and programming best practices for effective string manipulation.
String Functions
Complete reference
Practical Examples
Real-world usage
Common Pitfalls
Avoid mistakes
Introduction to C Strings
In C programming, strings are arrays of characters terminated by a null character ('\0'). Strings are fundamental for text processing, user input, file handling, and data manipulation.
Key Characteristics
- Null-terminated: Always ends with '\0'
- Character Arrays: Strings are char arrays
- Immutable Literals: String literals are read-only
- Header File: Functions in <string.h>
- Memory Management: Manual allocation needed
String Types in C
- String Literals: "Hello" (read-only)
- Character Arrays: char str[10] (mutable)
- Pointers to Strings: char *str (dynamic)
- Array of Strings: 2D char array
- Formatted Strings: sprintf() output
Important String Concepts
Strings in C are null-terminated character arrays. The null character ('\0') marks the end. String length doesn't include null terminator. Always allocate size + 1 for the null character.
String Declaration and Initialization
Strings can be declared and initialized in several ways. Understanding these methods is crucial for proper string manipulation.
Common Syntax Patterns:
char str1[20]; // Declaration with size
char str2[] = "Hello World"; // Auto-size initialization
char *str3 = "Hello World"; // Pointer to string literal
char str4[] = {'H','e','l','l','o','\0'}; // Character array
Examples:
#include <stdio.h>
#include <string.h>
int main() {
char arr[] = "Hello"; /* modifiable array */
char *ptr = "World"; /* pointer to literal (read-only) */
char buf[20];
strcpy(buf, arr);
printf("%s %s\n", buf, ptr);
printf("Length of arr: %zu\n", strlen(arr));
return 0;
}
Hello World
Length of arr: 5
Memory Visualization:
String: "Hello" (6 bytes including '\0')
String length: 5 characters | Memory: 6 bytes (including null terminator)
char *str = "Hello"; creates a string literal in read-only memory.char str[] = "Hello"; creates a modifiable character array on stack.Never modify string literals as it causes undefined behavior.
String Input/Output Functions
C provides several functions for reading and writing strings. Understanding their differences is crucial for safe programming.
#include <stdio.h>
int main() {
char name[20];
char line[50];
printf("Enter name (no spaces): ");
scanf("%19s", name);
printf("Hello, %s!\n", name);
while (getchar() != '\n'); /* clear buffer */
printf("Enter a line: ");
fgets(line, sizeof(line), stdin);
puts(line);
return 0;
}
| Function | Usage | Pros | Cons | When to Use |
|---|---|---|---|---|
scanf("%s") |
Reads until whitespace | Simple, formatted input | No space support, buffer overflow risk | Single words, known format |
fgets() |
Reads with size limit | Safe, reads spaces, includes newline | Includes newline, needs cleanup | Always for user input |
gets() |
Reads until newline | Simple syntax | Extremely dangerous, deprecated | Never use! |
printf() |
Formatted output | Flexible formatting | No automatic newline | General output |
puts() |
Simple output | Automatic newline, simple | No formatting | Simple messages |
String Built-in Functions Reference
The <string.h> header provides numerous functions for string manipulation. Here is an expanded reference of common functions from <string.h> and related headers:
| Function | Syntax | Description | Return Value | Category |
|---|---|---|---|---|
strlen()
|
size_t strlen(const char *str)
|
Returns length of string (excluding '\0') | Length as size_t | Length |
strcpy()
|
char *strcpy(char *dest, const char *src)
|
Copies source string to destination | Pointer to destination | Copy |
strcat()
|
char *strcat(char *dest, const char *src)
|
Appends source string to destination | Pointer to destination | Concatenation |
strcmp()
|
int strcmp(const char *str1, const char *str2)
|
Compares two strings lexicographically | <0, 0, or >0 | Comparison |
strchr()
|
char *strchr(const char *str, int c)
|
Finds first occurrence of character | Pointer to char or NULL | Search |
strtok()
|
char *strtok(char *str, const char *delim)
|
Breaks string into tokens | Pointer to token or NULL | Tokenization |
memcpy()
|
void *memcpy(void *dest, const void *src, size_t n)
|
Copies n bytes from source to destination | Pointer to destination | Memory |
atoi()
|
int atoi(const char *str)
|
Converts string to integer | Converted integer | Conversion |
strncpy() |
char *strncpy(char *dest, const char *src, size_t n) |
Copy at most n characters; may not add \0 if src longer than n |
Pointer to dest | Copy |
strncat() |
char *strncat(char *dest, const char *src, size_t n) |
Append at most n characters from src | Pointer to dest | Concatenation |
strncmp() |
int strncmp(const char *s1, const char *s2, size_t n) |
Compare at most n characters | <0, 0, or >0 | Comparison |
strstr() |
char *strstr(const char *haystack, const char *needle) |
Find first occurrence of substring | Pointer or NULL | Search |
strrchr() |
char *strrchr(const char *str, int c) |
Find last occurrence of character | Pointer or NULL | Search |
strspn() |
size_t strspn(const char *str, const char *accept) |
Length of initial segment matching accept chars | Count | Search |
strcspn() |
size_t strcspn(const char *str, const char *reject) |
Length before first char in reject set | Count | Search |
strpbrk() |
char *strpbrk(const char *str, const char *accept) |
Find first char in str that appears in accept | Pointer or NULL | Search |
strnlen() |
size_t strnlen(const char *str, size_t max) |
Length up to max chars (C11) | Length | Length |
memset() |
void *memset(void *s, int c, size_t n) |
Set n bytes to value c (often 0 to clear) | Pointer to s | Memory |
memmove() |
void *memmove(void *dest, const void *src, size_t n) |
Copy n bytes; safe if regions overlap | Pointer to dest | Memory |
memcmp() |
int memcmp(const void *s1, const void *s2, size_t n) |
Compare first n bytes | <0, 0, or >0 | Memory |
memchr() |
void *memchr(const void *s, int c, size_t n) |
Search n bytes for byte c | Pointer or NULL | Memory |
atol() |
long atol(const char *str) |
Convert string to long (stdlib.h) |
long value | Conversion |
atof() |
double atof(const char *str) |
Convert string to double (stdlib.h) |
double value | Conversion |
- Always include
#include <string.h>for string functions - Functions with 'n' (like strncpy, strncat) are safer as they limit operations
- Check return values for NULL when using search functions
- Ensure destination buffers are large enough for operations
- Use
memmove()instead ofmemcpy()when memory regions overlap
Implementing Built-in Functions in C
Understanding how standard string functions work helps you debug, interview, and write safer code. Below are simple educational versions of common <string.h> routines. They are not replacements for the library — use the real functions in production.
my_strlen — like strlen()
Count characters until '\0'.
#include <stdio.h>
size_t my_strlen(const char *s) {
size_t len = 0;
while (s[len] != '\0')
len++;
return len;
}
int main() {
printf("Length = %zu\n", my_strlen("Hello"));
return 0;
}
my_strcpy — like strcpy()
Copy source into destination including the null terminator.
#include <stdio.h>
char *my_strcpy(char *dest, const char *src) {
char *start = dest;
while ((*dest++ = *src++) != '\0')
;
return start;
}
int main() {
char buf[20];
my_strcpy(buf, "C strings");
printf("%s\n", buf);
return 0;
}
my_strcmp — like strcmp()
Compare unsigned char values; return negative, zero, or positive.
#include <stdio.h>
int my_strcmp(const char *a, const char *b) {
while (*a && (*a == *b)) {
a++;
b++;
}
return (unsigned char)*a - (unsigned char)*b;
}
int main() {
printf("cat vs dog: %d\n", my_strcmp("cat", "dog"));
printf("abc vs abc: %d\n", my_strcmp("abc", "abc"));
return 0;
}
my_strcat — like strcat()
Find end of dest, then append src.
#include <stdio.h>
char *my_strcat(char *dest, const char *src) {
char *start = dest;
while (*dest)
dest++;
while ((*dest++ = *src++) != '\0')
;
return start;
}
int main() {
char buf[30] = "Hello";
my_strcat(buf, " World");
printf("%s\n", buf);
return 0;
}
my_strchr — like strchr()
Return pointer to first match or NULL.
#include <stdio.h>
char *my_strchr(const char *s, int c) {
while (*s) {
if (*s == (char)c)
return (char *)s;
s++;
}
return (c == '\0') ? (char *)s : NULL;
}
int main() {
char text[] = "programming";
char *p = my_strchr(text, 'g');
if (p)
printf("First 'g' at: %s\n", p);
return 0;
}
Demo: library vs our versions
#include <stdio.h>
#include <string.h>
size_t my_strlen(const char *s) {
size_t n = 0;
while (s[n]) n++;
return n;
}
int my_strcmp(const char *a, const char *b) {
while (*a && *a == *b) { a++; b++; }
return (unsigned char)*a - (unsigned char)*b;
}
int main() {
const char *word = "LearnHub";
printf("strlen: lib=%zu mine=%zu\n", strlen(word), my_strlen(word));
printf("strcmp: lib=%d mine=%d\n",
strcmp(word, "LearnHub"), my_strcmp(word, "LearnHub"));
return 0;
}
Learning tip
Real <string.h> functions are highly optimized and handle edge cases. Practice writing your own once, then always prefer strncpy, strncat, and bounded buffers in real projects.
Practical String Examples
#include <stdio.h>
#include <string.h>
int main() {
char s[30] = "Hello";
char t[30];
printf("strlen = %zu\n", strlen(s));
strcpy(t, s);
strcat(t, " C");
printf("after strcat: %s\n", t);
printf("strcmp with \"Hello C\" = %d\n", strcmp(t, "Hello C"));
return 0;
}
#include <stdio.h>
#include <string.h>
int main() {
char a[20], b[20];
printf("Enter two words: ");
scanf("%19s %19s", a, b);
if (strcmp(a, b) == 0)
printf("Strings are equal\n");
else
printf("Strings are different\n");
return 0;
}
Common Mistakes and Best Practices
String Best Practices:
- Always use fgets() instead of gets() for input
- Check buffer sizes before string operations
- Use 'n' versions of functions (strncpy, strncat) for safety
- Always null-terminate strings manually if building them
- Validate input strings before processing
- Use sizeof() for array sizes, not hardcoded numbers
- Handle whitespace properly (trim if needed)
- Be careful with string literals vs character arrays
- Always check return values of string functions
- Use const for strings that shouldn't be modified
Key Takeaways
- Strings in C are null-terminated character arrays ('\0' marks end)
- Include
<string.h>for string manipulation functions - Use fgets() for safe input (never use gets())
- Always ensure sufficient buffer size for string operations
- String literals are read-only; use arrays for modifiable strings
- strlen() returns length excluding null terminator
- strcpy()/strcat() vs strncpy()/strncat() - use 'n' versions for safety
- strcmp() returns 0 for equal strings, not 1
- Always null-terminate strings when building them manually
- Use const keyword for strings that shouldn't be modified
- Check for NULL returns from search functions (strchr, strstr)
- Be mindful of buffer overflows - biggest security risk with strings