Skip to content
Laviyx Learn

Try

C course menu

Strings in C: char Arrays, the Null Terminator and Reading Text Safely

Understand strings in C: strings as char arrays ending in a null terminator, string literals, char array versus char pointer, printing and reading strings, why gets is gone and scanf %s is risky, reading lines safely with fgets, and processing characters with ctype.h.

Beginner7 min readUpdated
On this page

C has no separate string type. A string is an array of char that ends with the null character '\0' (a byte with value 0). Every string function relies on that terminator to know where the text stops.

The null terminator#

C
#include <stdio.h>

int main(void) {
    char word[] = "Hi!";
    printf("%zu bytes\n", sizeof word);
    for (int i = 0; i < (int)sizeof word; i++) {
        printf("[%d]=%d ", i, word[i]);
    }
    printf("\n");
    return 0;
}
Output
4 bytes
[0]=72 [1]=105 [2]=33 [3]=0 

"Hi!" has 3 characters but takes 4 bytes: 'H', 'i', '!' and '\0'. Always leave room for the terminator.

Declaring strings#

C
char a[] = "chennai";          /* array of 8 chars, a copy you can change */
char b[20] = "pune";           /* room for up to 19 characters */
const char *c = "mumbai";      /* pointer to a read-only string literal */

a[0] = 'C';
b[0] = 'P';
printf("%s %s %s\n", a, b, c);
Output
Chennai Pune mumbai

A string literal like "mumbai" is stored in read-only memory. Modifying it through a pointer (c[0] = 'M') is undefined behavior and usually crashes, so point to literals with const char *.

Printing strings#

%s prints characters until it reaches '\0'. A width pads the output, and a precision limits how many characters are printed:

C
const char *city = "Hyderabad";
printf("[%s]\n", city);
printf("[%12s]\n", city);
printf("[%-12s]\n", city);
printf("[%.3s]\n", city);
puts("puts adds a newline");
Output
[Hyderabad]
[   Hyderabad]
[Hyderabad   ]
[Hyd]
puts adds a newline

Reading strings safely#

scanf("%s", buf) stops at the first space and does not know how big buf is, so long input overflows the buffer. If you use it, always give a width one less than the buffer size: scanf("%19s", buf) for char buf[20].

To read a whole line, use fgets, which never writes more than the size you give:

C
#include <stdio.h>
#include <string.h>

int main(void) {
    char name[32];
    printf("Name: ");
    if (fgets(name, sizeof name, stdin) == NULL) return 1;
    name[strcspn(name, "\n")] = '\0';      /* remove the newline fgets keeps */
    printf("Hello, %s! (%zu characters)\n", name, strlen(name));
    return 0;
}
Output
Name: Kiran Rao
Hello, Kiran Rao! (9 characters)
  • fgets keeps the '\n' if it fits, so remove it with the strcspn line.
  • It returns NULL at end of input or on error.

Processing characters#

Loop until the terminator, and use <ctype.h> to classify and convert characters:

C
#include <stdio.h>
#include <ctype.h>

int main(void) {
    char text[] = "Room 42b, Floor 3";
    int letters = 0, digits = 0, spaces = 0;

    for (int i = 0; text[i] != '\0'; i++) {
        unsigned char ch = (unsigned char)text[i];
        if (isalpha(ch)) letters++;
        else if (isdigit(ch)) digits++;
        else if (isspace(ch)) spaces++;
        text[i] = (char)toupper(ch);
    }
    printf("%s\n", text);
    printf("letters %d, digits %d, spaces %d\n", letters, digits, spaces);
    return 0;
}
Output
ROOM 42B, FLOOR 3
letters 10, digits 3, spaces 3

The <ctype.h> functions expect values that fit in unsigned char (or EOF), so cast char values before passing them.

Practice#

Practice exercise

Without using <string.h>, write int my_strlen(const char *s) and int is_palindrome(const char *s) (same forwards and backwards). Test with "level" and "laviyx".

Show solution
C
#include <stdio.h>

int my_strlen(const char *s) {
    int n = 0;
    while (s[n] != '\0') n++;
    return n;
}

int is_palindrome(const char *s) {
    int i = 0, j = my_strlen(s) - 1;
    while (i < j) {
        if (s[i] != s[j]) return 0;
        i++;
        j--;
    }
    return 1;
}

int main(void) {
    printf("%d %d\n", my_strlen("level"), is_palindrome("level"));
    printf("%d %d\n", my_strlen("laviyx"), is_palindrome("laviyx"));
    return 0;
}
Output
5 1
6 0

Key takeaway#

Finished this lesson?