What is C Strings and Null Terminator- Embedded C Programming Course

Need Help or More Information?

Questions about this free C programming course, embedded C training or career guidance? Get in touch.

Free C Programming Course · Chapter 9 · Lecture 1 of 7

C Strings and Null Terminator

How C stores text as a char array ended by the NUL byte, explained with a runnable example and a byte-level memory view.

9
Chapter: Strings
1/7
Lecture in this chapter
Free
Always, for every student

What You Will Learn

  • What a C string really is, and why C has no separate string type
  • How the NUL terminator '\0' marks the end of text
  • The difference between '\0', '0', NULL and ""
  • How to build a string by hand and by literal, and verify the bytes with a program
  • Why a plain char array is not automatically a string
  • The mistakes that cause garbage output and buffer over-reads in embedded C programming

Prerequisites

  • Arrays and indexing from the Arrays chapter
  • The char type and character constants
  • Basic printf usage

Welcome to Chapter 9 of the free C programming course from EmbeddedPathashala. Strings are where C is at its most honest: there is no string object, no length field and no safety net, only bytes in memory and one agreed marker for where the text stops. In this free C tutorial you will see exactly how C strings work, byte by byte, because every later topic (string literals, scanf, library functions, UART parsers) builds on this one idea. If you are following this free embedded C course to write firmware, treat this lecture as the foundation of everything text-related.

What Is a String in C?

Languages such as Python or Java give you a string type that remembers its own length. C does not. In C a string is just a contiguous array of char that ends with a zero byte. The zero byte is called the NUL terminator, and in source code it is written '\0'. Text such as a word, a sentence or a sensor name is stored in the array, and the terminator tells every function where the text stops.

Because the length is not stored anywhere, a function that wants to know how long a string is has to walk the bytes and count until it meets the zero. That single design choice explains most of the speed, the flexibility and the danger of C strings.

IdeaPlain char arrayC string
Is it an array of char?YesYes
Ends with a zero byte?Not necessarilyAlways
Safe for printf(“%s”) and strlen?NoYes
Length stored anywhere?NoNo, found by scanning for the zero
Can hold arbitrary binary data?YesNo, a zero byte inside ends the text early

The NUL Terminator in C Strings

The terminator is an escape sequence whose numeric value is 0. It is the very first entry in the ASCII table, a control character that prints nothing. People mix it up with three look-alikes, so get them straight now:

SpellingMeaningValueTypical use
'\0'NUL character0Ends every C string
'0'The digit zero as text48 (0x30)Printing the digit 0
NULLNull pointer constantpointer, not a charA pointer that points nowhere
""Empty string literalone byte: 0A string with zero characters

Do not confuse these

'\0' and NULL both evaluate to zero in many expressions, which tempts people to swap them. Keep '\0' for characters and NULL for pointers so the code says what you mean.

How the string UART sits in memory

Index01234
CharacterUART\0
Byte (hex)0x550x410x520x540x00
Roletexttexttexttextterminator

Four visible characters need five bytes. The extra byte is the price of knowing where the text ends, and it is the reason every string buffer must be at least one byte longer than the longest text it will hold.

Build a C String Two Ways

The program below builds the same string by listing every character yourself and by using a string literal. It then prints the size, the length and each stored byte, and also shows a char array that is deliberately not a string.

Save it as nul_demo.c.

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

int main(void)
{
    char a[] = {'U', 'A', 'R', 'T', '\0'};   /* hand-built string      */
    char b[] = "UART";                       /* same thing, shorter    */
    char raw[4] = {'U', 'A', 'R', 'T'};      /* char array, NOT string */

    printf("sizeof a = %zu, strlen a = %zu\n", sizeof a, strlen(a));
    printf("sizeof b = %zu, strlen b = %zu\n", sizeof b, strlen(b));
    printf("same bytes? %s\n", memcmp(a, b, sizeof a) == 0 ? "yes" : "no");

    puts("--- bytes of b ---");
    for (size_t i = 0; i < sizeof b; i++) {
        if (b[i] != '\0')
            printf("b[%zu] = 0x%02X  '%c'\n", i, (unsigned char)b[i], b[i]);
        else
            printf("b[%zu] = 0x%02X  NUL terminator\n", i, (unsigned char)b[i]);
    }

    printf("--- raw has %zu bytes and no NUL, so never use %%s on it ---\n",
           sizeof raw);
    return 0;
}

Build and run it with the C17 standard and warnings switched on:

gcc -std=c17 -Wall -Wextra -o nul_demo nul_demo.c
./nul_demo

Expected output:

sizeof a = 5, strlen a = 4
sizeof b = 5, strlen b = 4
same bytes? yes
--- bytes of b ---
b[0] = 0x55  'U'
b[1] = 0x41  'A'
b[2] = 0x52  'R'
b[3] = 0x54  'T'
b[4] = 0x00  NUL terminator
--- raw has 4 bytes and no NUL, so never use %s on it ---

What the output tells you

  • sizeof reports 5 because it counts all array elements, including the terminator.
  • strlen reports 4 because it stops at the first zero byte and does not count it.
  • memcmp confirms that the hand-built array and the literal-initialised array hold identical bytes.
  • The array raw holds exactly the four letters and nothing else. It is a valid array of char, but it is not a string.

Why the Terminator Matters

Standard functions never receive the array size. They receive only the address of the first byte and keep going until they see a zero. Look at how printf("%s", text) walks through the bytes:

How printf with percent s finds the end of the text

Start at first byte → Print it → Move to next byte → Is it 0x00? → No: repeat. Yes: stop

If the zero is missing, the loop does not stop at the end of your array. It carries on through whatever happens to sit next in memory, perhaps another variable, perhaps a stack frame, until some zero byte appears by chance. On a PC that usually prints junk. On a microcontroller it can print secrets, corrupt a display or trigger a hard fault.

A string needs room for the terminator

When you size an array by hand, count the characters and add one. The expression char name[5] = "UART" fits exactly. char name[4] would leave no room for the zero. In this C programming for embedded systems habit-forming moment, always write the size as longest text + 1, or let the compiler count by leaving the brackets empty.

Real-World Uses of C Strings in Embedded Systems

Use 1

Log and debug messages

Boot banners, error texts and status lines sent over a UART are all strings that end in a zero byte.

Use 2

Command parsers

A serial console receives text such as a command name, compares it with a table of known commands and acts on the match.

Use 3

Configuration names

Device names, file names and Wi-Fi network names are stored and compared as strings.

Use 4

Display text

Character LCDs and OLED drivers walk a string one character at a time until the terminator.

Common Mistakes With C Strings

MistakeWhat happensFix
Sizing the array to the text length onlyNo room for the terminator; later reads run past the endSize = characters + 1
Writing '0' when you mean '\0'The string never ends where you expectUse '\0' for the terminator
Calling strlen on a plain char arrayUndefined behaviour, a read past the arrayMake it a string first, or track the length yourself
Assuming sizeof equals strlenOff-by-one bugs in loops and copiesRemember sizeof includes the terminator
Storing binary data in a stringA data byte equal to zero cuts the text shortUse a length plus a raw buffer for binary data

Best Practices, Performance and Security

  • Let the compiler count: write char msg[] = "..." when the array should hold exactly this text.
  • Name the capacity in a macro or constant so every copy, read and comparison uses the same number.
  • Treat every string that arrives from outside your program (UART, network, file) as untrusted and bound all reads.
  • Performance: strlen is O(n) because it scans for the zero. Inside a loop condition it is re-run on every pass, so compute it once and store it.
  • Security: a missing terminator causes buffer over-reads, a classic source of information leaks. Bounded functions and explicit sizes are your defence.

Summary and Key Takeaways

  • C has no string type. A string is a char array that ends with '\0'.
  • The terminator takes one byte, so storage is always length plus one.
  • '\0', '0', NULL and "" are four different things.
  • A char array without the terminator is valid data but is not safe to pass to string functions.

This lecture gave you the mental model for how C strings work across the whole chapter: text in C is bytes plus a marker, and good C strings habits start with counting that extra byte. In the next lecture of this free C programming course you will meet string literals, the quoted text you write directly in source code, and learn that the compiler turns each one into exactly this kind of array and hands you a pointer to it.

Frequently Asked Questions

Is there a string data type in C?

No. C has no built-in string type. A string is a convention: an array of char whose last meaningful element is the byte value 0, written '\0'. Every standard string function relies on that convention.

What is the difference between ‘\0’, ‘0’ and NULL?

'\0' is the character with value 0, the string terminator. '0' is the digit character with ASCII value 48. NULL is a null pointer constant used with pointers, not with characters.

Does strlen count the NUL terminator?

No. strlen counts the characters before the first NUL. sizeof on an array holding the string does include the terminator, so for char b[] = "UART" you get strlen 4 and sizeof 5.

What happens if I forget the terminator?

Functions such as printf("%s") and strlen keep reading bytes past the end of your array until they happen to meet a zero byte. You get garbage output, a crash, or silently leaked memory contents.

Does the compiler add the NUL automatically?

Yes, when you initialise an array from a string literal such as char b[] = "UART". It does not add one when you list characters yourself unless you include '\0', and it cannot add one if you fix the array size too small.

Why does embedded C programming care so much about string length?

Microcontrollers have kilobytes of RAM. Every string costs its length plus one byte, and a missing terminator in a UART or log buffer can corrupt neighbouring variables. Knowing the exact byte layout is part of writing safe firmware.

Topics Covered in This Lecture

C stringsNUL terminatorchar arraystring in Cembedded C programmingfree C tutorialsizeof vs strlen

Keep Going With the Free C Programming Course

EmbeddedPathashala teaches C from the first printf to embedded-ready pointers and strings, completely free. Next: how string literals are stored and why they behave like pointers.

Need Help or More Information?

Questions about this free C programming course, embedded C training or career guidance? Get in touch.

1 Comment

Leave a Reply

Your email address will not be published. Required fields are marked *