There is no separate "string" data type in C. The string is a char array** terminated by '\0' (the null character).
Length/Copy/Compare/Concatenate is handled using the standard functions of <string.h>.
Learning Objectives
- Understand the null-terminated rules of C strings.
- Use
strlen,strcpy,strcat, andstrcmpof<string.h>. - Receive one line safely with
fgets. - Be aware of the risk of buffer overflow.
Why isn't "string" a separate type?
C was designed as a small and fast language, and strings are also expressed as simple char arrays.
The null character ('\0') was introduced because a way to signal the end of an array was needed.
char s[] = "Hi";
is stored in memory as follows:
s[0] s[1] s[2]
┌────┬────┬─────┐
│ H │ i │ \0 │ ← '\0' indicates "This is the end!"
└────┴────┴─────┘
Why strlen("Hi") returns 2: Count the number of characters until '\0' is encountered.
Key concepts
1) String expression
char s1[] = "Hello"; // 6 byte ('H','e','l','l','o','\0')
char s2[10] = "Hi"; //The rest is filled with '\0'
char s3[] = {'H','i','\0'}; //Equivalent expression
2) Core functions of <string.h>
| function | Meaning | Caution |
|---|---|---|
strlen(s) |
Length (excluding null) | s must not be NULL |
strcpy(dst, src) |
Copy src to dst | dst buffer must be sufficient |
strcat(dst, src) |
Append src to the end of dst | Requires space equal to combined length + 1 |
strcmp(a, b) |
Compare alphabetically | If they are equal, it is 0, if a<b it is negative, if a>b it is positive |
3) Enter one line as fgets
char buf[128];
fgets(buf, sizeof(buf), stdin); //Includes line breaks
buf[strcspn(buf, "\n")] = '\0'; //Remove line breaks
scanf("%s", ...) breaks when it encounters a space, and does not check the input length, so there is a risk of buffer overflow.
4) Character unit processing (<ctype.h>)
| function | Description |
|---|---|
isalpha(c) |
alphabet? |
isdigit(c) |
number? |
tolower(c) / toupper(c) |
Convert Small/capital-letters |
See as example
Example 1 — ex01_basic.c: View length and character by character
Execution result
String: Hello, C!
Length: 9
s[0] = H (code 72)
s[1] = e (code 101)
s[2] = l (code 108)
s[3] = l (code 108)
s[4] = o (code 111)
s[5] = , (code 44)
s[6] = (code 32)
s[7] = C (code 67)
s[8] = ! (Code 33)
Bottom line: the string is ultimately an array of char integers, and the '\0' at the end is not included in the length.
Example 2 — ex02_strops.c: Copy/Concatenate/Compare
char a[64] = "Hello";
char b[] = ", World!";
char c[64];
strcpy(c, a);
strcat(a, b);
Execution result
a = Hello, World!
c = Hello
strcmp("abc", "abd") = -1
strcmp("abc", "abc") = 0
Key point: strcat concatenates dst starting from the null position, so dst must be a valid string.
Example 3 — ex03_fgets.c: Safe Input
Input: hello c world
Enter a sentence: Input value: "hello c world"
Length: 13
Bottom line: fgets receives a buffer size so it doesn't overflow.
Example 4 — ex04_count.c : Vowel/Consonant count
Input: Hello World
Enter English sentences: Vowels: 3, Consonants: 7
Key point: If you compare after unifying the case with tolower, the branching will be reduced by half.
A different perspective — why string operations seem slow
Every time you call strlen, the compiler looks for '\0' from the beginning.
for (int i = 0; i < strlen(s); i++) //Length recalculated at each iteration!
When performance is important, find the length only once.
size_t n = strlen(s);
for (size_t i = 0; i < n; i++) ...
The fact that C strings are endless arrays affects both efficiency and safety.
Common Mistakes
- Buffer Insufficient:
char dst[3]; strcpy(dst, "Hello");→ Adjacent memory corruption. - Missing null termination: If you just do
char s[5]; s[0]='H'; s[1]='i';, you don't know where it ends → Garbage output. - String comparison with
==: Compares two pointers, so even if the contents are the same, it is false. Must bestrcmp. - Line break remaining after
fgets:\nremains at the end, so the output goes down one more line → is removed asstrcspn. - Constant string modification:
char *p = "hi"; p[0] = 'H';has undefined behavior. To fixchar p[] = "hi";.
Cleanup
- The C string is a
chararray ending with'\0'. - Length/Copy/Compare/Concatenate
<string.h>function. fgetsis safer thanscanf("%s").- For
strcat/strcpy, the caller is responsible for whether the dst buffer is sufficient. - String comparison is
strcmp, absolute==.
Try it yourself
cd src
gcc -std=c11 -Wall -o ex01 ex01_basic.c && ./ex01
gcc -std=c11 -Wall -o ex02 ex02_strops.c && ./ex02
gcc -std=c11 -Wall -o ex03 ex03_fgets.c && echo "hello c world" | ./ex03
gcc -std=c11 -Wall -o ex04 ex04_count.c && echo "Hello World" | ./ex04
Application:
- Add one line from
ex01tos[2] = '\0';and print it. Observe how the string breaks. - If you copy the
c[]buffer inex02with a buffer that is too small (e.g.char c[3]), what kind of warning/error will appear?