Strings in C
Strings are character arrays ending with \0. Learn to create strings, read them safely, and use string functions like strlen, strcpy, strcmp.
Track Your Progress
Sign in to save your learning progress
What You Will Learn
- ✓Understand strings as char arrays with \0
- ✓Create and initialize strings
- ✓Read strings safely with fgets (not gets!)
- ✓Use string functions: strlen, strcpy, strcmp
01What is a String?
In C, a string is simply an array of characters that ends with a special character called the null terminator ('\0').
A String = Character Array + Null Terminator
Unlike some languages where strings are a built-in type, C doesn't have a dedicated string type. Instead, strings are arrays of char.
The string "Hello" is stored as 6 characters (5 letters + null terminator)
Why the Null Terminator?
The \0 character tells functions like printf()where the string ends. Without it, functions would keep reading random memory until they crash!
02Declaring Strings
There are several ways to create strings in C:
▶ Try it: Shows 4 different ways to declare strings. Note the difference between arrays and pointers!
1#include <stdio.h>23int main() {4 // Method 1: Character array with size5 char name[10] = "Alice"; // Allocates 10 bytes, uses 6 (5+\0)6 7 // Method 2: Let compiler determine size8 char greeting[] = "Hello"; // Compiler allocates 6 bytes9 10 // Method 3: Character by character (must add \0!)11 char word[4] = {'C', 'a', 't', '\0'};12 13 // Method 4: Pointer to string literal (read-only!)14 char *message = "World";15 16 // Print all strings17 printf("Name: %s\n", name);18 printf("Greeting: %s\n", greeting);19 printf("Word: %s\n", word);20 printf("Message: %s\n", message);21 22 return 0;23}How This Program Works
char name[10] = "Alice" — Allocates 10 bytes, stores "Alice" + \0 (6 bytes used, 4 empty).
char greeting[] = "Hello" — Compiler counts and allocates exactly 6 bytes (5 chars + null terminator).
{'C', 'a', 't', '\\0'} — Manual char-by-char. You must add \0 or string functions will fail!
char *message = "World" — Pointer to a string literal stored in read-only memory. Cannot modify!
%s format specifier — Prints characters until it finds \0. That's why null terminator is essential!
char name[] = "Alice";
- • Creates a modifiable character array
- • You can change individual characters
- • Stored in stack memory
char *name = "Alice";
- • Pointer to a read-only string literal
- • Cannot modify characters!
- • String stored in read-only memory
Common Mistake
char *str = "Hello";str[0] = 'J'; // CRASH! String literals are read-onlychar str2[] = "Hello";str2[0] = 'J'; // OK! This is a modifiable array03String Memory Layout
Understanding how strings are stored in memory is crucial for avoiding bugs.
char str[10] = "Hello";
[0]
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]
Used (5 chars)
H, e, l, l, o
Null terminator
\0 (ASCII 0)
Unused space
Contains garbage
String Size Calculation
Array size needed = string length + 1 (for \0)
For "Hello": 5 characters + 1 null = 6 bytes minimum
▶ Try it: Demonstrates the difference between sizeof() and strlen(), and prints the memory address of each character.
1#include <stdio.h>2#include <string.h> // For strlen()34int main() {5 char str[] = "Hello";6 7 // sizeof() returns total array size (including \0)8 printf("sizeof(str): %zu bytes\n", sizeof(str)); // 69 10 // strlen() returns string length (excluding \0)11 printf("strlen(str): %zu characters\n", strlen(str)); // 512 13 // Show address of each character14 printf("\n--- Address Calculation for \"%s\" ---\n", str);15 printf("Base Address: %p\n\n", (void*)str);16 printf("Index | Char | Address | Calculation\n");17 printf("----------------------------------------------\n");18 for (int i = 0; i <= strlen(str); i++) {19 if (str[i] == '\0') {20 printf(" %d | \\0 | %p | Base + %d\n", 21 i, (void*)&str[i], i);22 } else {23 printf(" %d | '%c' | %p | Base + %d\n", 24 i, str[i], (void*)&str[i], i);25 }26 }27 printf("----------------------------------------------\n");28 29 // Important difference!30 char buffer[100] = "Hi";31 printf("\nsizeof(buffer): %zu\n", sizeof(buffer)); // 10032 printf("strlen(buffer): %zu\n", strlen(buffer)); // 233 34 return 0;35}$ ./string_size
sizeof(str): 6 bytes
strlen(str): 5 characters
--- Address Calculation for "Hello" ---
Base Address: 0x7ffd5c3e1a40
Index | Char | Address | Calculation
----------------------------------------------
0 | 'H' | 0x7ffd5c3e1a40 | Base + 0
1 | 'e' | 0x7ffd5c3e1a41 | Base + 1
2 | 'l' | 0x7ffd5c3e1a42 | Base + 2
3 | 'l' | 0x7ffd5c3e1a43 | Base + 3
4 | 'o' | 0x7ffd5c3e1a44 | Base + 4
5 | \0 | 0x7ffd5c3e1a45 | Base + 5
----------------------------------------------
sizeof(buffer): 100
strlen(buffer): 2
Notice: Each address differs by only 1 byte (1a40 → 1a41 → 1a42...) because sizeof(char) = 1
Address Calculation in Strings
Since strings are just character arrays, address calculation is simpler than numeric arrays. Each char is exactly 1 byte, so the formula simplifies beautifully!
# String Address Formula
Address of str[i] = Base Address + i
Since sizeof(char) = 1, the formula becomes: Base + (i × 1) = Base + i
Base Address
Address of first character str[0]
i (Index)
Position of character (0, 1, 2...)
Example: char str[] = "Hello" with Base = 5000
5000
[0]
5001
[1]
5002
[2]
5003
[3]
5004
[4]
5005
[5]
| Index (i) | Character | Calculation | Address |
|---|---|---|---|
| 0 | 'H' | 5000 + 0 | 5000 |
| 1 | 'e' | 5000 + 1 | 5001 |
| 2 | 'l' | 5000 + 2 | 5002 |
| 3 | 'l' | 5000 + 3 | 5003 |
| 4 | 'o' | 5000 + 4 | 5004 |
| 5 | '\0' | 5000 + 5 | 5005 |
▶ Try it: Prints each character's memory address and demonstrates pointer arithmetic (ptr+2 moves 2 bytes forward).
1#include <stdio.h>23int main() {4 char str[] = "Hello";5 6 // Base address (address of first character)7 printf("Base Address (str or &str[0]): %p\n\n", (void*)str);8 9 // Demonstrate address calculation10 printf("Character addresses in \"Hello\":\n");11 for (int i = 0; str[i] != '\0'; i++) {12 printf("str[%d] = '%c' at address %p (Base + %d)\n", 13 i, str[i], (void*)&str[i], i);14 }15 printf("str[5] = '\\0' at address %p (Base + 5)\n", (void*)&str[5]);16 17 // Pointer arithmetic with strings18 printf("\nPointer arithmetic:\n");19 char *ptr = str;20 printf("ptr = %p (points to '%c')\n", (void*)ptr, *ptr);21 printf("ptr + 2 = %p (points to '%c')\n", (void*)(ptr + 2), *(ptr + 2));22 printf("ptr + 4 = %p (points to '%c')\n", (void*)(ptr + 4), *(ptr + 4));23 24 return 0;25}Why Strings Are Simpler
For other data types, address = base + (i × size). But since sizeof(char) = 1, strings follow the simplest formula: address = base + i.
This is why pointer arithmetic with strings is so intuitive — incrementing a char*pointer by 1 moves exactly 1 byte to the next character!
Pointer Arithmetic with Strings
Understanding address calculation helps you understand pointer arithmetic:
Array Notation
str[3]
Access 4th character directly
Pointer Notation
*(str + 3)
Base + 3, then dereference
Both are equivalent! str[i] is just syntactic sugar for *(str + i)
04Reading Strings from User
scanf("%s", str) - Limited
- • Stops at first whitespace
- • No buffer overflow protection
- • Use %99s for size limit (buffer-1)
fgets(str, size, stdin) - Recommended
- • Reads entire line including spaces
- • Built-in buffer overflow protection
- • Includes newline character \n
This interactive program reads user input using both scanf (limited) and fgets (recommended), showing how to handle the input buffer properly.
1#include <stdio.h>2#include <string.h>34int main() {5 char name[50];6 char city[50];7 8 // Method 1: scanf (stops at space)9 printf("Enter first name: ");10 scanf("%49s", name); // %49s prevents overflow11 printf("Name: %s\n", name);12 13 // Clear input buffer after scanf14 while (getchar() != '\n');15 16 // Method 2: fgets (reads full line) - RECOMMENDED17 printf("Enter city name: ");18 fgets(city, sizeof(city), stdin);19 20 // Remove trailing newline from fgets21 city[strcspn(city, "\n")] = '\0';22 23 printf("City: %s\n", city);24 25 return 0;26}Best Practice
Always use fgets() for reading strings. It's safer because it limits how many characters are read and prevents buffer overflow attacks.
05String Functions (<string.h>)
The <string.h> library provides many useful functions for working with strings. You must include this header to use these functions:
| Function | Prototype | Returns |
|---|---|---|
| strlen | size_t strlen(const char *s) | Length of string (not counting \0) |
| strcpy | char *strcpy(char *dest, const char *src) | Pointer to dest |
| strcat | char *strcat(char *dest, const char *src) | Pointer to dest |
| strcmp | int strcmp(const char *s1, const char *s2) | 0 if equal, <0 if s1<s2, >0 if s1>s2 |
| strchr | char *strchr(const char *s, int c) | Pointer to char, or NULL if not found |
| strstr | char *strstr(const char *s1, const char *s2) | Pointer to substring, or NULL if not found |
▶ Try it: Demonstrates the 5 most important string functions: strlen, strcpy, strcat, strcmp, and strchr.
1#include <stdio.h>2#include <string.h>34int main() {5 // strlen - Get length6 char msg[] = "Hello";7 printf("Length: %zu\n", strlen(msg)); // 58 9 // strcpy - Copy string10 char dest[20];11 strcpy(dest, "World");12 printf("Copied: %s\n", dest); // World13 14 // strcat - Concatenate15 char greeting[50] = "Hello, ";16 strcat(greeting, "World!");17 printf("Joined: %s\n", greeting); // Hello, World!18 19 // strcmp - Compare (returns 0 if equal)20 char a[] = "apple";21 char b[] = "banana";22 int result = strcmp(a, b);23 if (result == 0) {24 printf("Strings are equal\n");25 } else if (result < 0) {26 printf("%s comes before %s\n", a, b); // This prints27 } else {28 printf("%s comes after %s\n", a, b);29 }30 31 // strchr - Find character32 char *found = strchr("Hello", 'l');33 if (found) {34 printf("Found 'l' at position: %ld\n", found - "Hello"); // 235 }36 37 return 0;38}How These String Functions Work
strlen("Hello") — Counts characters until \0. Returns 5 (doesn't count the null terminator).
strcpy(dest, "World") — Copies each character from source to destination, including \0.
strcat(greeting, "World!") — Finds the \0 in greeting, then appends source characters there.
strcmp("apple", "banana") — Compares char by char. Returns <0 because 'a' (97) < 'b' (98) in ASCII.
strchr("Hello", 'l') — Returns pointer to first 'l'. Subtract string start to get index: position 2.
Buffer Overflow Warning
strcpy() and strcat() don't check buffer sizes! Use strncpy() and strncat() for safer alternatives:
strncpy(dest, src, sizeof(dest) - 1); // Saferdest[sizeof(dest) - 1] = '\0'; // Ensure null termination06Comparing Strings
You Cannot Use == to Compare Strings!
char a[] = "Hello";char b[] = "Hello";if (a == b) { // WRONG! Compares memory addresses, not content printf("Equal"); // This won't print!}▶ Try it: Shows the correct way to compare strings using strcmp() - equal strings, different strings, and alphabetical ordering.
1#include <stdio.h>2#include <string.h>34int main() {5 char str1[] = "Hello";6 char str2[] = "Hello";7 char str3[] = "World";8 9 // Correct way: Use strcmp()10 if (strcmp(str1, str2) == 0) {11 printf("str1 and str2 are EQUAL\n"); // This prints!12 }13 14 if (strcmp(str1, str3) != 0) {15 printf("str1 and str3 are DIFFERENT\n"); // This prints!16 }17 18 // strcmp returns:19 // 0 if strings are equal20 // <0 if str1 comes before str2 alphabetically21 // >0 if str1 comes after str2 alphabetically22 23 printf("strcmp(\"apple\", \"banana\"): %d\n", strcmp("apple", "banana")); // -124 printf("strcmp(\"cat\", \"car\"): %d\n", strcmp("cat", "car")); // positive25 printf("strcmp(\"hello\", \"hello\"): %d\n", strcmp("hello", "hello")); // 026 27 return 0;28}!Code Pitfalls: Common Mistakes & What to Watch For
These are the most common mistakes that trip up beginners. Study them carefully to avoid hours of debugging!
Forgetting Null Terminator
char str[5] = {'H', 'e', 'l', 'l', 'o'}; // No \0!printf("%s", str); // Undefined behavior - prints garbage after "Hello"Buffer Too Small
char str[5] = "Hello"; // Needs 6 bytes! (5 chars + \0)// This may cause overflowModifying String Literals
char *str = "Hello";str[0] = 'J'; // CRASH! String literals are read-onlyUsing = to Assign Strings
char str[10];str = "Hello"; // ERROR! Cannot assign arrays like this// Correct way:strcpy(str, "Hello");Watch Out When Copying Code!
Strings Are C's #1 Source of Security Vulnerabilities!
Copied string code is often vulnerable to buffer overflows — the most exploited security flaw in history:
1. Using Deprecated gets()
You may still find gets() which has NO length limit — guaranteed buffer overflow:
char name[10];gets(name); // NEVER USE! Removed from C11// Safe alternative:fgets(name, sizeof(name), stdin);2. Forgetting Space for Null Terminator
"Hello" needs 6 bytes (5 letters + \0), but Copied code might allocate only 5:
char str[5];strcpy(str, "Hello"); // BUG! Writes 6 bytes into 5-byte buffer// Correct:char str[6]; // 5 chars + 1 for \03. Using strcpy Without Size Check
strcpy() copies until \0 with no length limit. You should use strncpy() orsnprintf() to limit the copy length.
Golden Rules: (1) Always allocate +1 for null terminator, (2) Use "n" versions of functions (strncpy, snprintf), (3) Never use gets().
10Frequently Asked Questions
Q:What is the null terminator and why is it important?
A: The null terminator (\0, ASCII value 0) marks the end of a string. C has no string length stored anywhere — functions likeprintf, strlen read characters until they hit \0. Without it, they keep reading garbage memory until they crash or find a random 0. Always ensure your strings are null-terminated!
Q:What's the difference between char str[] and char *str?
A: char str[] = "Hello" creates a modifiable array on the stack containing the characters.char *str = "Hello" creates a pointer to aread-only string literal in memory. You can modify str[] but attempting to modify *str causes undefined behavior (usually a crash).
Q:Why can't I compare strings with == ?
A: == comparesaddresses, not contents. "Hello" == "Hello" checks if they're at the same memory location (usually false!). Usestrcmp(str1, str2) == 0 to compare contents.strcmp returns 0 if equal, negative if str1 < str2, positive if str1 > str2 (alphabetically).
Q:Why does fgets() include the newline character?
A: fgets preserves the newline from when you pressed Enter. This is by design — it tells you the user finished input. To remove it: str[strcspn(str, "\n")] = '\0'; or manually check and replace. Always account for this extra character in your buffer size calculations.
Q:What's the difference between strlen() and sizeof() for strings?
A: strlen() returns the length of the string (characters until \0).sizeof() returns the allocated buffer size. For char str[20] = "Hi": strlen(str) = 2,sizeof(str) = 20. Note: sizeof on a pointer returns pointer size (8), not string length!
Q:How do I concatenate (join) two strings?
A: Use strcat(dest, src) or safer strncat(dest, src, n). The destination must have enough space for both strings plus \0!strcat appends src to the end of dest. For formatted concatenation, use sprintf(dest, "%s%s", str1, str2) or safer snprintf.
Q:Why does printf show garbage after my string?
A: Your string is missing the null terminator!printf keeps reading memory until it finds\0. This happens when you: (1) Manually fill a char array without adding \0, (2) Use strncpywhich doesn't add null if the source is too long, (3) Overflow a buffer destroying the terminator. Always ensure strings end with \0.
10Summary
What You Learned:
- ✓WHY: C doesn't have a string type - we use character arrays
- ✓Null terminator: Every string ends with \0 (very important!)
- ✓Safe input: Use fgets() instead of gets() or scanf()
- ✓Functions: strlen, strcpy, strcmp from <string.h>
Test Your Knowledge
Related Tutorials
Arrays in C
Store multiple values of the same type together! Learn 1D arrays (lists), 2D arrays (tables), and how arrays are stored in memory.
C string.h Library Reference
Complete reference for string.h - strlen, strcpy, strcat, strcmp, searching, and memory functions.
Structures in C
Group related data together! Create your own data types with struct. Store a student's name, age, and grade in one variable.
Have Feedback?
Found something missing or have ideas to improve this tutorial? Let us know on GitHub!