Chapter 16Beginner

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.

20 min readUpdated 2024-12-16
stringschar arraynull terminator\0strlenstrcpystrcmpfgets

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').

🔤 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.

H
e
l
l
o
\0

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:

📝 This program shows 4 different ways to declare strings and prints each one. Note the difference between arrays and pointers!

string_declaration.c
C
1#include <stdio.h>
2
3int main() {
4 // Method 1: Character array with size
5 char name[10] = "Alice"; // Allocates 10 bytes, uses 6 (5+\0)
6
7 // Method 2: Let compiler determine size
8 char greeting[] = "Hello"; // Compiler allocates 6 bytes
9
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 strings
17 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

1

char name[10] = "Alice" — Allocates 10 bytes, stores "Alice" + \0 (6 bytes used, 4 empty).

2

char greeting[] = "Hello" — Compiler counts and allocates exactly 6 bytes (5 chars + null terminator).

3

{'C', 'a', 't', '\\0'} — Manual char-by-char. You must add \0 or string functions will fail!

4

char *message = "World" — Pointer to a string literal stored in read-only memory. Cannot modify!

5

%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

main.c
C
char *str = "Hello";
str[0] = 'J'; // CRASH! String literals are read-only
char str2[] = "Hello";
str2[0] = 'J'; // OK! This is a modifiable array

03String Memory Layout

Understanding how strings are stored in memory is crucial for avoiding bugs.

char str[10] = "Hello";

H

[0]

e

[1]

l

[2]

l

[3]

o

[4]

\0

[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

📝 This program demonstrates the difference between sizeof() and strlen(), and prints the memory address of each character in the string.

string_size.c
C
1#include <stdio.h>
2#include <string.h> // For strlen()
3
4int main() {
5 char str[] = "Hello";
6
7 // sizeof() returns total array size (including \0)
8 printf("sizeof(str): %zu bytes\n", sizeof(str)); // 6
9
10 // strlen() returns string length (excluding \0)
11 printf("strlen(str): %zu characters\n", strlen(str)); // 5
12
13 // Show address of each character
14 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)); // 100
32 printf("strlen(buffer): %zu\n", strlen(buffer)); // 2
33
34 return 0;
35}
Output — string_size.c

$ ./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

H

[0]

5001

e

[1]

5002

l

[2]

5003

l

[3]

5004

o

[4]

5005

\0

[5]

Index (i)CharacterCalculationAddress
0'H'5000 + 05000
1'e'5000 + 15001
2'l'5000 + 25002
3'l'5000 + 35003
4'o'5000 + 45004
5'\0'5000 + 55005

📝 This program prints each character's memory address and demonstrates pointer arithmetic — showing how ptr+2 moves 2 bytes forward.

string_address.c
C
1#include <stdio.h>
2
3int 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 calculation
10 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 strings
18 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.

string_input.c
C
1#include <stdio.h>
2#include <string.h>
3
4int 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 overflow
11 printf("Name: %s\n", name);
12
13 // Clear input buffer after scanf
14 while (getchar() != '\n');
15
16 // Method 2: fgets (reads full line) - RECOMMENDED
17 printf("Enter city name: ");
18 fgets(city, sizeof(city), stdin);
19
20 // Remove trailing newline from fgets
21 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:

#include <string.h>
FunctionPrototypeReturns
strlensize_t strlen(const char *s)Length of string (not counting \0)
strcpychar *strcpy(char *dest, const char *src)Pointer to dest
strcatchar *strcat(char *dest, const char *src)Pointer to dest
strcmpint strcmp(const char *s1, const char *s2)0 if equal, <0 if s1<s2, >0 if s1>s2
strchrchar *strchr(const char *s, int c)Pointer to char, or NULL if not found
strstrchar *strstr(const char *s1, const char *s2)Pointer to substring, or NULL if not found

📝 This program demonstrates the 5 most important string functions: strlen, strcpy, strcat, strcmp, and strchr. Each function is used with a practical example.

string_functions.c
C
1#include <stdio.h>
2#include <string.h>
3
4int main() {
5 // strlen - Get length
6 char msg[] = "Hello";
7 printf("Length: %zu\n", strlen(msg)); // 5
8
9 // strcpy - Copy string
10 char dest[20];
11 strcpy(dest, "World");
12 printf("Copied: %s\n", dest); // World
13
14 // strcat - Concatenate
15 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 prints
27 } else {
28 printf("%s comes after %s\n", a, b);
29 }
30
31 // strchr - Find character
32 char *found = strchr("Hello", 'l');
33 if (found) {
34 printf("Found 'l' at position: %ld\n", found - "Hello"); // 2
35 }
36
37 return 0;
38}

🔍 How These String Functions Work

1

strlen("Hello") — Counts characters until \0. Returns 5 (doesn't count the null terminator).

2

strcpy(dest, "World") — Copies each character from source to destination, including \0.

3

strcat(greeting, "World!") — Finds the \0 in greeting, then appends source characters there.

4

strcmp("apple", "banana") — Compares char by char. Returns <0 because 'a' (97) < 'b' (98) in ASCII.

5

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:

main.c
C
strncpy(dest, src, sizeof(dest) - 1); // Safer
dest[sizeof(dest) - 1] = '\0'; // Ensure null termination

06Comparing Strings

❌ You Cannot Use == to Compare Strings!

main.c
C
char a[] = "Hello";
char b[] = "Hello";
if (a == b) { // WRONG! Compares memory addresses, not content
printf("Equal"); // This won't print!
}

📝 This program shows the correct way to compare strings using strcmp(). It demonstrates equal strings, different strings, and alphabetical ordering.

string_compare.c
C
1#include <stdio.h>
2#include <string.h>
3
4int 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 equal
20 // <0 if str1 comes before str2 alphabetically
21 // >0 if str1 comes after str2 alphabetically
22
23 printf("strcmp(\"apple\", \"banana\"): %d\n", strcmp("apple", "banana")); // -1
24 printf("strcmp(\"cat\", \"car\"): %d\n", strcmp("cat", "car")); // positive
25 printf("strcmp(\"hello\", \"hello\"): %d\n", strcmp("hello", "hello")); // 0
26
27 return 0;
28}

07Common String Mistakes

❌ Forgetting Null Terminator

main.c
C
char str[5] = {'H', 'e', 'l', 'l', 'o'}; // No \0!
printf("%s", str); // Undefined behavior - prints garbage after "Hello"

❌ Buffer Too Small

main.c
C
char str[5] = "Hello"; // Needs 6 bytes! (5 chars + \0)
// This may cause overflow

❌ Modifying String Literals

main.c
C
char *str = "Hello";
str[0] = 'J'; // CRASH! String literals are read-only

❌ Using = to Assign Strings

main.c
C
char str[10];
str = "Hello"; // ERROR! Cannot assign arrays like this
// Correct way:
strcpy(str, "Hello");

08Summary

What You Learned:

  • Strings: Character arrays ending with \0 (null terminator)
  • Memory: String needs length + 1 bytes (for \0)
  • Input: Use fgets() for safe string input
  • Functions: strlen, strcpy, strcat, strcmp from <string.h>
  • Comparison: Use strcmp(), not == operator

09Next Steps

Continue learning about other derived data types: