Arrays and Strings in C โ Revision Notes
Arrays and C-strings expose subtle memory behaviour โ array-to-pointer decay, why sizeof differs inside a function, and the null terminator. These are heavily tested in written rounds because a single off-by-one causes a buffer overflow.
Arrays
An array is a contiguous block of same-type elements. The name a usually decays to a pointer to its first element (&a[0]) โ but not under sizeof, &, or in a string literal initializer. So sizeof(a) inside main gives the whole array size, but a function receiving int a[] only sees a pointer.
Strings
A C-string is a char array terminated by a null character '\0'. "hello" occupies 6 bytes (5 letters + terminator). Standard functions rely on that terminator to know where the string ends.
| Function | Purpose | Note |
|---|---|---|
strlen |
length | excludes '\0' |
strcpy |
copy | no bounds check |
strcmp |
compare | 0 if equal |
strcat |
concatenate | destination must have room |
Exam Tricks & Tips
- ๐ฏ
strlen("hello")is 5 but the array needs 6 bytes โ the'\0'is counted in storage, not in length. - ๐ฏ
sizeof(arr)gives the full byte size only where the array is declared; passed to a function it decays to a pointer andsizeofreturns the pointer size. - ๐ฏ
sizeof(arr)/sizeof(arr[0])is the idiom to count elements โ but only valid before decay. - ๐ฏ Array indices start at 0;
a[n]on ann-element array is out of bounds (undefined behavior, not a guaranteed crash). - ๐ฏ
char *s = "hi";points to read-only memory โ modifying it is undefined; usechar s[] = "hi";for a mutable copy. - ๐ฏ
strcpy/strcatdo no bounds checking โ a classic buffer-overflow vector; preferstrncpy/snprintf. - โ Common mistake: comparing strings with
==(compares addresses, not content) instead ofstrcmp.
Expected pattern
"What does sizeof print inside vs outside a function?", off-by-one on the null terminator, "why is str1 == str2 wrong?", and 2D-array element-address arithmetic.
Quick recap
Arrays are contiguous; the name decays to a pointer except under sizeof/&. C-strings end in '\0', so "hello" is 6 bytes though strlen is 5. Use strcmp (not ==) to compare, and bounded functions to avoid overflow.
Arrays and Strings in C โ Flashcards
Cover the answer, recall, then check. 12 cards on C arrays and strings.
Q1. How many bytes does the string literal "hello" occupy?
A1. 6 bytes โ 5 characters plus the null terminator '\0'.
Q2. What does strlen("hello") return?
A2. 5 โ strlen counts characters up to but excluding the null terminator.
Q3. What is "array decay"?
A3. An array name converting to a pointer to its first element in most expressions (e.g. when passed to a function).
Q4. When does an array name NOT decay to a pointer?
A4. Under sizeof, the address-of operator &, and when initializing a char array from a string literal.
Q5. How do you compute the number of elements in an array?
A5. sizeof(arr) / sizeof(arr[0]) โ but only where the array is declared, before it decays.
Q6. Why is sizeof(arr) different inside a function that receives the array?
A6. The parameter is really a pointer (decayed), so sizeof returns the pointer size, not the array size.
Q7. Why is comparing strings with == wrong?
A7. == compares the two pointer addresses, not the character contents; use strcmp (returns 0 if equal).
Q8. Difference between char *s = "hi"; and char s[] = "hi";?
A8. The first points to read-only literal memory (modifying is UB); the second is a mutable local copy.
Q9. Why are strcpy and strcat dangerous?
A9. They do no bounds checking, so they can overflow the destination buffer; prefer strncpy/snprintf.
Q10. What terminates a C-string?
A10. The null character '\0' (value 0).
Q11. Is accessing a[n] on an n-element array safe?
A11. No โ indices run 0..n-1, so a[n] is out of bounds and undefined behavior.
Q12. Are array elements stored contiguously?
A12. Yes โ an array is a single contiguous block of memory, which is why pointer arithmetic works over it.
Arrays and Strings in C
C has no string type. It has arrays of char and a single convention โ a terminating '\0' byte โ and everything from strlen to buffer-overflow exploits follows from that. Understanding arrays and their decay into pointers is the key.
Core idea: an array is a contiguous block of same-typed elements. A C string is simply a char array whose logical end is marked by a null byte '\0' (value 0), not by its allocated length.
How it works
Beginner โ arrays are contiguous
int a[5] = {10, 20, 30}; // a[3], a[4] are zero-initialised
Elements sit back-to-back in memory, so a[i] is found by address arithmetic base + i*sizeof(int) โ O(1) access. C does no bounds checking: a[7] compiles and runs, reading whatever bytes are there. That silence is the root of countless security bugs.
Intermediate โ array-to-pointer decay
In almost every expression, an array name decays to a pointer to its first element. So when you pass a to a function, the function receives an int *, not the array โ the size information is lost.
void f(int arr[]) { printf("%zu\n", sizeof(arr)); } // prints 8 (pointer!), NOT 20
That is why C functions almost always take a length parameter alongside the array. The two places decay does not happen: operands of sizeof and of &.
Advanced โ strings and the null terminator
char s[] = "hi"; // stored as {'h','i','\0'} โ THREE bytes
strlen(s) walks from the start counting until it hits '\0' โ returns 2 (the terminator is not counted), an O(n) scan. sizeof(s) is 3 (includes the terminator). Copying with strcpy(dst, src) copies bytes including the terminator but performs no bounds check โ if dst is smaller than src, you overflow. Safer: strncpy/snprintf with an explicit limit.
Worked example โ strlen vs sizeof
char msg[10] = "code"; // bytes: c o d e \0 \0 \0 \0 \0 \0
printf("%zu %zu\n", strlen(msg), sizeof(msg)); // 4 10
strlen counts up to the first '\0' โ 4. sizeof reports the allocated array size โ 10. Confusing the two is the classic off-by-one/overflow source: you must budget length+1 for the terminator.
Interview & exam relevance
Favourites: "difference between sizeof and strlen", "why does sizeof(arr) inside a function not give the array size" (decay), "reverse a string in place", and reasoning about char *s = "x"; (string literal, read-only) versus char s[] = "x"; (a modifiable copy). Writing to a string literal is undefined behaviour.
Tricks & gotchas
- Always allocate
length + 1bytes for a string to hold the'\0'. - Prefer
snprintfoversprintf/strcpyโ thenvariants take a size bound and prevent overflow. char *p = "hello";points to read-only memory; modifyingp[0]is UB. Usechar p[] = "hello";to get a writable array.- Mnemonic: "sizeof = box, strlen = string."
Forgetting the null terminator when sizing a buffer. To store the 5-character word "hello" you need char buf[6], not buf[5]. Allocating exactly strlen bytes and then strcpy-ing overruns by one byte โ a subtle, corruption-prone bug that may not crash immediately.
- โ- Arrays are contiguous, O(1) indexed, and unchecked โ no bounds safety.
- โ- Array names decay to pointers in expressions, losing size info (except under
sizeof/&). - โ- C strings are
chararrays ending in'\0'; allocate length+1. - โ-
strlenis O(n) up to the terminator;sizeofis the allocated size. - โ- Use bounded copies (
snprintf,strncpy) to avoid overflows.
- โAn array is contiguous unchecked memory; a string is such an array terminated by
'\0'. Respect decay (pass a length), respect the terminator (allocate +1), and prefer bounded string functions.
Arrays and Strings in C โ Worked Example
Worked Example
Problem: Explain the output and the subtle bug.
#include <stdio.h>
#include <string.h>
int main(void) {
char s[] = "hello";
printf("len=%zu size=%zu\n", strlen(s), sizeof s); // (A)
char *p = "world";
int a[5] = {1, 2};
printf("a2=%d a4=%d\n", a[2], a[4]); // (B)
char dst[4];
strcpy(dst, "abcd"); // (C) danger
printf("%s\n", dst);
return 0;
}
Solution:
(A) "hello" is 5 characters plus a terminating '\0'. strlen counts up to but not including '\0', so strlen(s)=5. sizeof s is the whole array including the terminator, so sizeof s=6. This distinction (logical length vs storage size) is a classic exam point.
(B) An array initialised with fewer values than its size has the remaining elements zero-initialised. So a = {1,2,0,0,0}; a[2]=0 and a[4]=0.
(C) dst has room for only 4 chars. "abcd" needs 5 bytes (4 letters + '\0'). strcpy writes past the end of dst โ a buffer overflow (undefined behaviour). The fix is a bounded copy that always leaves room for '\0':
char dst[5];
strncpy(dst, "abcd", sizeof dst - 1);
dst[sizeof dst - 1] = '\0';
Answer: A prints len=5 size=6; B prints a2=0 a4=0; C is a buffer overflow โ dst must be at least 5 bytes and the copy must be bounded.
- โ- strlen = characters before '\0'; sizeof(array) = total bytes including '\0'.
- โ- Partial initialisers zero the remaining array elements.
- โ- Always size a buffer for length + 1 and use bounded copies to avoid overflows.