← Back to C series
⚙️
Intermediate
char[] · <string.h> · fgets

Chapter 4 — Strings

In C a string is **a char array ending with `\0`**. The `\0` is what makes a "string" different from a "char array".

charstring.hfgets
Duration
1-2 hours
Level
📊 Beginner+
Prerequisite
🎯 Intermediate 3
Outcome
Use string.h safely

What you'll learn

  • 1Declare and initialize strings.
  • 2Use core `<string.h>` functions: `strlen`, `strcpy`, `strcmp`, `strcat`.
  • 3Read a line safely with `fgets`.
  • 4Avoid buffer overflows.

Core Concepts

1) Storage layout

c
char s[] = "abc";   // {'a', 'b', 'c', '\0'}  — length 4

`strlen("abc")` is 3 (excludes the `\0`); `sizeof(s)` is 4 (includes it).

2) Key `<string.h>` functions

FunctionWhat
`strlen(s)`length, excluding `\0`
`strcpy(dst, src)`copy — **dst must be big enough**
`strncpy(dst, src, n)`bounded copy
`strcmp(a, b)`0 = equal, <0 = a<b, >0 = a>b
`strcat(dst, src)`concat — same warning as `strcpy`
`strchr(s, c)`find char; returns pointer or NULL

3) Reading a line safely

c
char buf[100];
fgets(buf, sizeof(buf), stdin);  // includes trailing '\n'

Strip the `\n` if you don't want it:

c
buf[strcspn(buf, "\n")] = '\0';

4) Why `gets` is gone

The old `gets()` had no length check and was removed from C11. **Never use it.**

5) Compare strings — don't use `==`

c
char a[] = "hi", b[] = "hi";
a == b;          // ❌ compares pointers (different)
strcmp(a, b);    // ✅ returns 0

Examples

Example 1 — `ex01_basic.c`: strlen vs sizeof

c
char s[] = "Hello";
printf("strlen = %zu\n", strlen(s));
printf("sizeof = %zu\n", sizeof(s));

**Output**

text
strlen = 5
sizeof = 6

Key: `sizeof` includes the `\0`, `strlen` doesn't.

Example 2 — `ex02_strops.c`: copy, compare, concat

c
char a[20] = "Hello";
char b[] = "World";
strcat(a, ", ");
strcat(a, b);
printf("%s\n", a);
printf("cmp = %d\n", strcmp("abc", "abd"));

**Output**

text
Hello, World
cmp = -1

Key: `a` was declared with room (`[20]`) so `strcat` doesn't overflow.

Example 3 — `ex03_fgets.c`: read a name

c
char name[32];
printf("Name? ");
fgets(name, sizeof(name), stdin);
name[strcspn(name, "\n")] = '\0';
printf("Hi, %s!\n", name);

**Output**

text
Name? Alice
Hi, Alice!

Key: `fgets` is safe; always strip the trailing newline.

Example 4 — `ex04_count.c`: count vowels

c
const char *s = "Programming";
int n = 0;
for (int i = 0; s[i]; i++) {
    char c = s[i];
    if (c=='a'||c=='e'||c=='i'||c=='o'||c=='u'||
        c=='A'||c=='E'||c=='I'||c=='O'||c=='U') n++;
}
printf("vowels = %d\n", n);

**Output**

text
vowels = 3

Key: loop condition `s[i]` stops naturally at `\0`.

Common mistakes

  1. **`strcpy` into a too-small buffer** — silent buffer overflow.
  2. **Comparing strings with `==`** — compares pointers, not content.
  3. **Forgetting the `\0`** — manual char arrays can be unterminated; `printf("%s")` then runs off the end.
  4. **`fgets` newline left behind** — strip with `strcspn`.

Recap

  • A C string is bytes + `\0`. `\0` is everything.
  • Always size the destination; prefer `strncpy`/`snprintf`.
  • Compare with `strcmp`, not `==`.

Try it

bash
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 && ./ex03 <<< Alice
gcc -std=c11 -Wall -o ex04 ex04_count.c && ./ex04

💻 Examples

Compilable, runnable examples — see the output yourself.

ex01_basic.cstrlen vs sizeof
CODE
#include <stdio.h>
#include <string.h>

int main(void) {
    char s[] = "Hello, C!";

    printf("string: %s\n", s);
    printf(":   %zu\n", strlen(s));

    /*    */
    for (size_t i = 0; s[i] != '\0'; i++) {
        printf("s[%zu] = %c ( %d)\n", i, s[i], s[i]);
    }
    return 0;
}
▶ Output
strlen = 5
sizeof = 6
ex02_strops.ccopy, compare, concat
CODE
#include <stdio.h>
#include <string.h>

int main(void) {
    char a[64] = "Hello";
    char b[]   = ", World!";
    char c[64];

    strcpy(c, a);
    strcat(a, b);

    printf("a = %s\n", a);
    printf("c = %s\n", c);
    printf("strcmp(\"abc\", \"abd\") = %d\n", strcmp("abc", "abd"));
    printf("strcmp(\"abc\", \"abc\") = %d\n", strcmp("abc", "abc"));
    return 0;
}
▶ Output
Hello, World
cmp = -1
ex03_fgets.cread a name
CODE
#include <stdio.h>
#include <string.h>

int main(void) {
    char line[128];

    printf("Sentence: ");
    if (fgets(line, sizeof(line), stdin) == NULL) return 1;

    line[strcspn(line, "\n")] = '\0';   /*  \n  */

    printf("input: \"%s\"\n", line);
    printf(":   %zu\n", strlen(line));
    return 0;
}
▶ Output
Name? Alice
Hi, Alice!
ex04_count.ccount vowels
CODE
#include <stdio.h>
#include <ctype.h>
#include <string.h>

int main(void) {
    char buf[256];
    printf(" Sentence: ");
    if (fgets(buf, sizeof(buf), stdin) == NULL) return 1;
    buf[strcspn(buf, "\n")] = '\0';

    int vowels = 0, consonants = 0;
    for (size_t i = 0; buf[i] != '\0'; i++) {
        char ch = (char)tolower((unsigned char)buf[i]);
        if (ch >= 'a' && ch <= 'z') {
            if (ch == 'a' || ch == 'e' || ch == 'i' ||
                ch == 'o' || ch == 'u')
                vowels++;
            else
                consonants++;
        }
    }

    printf(": %d, : %d\n", vowels, consonants);
    return 0;
}
▶ Output
vowels = 3

📝 Exercises

Try them yourself first, then open the solution to compare.

Exercise 1

Problem 1 (hw01.c)

Goal: Read a word and print it reversed (in place).

Requirements
  • Filename: hw01.c
Toggle solution
SOLUTION
#include <stdio.h>
#include <ctype.h>
#include <string.h>

int main(void) {
    char buf[256];
    printf("Sentence: ");
    if (fgets(buf, sizeof(buf), stdin) == NULL) return 1;
    buf[strcspn(buf, "\n")] = '\0';

    for (size_t i = 0; buf[i] != '\0'; i++)
        buf[i] = (char)toupper((unsigned char)buf[i]);

    printf("%s\n", buf);
    return 0;
}
Exercise 2

Problem 2 (hw02.c)

Goal: Read a sentence and count words (split on spaces).

Requirements
  • Filename: hw02.c
Toggle solution
SOLUTION
#include <stdio.h>
#include <ctype.h>
#include <string.h>

int main(void) {
    char buf[256];
    printf("Sentence: ");
    if (fgets(buf, sizeof(buf), stdin) == NULL) return 1;
    buf[strcspn(buf, "\n")] = '\0';

    int len = (int)strlen(buf);
    int palindrome = 1;
    for (int i = 0, j = len - 1; i < j; i++, j--) {
        char a = (char)tolower((unsigned char)buf[i]);
        char b = (char)tolower((unsigned char)buf[j]);
        if (a != b) { palindrome = 0; break; }
    }

    printf("%s\n", palindrome ? "It is a palindrome." : "Not a palindrome.");
    return 0;
}
Exercise 3

Problem 3 (hw03.c)

Goal: Read a string and a character; print how many times the character appears.

Requirements
  • Filename: hw03.c
Toggle solution
SOLUTION
#include <stdio.h>
#include <string.h>

int main(void) {
    char buf[256];
    char target;

    printf("Sentence: ");
    if (fgets(buf, sizeof(buf), stdin) == NULL) return 1;
    buf[strcspn(buf, "\n")] = '\0';

    printf("Char to find: ");
    scanf(" %c", &target);

    int count = 0;
    for (size_t i = 0; buf[i] != '\0'; i++)
        if (buf[i] == target) count++;

    printf("'%c' appears %d times.\n", target, count);
    return 0;
}
Example code / lecture materials

All lecture materials and example code are openly available on GitHub.

View on GitHub ↗