// Method 1: 2D char array — a rectangular gridchar days[7][10] = {
"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"
}
;
// Method 2: array of pointers — each points to a stringchar *months[] = {
"January", "February", "March", "April"
}
;Array of Strings in C: Storing and Accessing Multiple Text Values
What is Array of Strings in C? Core Concept & Direct Summary
How do you represent collections of strings using 2D character arrays vs arrays of pointers in C?
One string is a char array. So what do you do when you need fifty? A list of names, a set of menu options, a table of words to search?
The answer, in C, is an array of strings — which sounds simple until you realize C gives you two completely different ways to build one, with genuinely different trade-offs. One is a 2D char array; the other is an array of pointers. Beginners often pick the wrong one and then fight the limitations. This tutorial covers both, side by side, so you can choose deliberately.
(Suggested image: the hero graphic — two side-by-side memory diagrams: a rigid 2D grid of fixed-width rows vs a row of pointers each reaching to a right-sized string)
How Does Array of Strings in C Work? In-Depth Mechanics & Architecture
The Two Approaches at a Glance
Both let you write days[2] / months[1] and get the third day / second month. Both print with %s. But under the surface they're different data structures with different capabilities — and the differences determine which one you should pick.
Method 1: The 2D char Array (A Grid of Characters)
What this declares: 3 rows, each holding up to 20 characters. Total memory: 3 × 20 = 60 bytes, regardless of how long the names actually are.
Accessing:
Determining how many strings:sizeof(names) / sizeof(names[0]) → 60 / 20 = 3 rows. (Careful: that gives you the row count, not the length of any individual string — use strlen(names[i]) for those.)
Advantages of the grid
- Writable. Every row is your own memory, so you can modify characters freely. This is the big one.
- Simple, single allocation. One declaration, no pointers to track.
- Easy iteration.
names[i]andnames[i][j]behave exactly like the 2D arrays you already know.
Drawbacks of the grid
- Every row costs the full width. Twenty bytes per name even if the name is three characters. Fifty names with a 50-byte row limit is 2,500 bytes, mostly wasted space.
- The longest string sets the width for everyone. Decide the column size wrong (too small) and your strings silently truncate or overflow.
- Wasted space adds up quickly. For large lists this matters a lot.
Method 2: The Array of Pointers (A List of Addresses)
What this declares: an array of 3 char * pointers — 3 addresses (24 bytes on a 64-bit system), plus the strings themselves stored wherever the literals live (usually a read-only data segment).
Each string gets exactly the space it needs — no padding, no fixed-width waste. And the pointers themselves form a simple array you can index, loop over, or sort.
Accessing:
Note that the access syntax is identical to the 2D array version. names[2] gives you a string either way; names[2][0] gives you a character either way. This is why the two are so easy to confuse — they behave alike in the common cases and diverge in the important ones.
The critical limitation
If the pointers reference string literals, the text is read-only:
This is the literal-vs-array rule from the strings basics page, applied at array scale. You can reassign a pointer to point at different text:
...but you can't modify the characters themselves. If you need to edit in place, either use Method 1, or allocate writable copies with strdup (POSIX) or malloc + strcpy.
(Suggested image: the pointer-array memory diagram with the literal pool marked read-only (padlock) and arrows from each pointer, contrasted against the writable 2D grid)
The Comparison: Which Should You Use?
This is the decision table worth keeping:
The practical guidance:
- Reading input into strings → 2D array (you need writable memory)
- A constant list of options, days, months, keywords → array of pointers (compact, and you never modify it)
- A list where strings vary wildly in length → array of pointers (no wasted width)
- A list where you'll modify characters in place → 2D array
When in doubt for input, use the 2D array — you can't crash it by writing to a literal.
(Suggested image: a small decision-flow graphic — "Do you need to modify the text? → 2D array. Just read it? → pointer array.")
Reading Multiple Strings From the User
Because input needs writable memory, this is Method 1's home turf:
Sample Run:
Four details doing real work here:
fgets(names[i], MAX_LEN, stdin)— passesnames[i], which is the row (achar[30], which decays to achar *). Exactly the array-to-function behavior from the arrays cluster.names[i][strcspn(names[i], "\n")] = '\0';— a 2D indexed use of the newline-stripping idiom.- The
getchar()flush loop — clearing the newlinescanfleft behind, or the firstfgetswould immediately read an empty line. You met this in our scanf and getchar tutorials. strlen(names[i])— per-row length, because the grid's fixed width tells you nothing about the actual text length.
Note that spaces work fine here — "Priya Sharma" and "Mei Ling Chen" both came through intact, which scanf("%s") could never manage.
Sorting an Array of Strings
A classic exercise, and a good demonstration of how arrays of strings interact with strcmp and strcpy.
Sorting a 2D char array — you compare with strcmp and swap with strcpy (you can't swap arrays with =):
Output:
Sorting an array of pointers is much lighter — you only swap addresses, no string copying at all:
Same result, but the swap moves two pointers instead of copying up to 30 bytes three times per exchange. This is the pointer array's killer advantage: sorting, reordering, and shuffling cost almost nothing, because you're rearranging addresses rather than data.
That's also why library sorting functions work on pointers — and it's a big reason real C code frequently uses char *list[] for collections of text.
(Suggested image: both sort approaches side by side — one showing three strcpy operations per swap, the other showing a single pointer exchange)
A Complete Example: A Command Handler
Programming languages and shells are built on arrays of strings — a table of keywords, checked against input. Here's a small version:
Sample Run:
Look at the design choices, each following the guidance from this page:
const char *commands[]— a constant list of strings, never modified. Array of pointers, compact, andconst(from the array-parameters tutorial) documents that nothing touches it.findCommandtakes aconst char *— it reads the input and the table, modifies neither.strcmp(...) == 0for the match — the zero-means-equal rule from the string functions reference.switchon the returned index — the multi-way dispatch pattern from the control flow cluster, now driven by string data.
And crucially: a linear scan through the command table is exactly what array-of-strings is for. Add a sixth command and you edit one array — nothing else changes. This is how real command interpreters and keyword-driven programs are structured.
Common Mistakes
- Assigning a string into a 2D char array row with
=—names[0] = "Alice";is a compile error (arrays aren't assignable). Usestrcpy(names[0], "Alice");. - Writing to a literal-backed pointer array —
char *a[] = {"x"}; a[0][0] = 'y';crashes. Use a 2D array if you need to modify. - Column size too small —
char names[5][10]with a 12-character input overflows or truncates. Size generously, or use an array of pointers withmalloccopies. - Confusing row count with string length —
sizeof(names)/sizeof(names[0])gives rows, not text lengths. Usestrlenper row. - Using
==when comparing rows —names[0] == names[1]compares addresses. Usestrcmp. - Trying to swap rows with
=— you must copy characters (strcpy+ temp buffer) for 2D arrays, or swap pointers for pointer arrays. The pointer version is much cleaner. - Reading input directly into a pointer array —
char *names[5]; fgets(names[0], 30, stdin);reads into a null/invalid pointer. Input needs allocated memory: use a 2D array, ormalloceach row first. - Forgetting
fgets's newline on each row — every string then carries a trailing\n, breaking comparisons and output formatting. - Mixing the two forms in one declaration —
char *names[5][30]isn't what you think. Know exactly which data structure you're building.
(Suggested image: "9 Array-of-Strings Mistakes" checklist graphic — consistent with the series)
Final Thoughts
An array of strings in C comes in two shapes, and choosing between them is a genuine design decision rather than a style preference. The 2D char array gives you writable storage in a fixed grid — ideal for reading input. The array of pointers gives you compact, cheap-to-rearrange references to text you don't intend to modify — ideal for constant tables.
The dividing question is short: will you modify the characters? If yes, you need the grid. If no, the pointer array will be smaller and faster. And if you need both — a large collection you'll edit — that's the signal to move to dynamic allocation, where each string gets its own precisely-sized malloc'd buffer (a Pointers cluster topic coming later).
Get the two forms straight and you've covered the way nearly all C programs handle collections of text — from command tables to file listings to configuration options.
Runnable C Code Example & Practical Implementation
#include <stdio.h>
int main() {
// Array of string pointers (Ragged Array)
const char *languages[] = {
"C Programming",
"Python",
"JavaScript",
"Rust",
"Go"
};
size_t count = sizeof(languages) / sizeof(languages[0]);
printf("Programming Languages List:\
");
for (size_t i = 0; i < count; i++) {
printf(" %zu: %s\
", i + 1, languages[i]);
}
return 0;
}Key Takeaways, Best Practices & Memory Safety Rules
const char *list[] for static string tables to eliminate wasted memory padding.Frequently Asked Questions & Technical Interview Insights
Technical Interview & Viva Questions
Frequently asked C programming interview questionsQ: What is the memory advantage of `const char *arr[]` over `char arr[100][50]`?
Q: How do you access the 3rd character of the 2nd string in `char names[5][20]`?
Related Tools, Tutorials & Authoritative References
Recommended Interactive Tools
- Online C Compiler & Runner — Interactive online GCC sandbox to execute C code in real time.
- Online C Code Editor & IDE — Multi-file C programming environment with code formatting.
- C++ Programming Tutorial — Transition from procedural C to Object-Oriented C++ with STL.
- JavaScript Programming Tutorial — Master modern JavaScript fundamentals, DOM APIs, and async patterns.
Authoritative Standards & Citations
- ISO/IEC 9899 (C Language Standard) — Official international C specification by ISO/IEC JTC 1/SC 22/WG 14.
- GNU GCC Documentation — Official reference manual for the GNU Compiler Collection and C libraries.
- The C Programming Language (K&R) — Definitive classic work by Brian Kernighan & Dennis Ritchie at Bell Labs.
- C Reference Documentation (cppreference.com) — Verified reference covering C89 through C23 language features.