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() {
// Method 1: Character array with size
char str1[20]; // Can hold up to 19 characters + null
// Method 2: Character array with initialization
char str2[] = "Hello World"; // Size automatically calculated (12)
// Method 3: Character pointer to string literal
char *str3 = "Hello World"; // Read-only memory
// Method 4: Using strcpy() after declaration
char str4[20];
strcpy(str4, "Hello World");
// Display all strings
printf("str1: %s (uninitialized)\n", str1);
printf("str2: %s (size: %lu)\n", str2, strlen(str2));
printf("str3: %s\n", str3);
printf("str4: %s\n", str4);
// Visualize str2 memory layout
printf("\nMemory layout of str2 \"Hello World\":\n");
for(int i = 0; i <= strlen(str2); i++) {
if(str2[i] == '\0')
printf("Index %d: '\\0' (null terminator)\n", i);
else
printf("Index %d: '%c'\n", i, str2[i]);
}
return 0;
}
str1: �▯▯� (uninitialized - garbage values)
str2: Hello World (size: 11)
str3: Hello World
str4: Hello World
Memory layout of str2 "Hello World":
Index 0: 'H'
Index 1: 'e'
Index 2: 'l'
Index 3: 'l'
Index 4: 'o'
Index 5: ' '
Index 6: 'W'
Index 7: 'o'
Index 8: 'r'
Index 9: 'l'
Index 10: 'd'
Index 11: '\0' (null terminator)
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>
#include <string.h>
int main() {
char name[50];
char sentence[100];
// 1. printf() - Output string
printf("=== STRING OUTPUT ===\n");
printf("Hello, World!\n");
// 2. puts() - Output string with newline
puts("This is puts() function");
// 3. scanf() - Input string (stops at whitespace)
printf("\nEnter your first name (no spaces): ");
scanf("%s", name);
printf("Hello, %s!\n", name);
// Clear input buffer
while(getchar() != '\n');
// 4. fgets() - Safe string input (with spaces)
printf("\nEnter a sentence (with spaces): ");
fgets(sentence, sizeof(sentence), stdin);
// Remove newline from fgets
sentence[strcspn(sentence, "\n")] = '\0';
printf("You entered: %s\n", sentence);
// 5. sprintf() - Format string into buffer
char buffer[100];
int age = 25;
sprintf(buffer, "Name: %s, Age: %d", name, age);
printf("\nFormatted string: %s\n", buffer);
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's a comprehensive reference:
| 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 |
- 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
Practical String Examples
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main() {
char str1[50] = "Hello";
char str2[50] = "World";
char result[100];
printf("=== BASIC STRING OPERATIONS ===\n\n");
// 1. String length
printf("1. strlen():\n");
printf(" Length of '%s': %lu\n", str1, strlen(str1));
// 2. String copy
printf("\n2. strcpy():\n");
strcpy(result, str1);
printf(" After strcpy, result: %s\n", result);
// 3. String concatenation
printf("\n3. strcat():\n");
strcat(result, " ");
strcat(result, str2);
printf(" After strcat, result: %s\n", result);
// 4. String comparison
printf("\n4. strcmp():\n");
int cmp = strcmp(str1, str2);
if(cmp < 0)
printf(" '%s' comes before '%s'\n", str1, str2);
else if(cmp > 0)
printf(" '%s' comes after '%s'\n", str1, str2);
else
printf(" Strings are equal\n");
// 5. String search
printf("\n5. strchr() and strstr():\n");
char *pos = strchr(result, 'W');
if(pos)
printf(" Found 'W' at position: %ld\n", pos - result);
char *sub = strstr(result, "World");
if(sub)
printf(" Found 'World' at position: %ld\n", sub - result);
// 6. String tokenization
printf("\n6. strtok() - Tokenization:\n");
char text[] = "apple,banana,cherry,date";
char *token = strtok(text, ",");
printf(" Tokens: ");
while(token != NULL) {
printf("%s ", token);
token = strtok(NULL, ",");
}
printf("\n");
return 0;
}
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int validatePassword(char *password) {
int hasUpper = 0, hasLower = 0, hasDigit = 0, hasSpecial = 0;
int length = strlen(password);
// Check length
if(length < 8) {
printf("Password must be at least 8 characters long.\n");
return 0;
}
// Check each character
for(int i = 0; i < length; i++) {
if(isupper(password[i])) hasUpper = 1;
else if(islower(password[i])) hasLower = 1;
else if(isdigit(password[i])) hasDigit = 1;
else if(!isalnum(password[i])) hasSpecial = 1;
}
// Display validation results
printf("\n=== PASSWORD VALIDATION REPORT ===\n");
printf("Length: %d characters %s\n", length,
length >= 8 ? "[✓]" : "[✗]");
printf("Uppercase letter: %s\n", hasUpper ? "[✓]" : "[✗]");
printf("Lowercase letter: %s\n", hasLower ? "[✓]" : "[✗]");
printf("Digit: %s\n", hasDigit ? "[✓]" : "[✗]");
printf("Special character: %s\n", hasSpecial ? "[✓]" : "[✗]");
// Check all conditions
if(hasUpper && hasLower && hasDigit && hasSpecial) {
printf("\nPassword is STRONG! ✅\n");
return 1;
} else {
printf("\nPassword is WEAK! ❌\n");
return 0;
}
}
int main() {
char password[100];
char confirm[100];
printf("=== PASSWORD VALIDATOR ===\n\n");
do {
printf("Create a new password: ");
fgets(password, sizeof(password), stdin);
password[strcspn(password, "\n")] = '\0';
if(!validatePassword(password)) {
printf("\nPlease try again with a stronger password.\n\n");
continue;
}
printf("\nConfirm password: ");
fgets(confirm, sizeof(confirm), stdin);
confirm[strcspn(confirm, "\n")] = '\0';
if(strcmp(password, confirm) != 0) {
printf("Passwords do not match! Try again.\n\n");
} else {
printf("\nPassword successfully set! ✅\n");
break;
}
} while(1);
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