GuideC Programming

Character Arrays And Strings

Arrays / Character Arrays And Strings

Concept Lesson
Intermediate
4 min

Learning Objective

Understand Character Arrays And Strings well enough to explain it, recognize it in C Programming, and apply it in a small task.

Why It Matters

This concept is part of the foundation that later lessons and projects assume you already understand.

Table Of ContentsCharacter ArraysDeclaration And InitializationCharacter Vs IntegerAscii Table Common Values
Private notes
0/8000

Notes stay private to your browser until account sync is configured.

Guide
2 min read18 headings

Character Arrays and Strings in C

Table of Contents

  1. Introduction
  2. Character Arrays
  3. Strings in C
  4. String Initialization
  5. String Input/Output
  6. String Library Functions
  7. Common String Operations
  8. Array of Strings
  9. Common Pitfalls
  10. Best Practices
  11. Summary

Introduction

In C, there is no built-in string type like in other languages. Instead, strings are implemented as arrays of characters terminated by a special null character \0.

Understanding character arrays is crucial because:

  • Text processing is fundamental to most programs
  • Many security vulnerabilities come from improper string handling
  • String manipulation requires manual memory management

Character Arrays

Declaration and Initialization

// Character array (not a string - no null terminator)
char letters[5] = {'H', 'e', 'l', 'l', 'o'};

// Memory layout:
// Index:   [0]   [1]   [2]   [3]   [4]
// Value:   'H'   'e'   'l'   'l'   'o'
// ASCII:    72   101   108   108   111

Character vs Integer

char ch = 'A';   // Stores ASCII value 65
char num = 65;   // Also stores 65 (same as 'A')

printf("%c\n", ch);   // Output: A
printf("%d\n", ch);   // Output: 65

ASCII Table (Common Values)

Character    ASCII Value
───────────────────────
'0' - '9'    48 - 57
'A' - 'Z'    65 - 90
'a' - 'z'    97 - 122
' '          32
'\n'         10
'\0'         0

Strings in C

What Makes a String?

A string in C is a character array that ends with the null terminator \0.

char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

// Memory layout:
// Index:   [0]   [1]   [2]   [3]   [4]   [5]
// Value:   'H'   'e'   'l'   'l'   'o'  '\0'
//                                         ↑
//                               Null terminator (required!)

Why Null Terminator?

Without \0, functions don't know where string ends!

char text[10] = "Hi";

Memory might look like:
[0]  [1]  [2]  [3]  [4]  [5]  [6]  [7]  [8]  [9]
'H'  'i'  \0   ???  ???  ???  ???  ???  ???  ???
           ↑
    String ends here (functions stop reading)

String Length vs Array Size

char str[10] = "Hello";

// Array size: 10 bytes (allocated)
// String length: 5 (characters before \0)
// Null terminator at: index 5

sizeof(str)     → 10  (total array size)
strlen(str)     → 5   (number of characters)

String Initialization

Method 1: String Literal

char str1[] = "Hello";       // Size = 6 (includes \0)
char str2[10] = "Hello";     // Size = 10, str ends at index 5
char str3[3] = "Hello";      // WARNING! Only "Hel" stored, no \0

Method 2: Character by Character

char str[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

Method 3: Pointer to String Literal

char *str = "Hello";    // Points to string in read-only memory

// WARNING: Cannot modify string literals!
// str[0] = 'h';  // UNDEFINED BEHAVIOR!

Comparison of Methods

Declaration          Modifiable?   Location
─────────────────────────────────────────────
char str[] = "Hi"    Yes          Stack
char str[10] = "Hi"  Yes          Stack
char *str = "Hi"     NO!          Read-only memory

Visual: String in Memory

char name[10] = "Alice";

Stack Memory:
Address:  1000  1001  1002  1003  1004  1005  1006  1007  1008  1009
Value:    'A'   'l'   'i'   'c'   'e'   '\0'   ?     ?     ?     ?
Index:    [0]   [1]   [2]   [3]   [4]   [5]   [6]   [7]   [8]   [9]
                                         ↑
                              String ends here

String Input/Output

Output with printf

char name[] = "Alice";

printf("%s\n", name);        // Output: Alice
printf("Hello, %s!\n", name); // Output: Hello, Alice!
printf("%.3s\n", name);      // Output: Ali (first 3 chars)
printf("%10s\n", name);      // Right-aligned in 10 chars
printf("%-10s\n", name);     // Left-aligned in 10 chars

Output with puts

char str[] = "Hello";
puts(str);  // Prints "Hello" followed by newline

Input with scanf

char name[50];
scanf("%s", name);   // Note: NO & needed for arrays!

// WARNING: scanf stops at whitespace!
// Input: "John Doe" → name contains only "John"

Input with fgets (Safer)

char line[100];
fgets(line, sizeof(line), stdin);

// Reads entire line including spaces
// Includes newline character if room permits
// Maximum 99 characters + null terminator

Removing Newline from fgets

char line[100];
fgets(line, sizeof(line), stdin);

// Remove trailing newline
size_t len = strlen(line);
if (len > 0 && line[len - 1] == '\n') {
    line[len - 1] = '\0';
}

Character Input with getchar

int ch;
while ((ch = getchar()) != '\n' && ch != EOF) {
    // Process character
    putchar(ch);
}

String Library Functions

Include <string.h> for these functions.

strlen - String Length

char str[] = "Hello";
size_t len = strlen(str);  // Returns 5 (not counting \0)

strcpy - String Copy

char src[] = "Hello";
char dest[10];

strcpy(dest, src);  // Copies "Hello\0" to dest

// WARNING: dest must be large enough!

strncpy - Safe Copy

char src[] = "Hello World";
char dest[6];

strncpy(dest, src, 5);  // Copy at most 5 chars
dest[5] = '\0';         // Ensure null termination

// dest now contains "Hello"

strcat - Concatenate

char str[20] = "Hello";
strcat(str, " World");  // str = "Hello World"

// WARNING: Destination must have enough space!

strncat - Safe Concatenate

char str[15] = "Hello";
strncat(str, " World!", 6);  // Append at most 6 chars
// str = "Hello World"

strcmp - Compare Strings

char a[] = "apple";
char b[] = "banana";

int result = strcmp(a, b);
// result < 0: a comes before b
// result = 0: strings are equal
// result > 0: a comes after b

strncmp - Compare N Characters

char a[] = "Hello World";
char b[] = "Hello There";

int result = strncmp(a, b, 5);  // Compare first 5 chars
// result = 0 (first 5 chars are equal)

strchr - Find Character

char str[] = "Hello World";
char *p = strchr(str, 'W');  // Find first 'W'

if (p != NULL) {
    printf("Found at index: %ld\n", p - str);  // Output: 6
}

strstr - Find Substring

char str[] = "Hello World";
char *p = strstr(str, "Wor");

if (p != NULL) {
    printf("Found: %s\n", p);  // Output: World
}

Quick Reference Table

Function    Purpose                 Returns
─────────────────────────────────────────────
strlen      Length of string        size_t
strcpy      Copy string             char*
strncpy     Copy n characters       char*
strcat      Concatenate             char*
strncat     Concatenate n chars     char*
strcmp      Compare strings         int
strncmp     Compare n chars         int
strchr      Find character          char* or NULL
strstr      Find substring          char* or NULL

Common String Operations

Checking if String is Empty

char str[100];
fgets(str, sizeof(str), stdin);

if (str[0] == '\0' || str[0] == '\n') {
    printf("Empty input\n");
}

Converting Case

#include <ctype.h>

void toUpperCase(char str[]) {
    for (int i = 0; str[i] != '\0'; i++) {
        str[i] = toupper(str[i]);
    }
}

void toLowerCase(char str[]) {
    for (int i = 0; str[i] != '\0'; i++) {
        str[i] = tolower(str[i]);
    }
}

Reversing a String

void reverseString(char str[]) {
    int len = strlen(str);
    for (int i = 0; i < len / 2; i++) {
        char temp = str[i];
        str[i] = str[len - 1 - i];
        str[len - 1 - i] = temp;
    }
}

Counting Words

int countWords(const char str[]) {
    int count = 0;
    int inWord = 0;

    for (int i = 0; str[i] != '\0'; i++) {
        if (str[i] == ' ' || str[i] == '\n' || str[i] == '\t') {
            inWord = 0;
        } else if (!inWord) {
            inWord = 1;
            count++;
        }
    }
    return count;
}

Checking Character Types

#include <ctype.h>

// These functions return non-zero if true, 0 if false
isalpha(c)   // Is letter (a-z, A-Z)?
isdigit(c)   // Is digit (0-9)?
isalnum(c)   // Is letter or digit?
isspace(c)   // Is whitespace?
isupper(c)   // Is uppercase?
islower(c)   // Is lowercase?
ispunct(c)   // Is punctuation?

Array of Strings

Method 1: 2D Character Array

char names[3][20] = {
    "Alice",
    "Bob",
    "Charlie"
};

// Memory: Fixed 20 bytes per string (wasted space)

// Access:
printf("%s\n", names[0]);  // Alice
printf("%c\n", names[1][0]); // B

Method 2: Array of Pointers

char *names[] = {
    "Alice",
    "Bob",
    "Charlie"
};

// Memory: Only pointer size per element
// Strings stored in read-only memory

// Access:
printf("%s\n", names[0]);  // Alice
printf("%c\n", names[1][0]); // B

// WARNING: Cannot modify string literals!

Visual Comparison

2D Array (char names[3][20]):
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│ A l i c e \0 . . .   │  ← 20 bytes each
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│ B o b \0 . . . . .   │  ← Wasted space
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│ C h a r l i e \0 .   │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
Total: 60 bytes

Array of Pointers (char *names[]):
ā”Œā”€ā”€ā”€ā”€ā”€ā”     ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│  ──────→  │ Alice\0  │  (in read-only memory)
ā”œā”€ā”€ā”€ā”€ā”€ā”¤     ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
│  ──────→  │ Bob\0    │
ā”œā”€ā”€ā”€ā”€ā”€ā”¤     ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
│  ──────→  │ Charlie\0│
ā””ā”€ā”€ā”€ā”€ā”€ā”˜     ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
Pointers: 24 bytes (on 64-bit)
Strings: Variable size

Sorting Array of Strings

void sortStrings(char *arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (strcmp(arr[j], arr[j + 1]) > 0) {
                char *temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

Common Pitfalls

1. Forgetting Null Terminator

// WRONG
char str[5] = "Hello";  // No room for \0!

// CORRECT
char str[6] = "Hello";  // 5 chars + \0

2. Buffer Overflow

char small[5];
strcpy(small, "This is too long!");  // DANGER! Buffer overflow

// Use strncpy instead
strncpy(small, "This is too long!", 4);
small[4] = '\0';

3. Comparing Strings with ==

char a[] = "Hello";
char b[] = "Hello";

// WRONG
if (a == b)  // Compares addresses, not content!

// CORRECT
if (strcmp(a, b) == 0)  // Compares content

4. Modifying String Literals

char *str = "Hello";
str[0] = 'h';  // UNDEFINED BEHAVIOR!

// Use array instead
char str[] = "Hello";
str[0] = 'h';  // OK

5. Uninitialized Strings

char str[100];
printf("%s\n", str);  // UNDEFINED! Contains garbage

// Initialize properly
char str[100] = "";  // or = {0}

6. scanf Without Size Limit

char input[10];
scanf("%s", input);  // Dangerous if input > 9 chars

// Safer
scanf("%9s", input);  // Read at most 9 characters

Best Practices

1. Always Allocate Space for \0

// If you need to store 10 characters, allocate 11
char str[11];  // 10 chars + null terminator

2. Use Safe String Functions

// Instead of strcpy, use strncpy
strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0';

// Instead of strcat, use strncat
strncat(dest, src, sizeof(dest) - strlen(dest) - 1);

3. Prefer fgets Over scanf for Strings

// Bad
scanf("%s", input);

// Good
fgets(input, sizeof(input), stdin);

4. Check Return Values

char *result = strchr(str, 'x');
if (result != NULL) {
    // Found it
} else {
    // Not found
}

5. Use const for Read-Only Strings

void printString(const char *str) {
    printf("%s\n", str);
    // str[0] = 'x';  // Error: cannot modify const
}

6. Initialize Strings

char str[100] = "";    // Initialize to empty string
char str[100] = {0};   // Initialize all bytes to 0

Summary

Key Concepts

Concept                 Description
─────────────────────────────────────────────────
Null Terminator        '\0' marks end of string
String Length          Characters before \0
Array Size             Total allocated bytes
String Literal         "text" in quotes (read-only)
Character Array        char[] can be modified
char pointer           char* to literal is read-only

Essential Functions

#include <string.h>

strlen(s)              // Length of string
strcpy(d, s)           // Copy s to d
strncpy(d, s, n)       // Copy up to n chars
strcat(d, s)           // Append s to d
strncat(d, s, n)       // Append up to n chars
strcmp(a, b)           // Compare strings
strncmp(a, b, n)       // Compare n chars
strchr(s, c)           // Find char in string
strstr(s, sub)         // Find substring

Memory Rules

āœ“ char str[] = "Hi";     → Modifiable, on stack
āœ— char *str = "Hi";      → NOT modifiable (literal)
āœ“ char str[10] = "Hi";   → Modifiable, fixed size
āœ“ Always leave room for \0
āœ“ Use strn* functions for safety

Next Steps

After mastering character arrays and strings:

  1. Learn about Pointers for deeper string manipulation
  2. Study Dynamic Memory for variable-length strings
  3. Explore String Algorithms (parsing, tokenizing)

"A string in C is just an array with a promise - the promise of a null terminator."

Skill Check

Test this lesson

Answer 4 quick questions to lock in the lesson and feed your adaptive practice queue.

--
Score
0/4
Answered
Not attempted
Status
1

Which module does this lesson belong to?

2

Which section is covered in this lesson content?

3

Which term is most central to this lesson?

4

What is the best way to use this lesson for real learning?

Your answers save locally first, then sync when account storage is available.
Practice queue