Data Structures
Strings
Master C Strings — what/why/applications, initialization, string.h functions, reading, writing, and string of strings — using LEARNCODEGURU’s 6-level learning model.
Level 1 Basics Content
C Strings Overview
In C, a string is a sequence of characters stored in a char array
and ended by a special character '\0' (null terminator). This level covers what
strings are, why they matter, applications, initialization, key string.h functions,
reading, writing, and a string of strings (array of strings).
Think of one string as a row of character boxes ending with '\0', and a string of
strings as several such rows (a 2D char table or a list of names).
What is a string?
A C string is not a separate data type. It is a char array whose
last meaningful byte is '\0'. Everything after the visible text is either unused
capacity or must still leave room for that terminator.
char name[6] = "Ravi";
/* Memory idea: 'R' 'a' 'v' 'i' '\0' (and maybe unused slots) */
- Character — one letter/digit/symbol in the array
- Null terminator
'\0'— marks the end of the string - Length — number of characters before
'\0'(strlen) - Capacity — size of the array (must be ≥ length + 1)
"Hi" needs 3 bytes: 'H', 'i', '\0'.
Why strings?
- Store text — names, messages, file paths, commands
- One name for many characters — easier than separate
charvariables - Library support —
strlen,strcpy,strcmp, … - I/O with %s — read/write whole words or lines as text
- Foundation for larger programs — menus, parsers, and string-of-strings tables
Applications of strings
- User input — login names, search queries, addresses
- Messages & UI text — titles, errors, prompts
- File / path names — open files by string path
- Token / word processing — count words, reverse, search
- Tables of text — list of student names (string of strings)
Initialization of strings
With a string literal (preferred for fixed text):
char s1[] = "Hello"; /* size becomes 6 (incl. '\0') */
char s2[20] = "Hello"; /* length 5; rest of buffer unused/zeroed with this form */
char s3[6] = {'H', 'i', '\0'}; /* explicit chars */
| Form | Meaning |
|---|---|
char s[] = "Hi"; | Mutable array; size inferred (3) |
char s[10] = "Hi"; | Fixed capacity 10; text + '\0' |
char *p = "Hi"; | Pointer to literal — do not modify the text |
char s[10]; (no init) | Garbage until you write a terminated string |
char s[5] = "Hello"; is too small
for "Hello" + '\0'.
String built-in functions (string.h)
Include #include <string.h>. Common starter functions:
| Function | Role | Example idea |
|---|---|---|
strlen(s) | Length before '\0' | strlen("Hi") → 2 |
strcpy(dest, src) | Copy string into dest | Need enough room in dest |
strcat(dest, src) | Append src onto dest | dest must have free space |
strcmp(a, b) | Compare lexicographically | 0 means equal |
strncpy / strncat | Length-limited variants | Still watch for missing '\0' |
#include <string.h>
char a[40] = "Learn";
char b[40];
strcpy(b, a); /* b becomes "Learn" */
strcat(b, "Code"); /* b becomes "LearnCode" */
/* strlen(b) == 9 ; strcmp(a, b) != 0 */
Reading strings
Word with scanf (stops at space):
char word[20];
scanf("%19s", word); /* width limits overflow; no & on array name */
Line with fgets (keeps spaces; may keep newline):
char line[100];
fgets(line, sizeof line, stdin);
gets() — it is unsafe. Prefer width-limited scanf or fgets.
Writing strings
Print whole string:
printf("%s\n", word);
puts(word); /* prints string + newline */
Print character by character:
int i;
for (i = 0; word[i] != '\0'; i++)
putchar(word[i]);
putchar('\n');
s[0] = 'A';,
strcpy(s, "OK");, or reading with scanf/fgets.
String of strings
A string of strings is a collection of strings — often a 2D char array
where each row is one string (null-terminated within that row).
char names[3][20] = {
"Asha",
"Ravi",
"Neha"
};
/* names[0] → "Asha" , names[1] → "Ravi" , names[2] → "Neha" */
printf("%s\n", names[1]); /* prints Ravi */
names[i]— the i-th stringnames[i][j]— character j inside string i- Each row needs space for text +
'\0'(here up to 19 chars + null)
Sample program — init, read word, string.h, string of strings
/* Strings basics sample */
#include <stdio.h>
#include <string.h>
int main(void) {
char greet[] = "Hello";
char word[40];
char copy[40];
char names[2][20] = { "Asha", "Ravi" };
int i;
printf("%s, world!\n", greet);
printf("Enter a word: ");
scanf("%39s", word);
printf("You typed: %s (len=%zu)\n", word, strlen(word));
strcpy(copy, word);
strcat(copy, "!");
printf("Copy+bang: %s\n", copy);
printf("Names:\n");
for (i = 0; i < 2; i++)
puts(names[i]);
return 0;
}
Level 2 Advanced Content
Going deeper into strings
Level 1 covered what/why/applications, init, basic string.h, read/write, and
string-of-strings. Level 2 digs into the null terminator, safe I/O, function details,
mutable vs literal storage, and two layouts for arrays of strings.
What is a string? — terminator & memory
Library functions stop at the first '\0'. If you overwrite the terminator or never
write one, %s / strlen walk into neighboring memory (undefined behavior).
char s[5];
s[0] = 'O'; s[1] = 'K'; s[2] = '\0'; /* valid short string */
sizeof(s) is the array capacity in bytes. strlen(s) is the text length.
They are equal only in special cases (e.g. full buffer packed with chars and no spare room — still
need a terminator inside capacity).
Why strings? — vs char-by-char & vs other languages
- C gives you raw control and speed, but you manage buffers yourself
- No automatic resizing — overflowing a buffer is your bug to prevent
- Same model underpins argv, file APIs, and network text protocols
Applications — parsing & tables
- Split / scan words inside a line (manual loops or library helpers)
- Menus: array of option strings; print and match user choice with
strcmp - CSV-like rows: each line is a string; columns may be further split
Initialization — literals, empty, and partial
char empty[] = ""; /* only '\0' */
char buf[8] = {0}; /* all zeros → empty string */
char msg[8] = {'H', 'i'}; /* rest zeroed → "Hi" */
char *p = "text"; points at a literal (often read-only).
char a[] = "text"; copies into a mutable array.
Built-in functions — deeper rules
| Call | Must ensure | Trap |
|---|---|---|
strcpy(d, s) | sizeof(d) ≥ strlen(s)+1 | No size check inside strcpy |
strcat(d, s) | Space for both strings + null | Easy to overflow after several appends |
strcmp(a, b) | Both properly terminated | == 0 means equal; do not treat as bool alone |
strncpy(d, s, n) | You may need to force d[n-1]='\0' | May leave dest without terminator |
if (strcmp(a, b) == 0)
puts("equal");
else if (strcmp(a, b) < 0)
puts("a before b");
else
puts("a after b");
Reading strings — scanf vs fgets
scanf("%s")— one word; skips leading whitespace; use field widthfgets— up to size−1 chars or until newline; stores'\0'; may keep'\n'- Mixing
scanfandfgetscan leave a leftover newline — clear or redesign input flow
/* Strip trailing newline after fgets */
size_t n = strlen(line);
if (n > 0 && line[n - 1] == '\n')
line[n - 1] = '\0';
Writing strings — format & manual loops
printf("%s", s)requires a valid terminator- To write into a string: assign chars, or
strcpy/sprintf(watch buffer size) - Building text char-by-char: write chars, then set
s[i] = '\0'when done
String of strings — 2D array vs array of pointers
Fixed-width rows (2D char array):
char table[3][16];
scanf("%15s", table[0]); /* read into first row */
Array of pointers (often to literals):
char *days[] = {
"Mon", "Tue", "Wed"
};
puts(days[1]); /* Tue — do not modify the literal text */
| Layout | Best for | Watch out |
|---|---|---|
char a[R][C] | Editable names you read from user | Wasted space if strings are short |
char *a[] | Fixed list of literals / messages | Pointers, not deep copies; literals may be read-only |
Common mistakes
| Mistake | Why it hurts | Fix |
|---|---|---|
No room for '\0' | Overflow / non-terminated string | Size ≥ length + 1 |
if (a == b) for text | Compares addresses | strcmp(a, b) == 0 |
scanf("%s", &s) | Wrong type for %s | scanf("%Ns", s) |
Modify string literal via char * | Undefined behavior | Use char buf[] = "..." |
Unbounded strcpy | Buffer overflow | Check sizes; prefer safer patterns |
Level 3 C Tricky Interview Points
Advanced tricky interview points on null terminators, strlen vs sizeof, safe I/O, string.h, literals, and string of strings.
Tricky Interview Point-1:
A C string is a char array ending with '\0' — not a separate type
There is no built-in string type in C. Text is stored as char s[...] with a null terminator. Forgetting '\0' means printf("%s") and strlen keep reading past your data — undefined behavior.
Tricky Interview Point-2:
strlen counts characters — sizeof includes the terminator (and capacity)
char s[] = "Hi"; → strlen(s) is 2, sizeof(s) is 3. For char buf[20] = "Hi"; strlen is still 2, but sizeof(buf) is 20 (the whole array). Confusing length and capacity is a classic trap.
Tricky Interview Point-3:
char s[5] = "Hello"; does not fit — needs room for '\0'
"Hello" needs 6 bytes (5 letters + null). char s[5] = "Hello"; is wrong / truncated depending on context. Always size ≥ length + 1.
Tricky Interview Point-4:
scanf("%s", s) stops at whitespace and needs space for '\0'
scanf with %s reads one word, not a full line. It writes a null terminator. Without a width (e.g. %19s for char s[20]), a long input overflows the buffer — prefer fgets for lines.
Tricky Interview Point-5:
gets() is unsafe and removed — use fgets()
gets() cannot limit input size and is obsolete. Use fgets(buf, sizeof buf, stdin). Remember fgets may keep the newline; strip it if you need a clean string.
Tricky Interview Point-6:
strcpy / strcat need enough destination space — they do not grow the array
Destination must already be large enough for the result including '\0'. Overflowing dest is undefined behavior. Prefer strncpy carefully (may omit '\0') or size-checked copies.
Tricky Interview Point-7:
strcmp returns 0 when strings are equal — not true/false like ==
if (strcmp(a, b) == 0) means equal. Positive / negative values mean lexicographic order. Comparing with == compares pointers (addresses), not text contents.
Tricky Interview Point-8:
String literals are often in read-only memory — do not modify them
char *p = "Hi"; then p[0] = 'h'; is undefined behavior. Use char s[] = "Hi"; if you need a mutable copy on the stack/array.
Tricky Interview Point-9:
Array of strings: char names[n][cols] vs char *names[]
char names[3][20] is a 2D char array (fixed row width). char *names[] = {"A","B"} is an array of pointers to string literals. Different memory layouts — know which you declared.
Tricky Interview Point-10:
Passing a string to a function decays to char *
void f(char s[]) or void f(char *s) receive a pointer. sizeof(s) inside the function is pointer size, not string length — use strlen or pass capacity separately.
Tricky Interview Point-11:
Empty string is "" — one byte: just '\0'
strlen("") is 0. char e[1] = ""; or char e[] = ""; both store only the terminator. Useful for “cleared” or default text.
Tricky Interview Point-12:
Putting %s with &s for a char array is wrong
For char s[20], use scanf("%19s", s) or printf("%s", s) — the array name already decays to &s[0]. Using &s with %s is a type mismatch (pointer to array vs pointer to char).
'\0', buffer capacity, and whether you mean
length (strlen) or storage size (sizeof).
Level 4 Simple Programs
Short programs for init/print, string.h ops, line input, and string of strings.
Program 1 — Initialize, length, character walk
/* Print string with %s and char-by-char */
#include <stdio.h>
#include <string.h>
int main(void) {
char s[] = "CodeGuru";
int i;
printf("String: %s\n", s);
printf("Length: %zu\n", strlen(s));
printf("Chars: ");
for (i = 0; s[i] != '\0'; i++)
putchar(s[i]);
putchar('\n');
return 0;
}
Program 2 — strcpy, strcat, strcmp
/* Copy, concat, compare */
#include <stdio.h>
#include <string.h>
int main(void) {
char a[40];
char b[40] = "Learn";
strcpy(a, b);
strcat(a, "Tech");
printf("a = %s\n", a);
if (strcmp(a, "LearnTech") == 0)
puts("Match!");
return 0;
}
Program 3 — fgets line + strip newline
/* Read a full line safely */
#include <stdio.h>
#include <string.h>
int main(void) {
char line[100];
size_t n;
printf("Enter a line: ");
if (fgets(line, sizeof line, stdin) == NULL)
return 1;
n = strlen(line);
if (n > 0 && line[n - 1] == '\n')
line[n - 1] = '\0';
printf("Got: [%s] len=%zu\n", line, strlen(line));
return 0;
}
Program 4 — String of strings (2D char array)
/* Read n names into char names[n][cols] and print */
#include <stdio.h>
int main(void) {
char names[50][40];
int n, i;
printf("How many names? ");
scanf("%d", &n);
printf("Enter %d names (one word each):\n", n);
for (i = 0; i < n; i++)
scanf("%39s", names[i]);
printf("Names:\n");
for (i = 0; i < n; i++)
printf("%d. %s\n", i + 1, names[i]);
return 0;
}
Level 5 Problem Solving Tricks
How to master strings while solving problems
Most string bugs come from missing '\0', tiny buffers, using == instead of
strcmp, unsafe input, and confusing 2D string tables with pointer arrays.
Use these habits every time you read, build, or compare text.
Always reserve +1 for the null terminator
When you know max text length L, declare char s[L + 1]. For n names of max length L, use char names[n][L + 1]. Never forget the terminator byte.
Prefer fgets for full lines — then strip '\n'
fgets(s, sizeof s, stdin) is safer than scanf("%s") for sentences. If s[strlen(s)-1] == '\n', set it to '\0' so later strcmp / strcat behave as expected.
Check destination capacity before strcpy / strcat
Ask: dest size ≥ strlen(src)+1 (copy) or strlen(dest)+strlen(src)+1 (concat)? If not, enlarge the buffer or refuse. Overflow bugs look like “random” crashes later.
Compare text with strcmp — not ==
Write if (strcmp(a, b) == 0). Using == compares addresses. For sorting / order, use the sign of strcmp’s return value.
Initialize before you print with %s
Uninitialized char buffers may lack '\0'. Always set with a literal, strcpy, scanf/fgets, or s[0] = '\0' before treating as a string.
For string-of-strings, pick 2D array vs pointer array clearly
Need editable fixed-width rows? char table[R][C]. Need list of literals / flexible lengths? char *list[]. Do not mix access patterns without knowing the layout.
Loop chars with for (i = 0; s[i] != '\0'; i++)
Manual walk is great for count vowels, reverse, toggle case. Stop at '\0'. Do not use sizeof(s)-1 as “length” unless you know the buffer is full and terminated.
Include <string.h> for strlen, strcpy, strcmp, strcat, …
Missing the header can still “compile” on some setups with warnings/implicit declarations — always #include <string.h> and <stdio.h> for I/O.
Quick success checklist
- Before run: capacity ≥ length+1? terminated? width on scanf? string.h included?
- Debug order: print with %s → check strlen → walk chars → verify strcmp result
- Many strings: choose char[R][C] vs char*[] → read into rows → print names[i]
Level 6 Practice Programs List
Programming questions only — focused on strings: init, built-in functions, reading, writing, and string of strings.
- 1. Write a C program that initializes a string and prints it with printf("%s") and character-by-character until '\0'.
- 2. Write a C program that reads a word with scanf("%s") and prints its length using strlen.
- 3. Write a C program that reads a full line with fgets, strips the newline, and prints the line.
- 4. Write a C program that copies one string into another with strcpy and concatenates a second string with strcat.
- 5. Write a C program that compares two strings with strcmp and prints whether they are equal, or which comes first.
- 6. Write a C program that counts vowels and consonants in a string (manual loop over characters).
- 7. Write a C program that reverses a string in place (swap characters from ends toward the middle).
- 8. Write a C program that stores n names in a 2D char array (string of strings), reads them, and prints them one per line.