What is C String Literals Explained- Free 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 2 of 7

C String Literals Explained

Learn how string literals in C are stored, why a literal acts like a pointer, and why equality on strings is a trap.

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

What You Will Learn

  • What a string literal (string constant) is and how the compiler stores it
  • Why a literal behaves like a pointer to its first character
  • How to read a literal with *, [] and pointer arithmetic
  • Why comparing two literals with == is a bug, and what to use instead
  • Where literals live in an embedded system and why that matters for flash and RAM
  • How to prove all of this with a short program

Prerequisites

  • Lecture 1 of this chapter: C strings and the NUL terminator
  • Pointer basics and the equivalence of p[i] and *(p + i)

This lecture of the free C programming course explains string literals in C: the quoted text you write directly in source code. They look simple, yet they hide several rules that trip up beginners and even working firmware engineers. By the end of this free C tutorial you will know what the compiler really does with "GPIO" and why that matters in embedded C programming.

What Is a String Literal in C?

A string literal (also called a string constant) is a run of characters enclosed in double quotes. Everything between the quotes is the text; the quotes themselves are punctuation for the compiler and are never stored. These are all valid literals:

LiteralCharacters storedBytes in memory
"V"V2 (V and the terminator)
"Embedded C"E m b e d d e d, space, C11
"2345"four digit characters, not a number5
""nothing1 (only the terminator)
"id=%d\n"a printf control string is also just text7

Whenever a literal appears in your program, the compiler places the characters, followed by a zero byte, somewhere in the program image as an array of char. You never name that array. Instead, the literal in your expression turns into the address of its first character.

A literal and the pointer that refers to it

WhereObjectHolds
Flash (read-only data)the literal’s arrayE m b e d d e d space C and a zero byte
RAMpointer variable msgthe address of the letter E

So after const char *msg = "Embedded C"; the variable msg contains an address, and the text it points to sits elsewhere. Passing "Hello" to printf works the same way: what you really pass is a pointer to the letter H.

String Literals in C Behave Like Pointers

An array name normally converts to a pointer to its first element, and a string literal is an array, so it converts too. That conversion does not happen in three cases: as the operand of sizeof, as the operand of the address-of operator, and when the literal initialises a char array. Everywhere else, you hold a pointer.

Because it is a pointer, every pointer notation applies. Pointer arithmetic moves through the text, * reads a character, and the subscript operator works because p[i] is simply another way of writing *(p + i). That is why "firmware"[3] is legal: the literal decays, three steps are added, and the character is read.

Save the next program as literal_demo.c. It reads a literal in several ways, measures it, and then asks a question that surprises many beginners: are two identical literals the same object?

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

int main(void)
{
    const char *msg = "Embedded C";

    printf("msg            : %s\n", msg);
    printf("*msg           : %c\n", *msg);
    printf("msg[9]         : %c\n", msg[9]);
    printf("*(msg + 4)     : %c\n", *(msg + 4));
    printf("sizeof literal : %zu\n", sizeof("Embedded C"));
    printf("strlen literal : %zu\n", strlen("Embedded C"));

    /* A literal is an array that decays to a pointer, so it can be indexed */
    printf("\"firmware\"[3]   : %c\n", "firmware"[3]);
    printf("3[\"firmware\"]   : %c\n", 3["firmware"]);

    /* Two identical literals: same object or not? The standard does not say. */
    const char *p1 = "GPIO";
    const char *p2 = "GPIO";
    printf("p1 == p2       : %s\n", p1 == p2 ? "same address" : "different addresses");
    printf("strcmp(p1, p2) : %d\n", strcmp(p1, p2));

    /* Two arrays are always two separate objects */
    char a1[] = "GPIO";
    char a2[] = "GPIO";
    printf("a1 == a2       : %s\n", (void *)a1 == (void *)a2 ? "same address" : "different addresses");
    printf("strcmp(a1, a2) : %d\n", strcmp(a1, a2));
    return 0;
}
gcc -std=c17 -Wall -Wextra -o literal_demo literal_demo.c
./literal_demo

Expected output:

msg            : Embedded C
*msg           : E
msg[9]         : C
*(msg + 4)     : d
sizeof literal : 11
strlen literal : 10
"firmware"[3]   : m
3["firmware"]   : m
p1 == p2       : same address
strcmp(p1, p2) : 0
a1 == a2       : different addresses
strcmp(a1, a2) : 0

Reading the output line by line

  • *msg and msg[9] give the first and last letters, and *(msg + 4) gives the fifth letter (count from index 0).
  • sizeof of the literal is 11 because it counts the terminator, while strlen says 10 because it does not.
  • "firmware"[3] and 3["firmware"] print the same letter. The second form is legal because a[b] means *(a + b) and addition is symmetric. Never write it in real code; it only proves the rule.
  • p1 == p2 reported the same address on the GCC used for this lecture, both with and without optimisation. Compilers merge identical literals to save space, which is common for string literals in C.
  • a1 == a2 reported different addresses because two arrays are two separate objects, even if they hold the same letters.

Comparing String Literals Correctly

Because a literal is a pointer in expressions, if (p1 == p2) asks whether both pointers hold the same address. Whether two identical literals share an address is unspecified by the C standard. The older textbook generation of compilers stored each literal separately, so the comparison was always false; current GCC usually merges them, so it is often true. Both answers are legal, which means a program relying on either one is broken.

Two ways of holding the same text

Casep1 and p2 (pointers to literals)a1 and a2 (arrays)
Objects holding the textone or two, compiler decidesalways two
== comparesaddressesaddresses
Result is reliable?NoAlways false for different arrays
To compare the text usestrcmpstrcmp

Rule to remember

To ask whether two strings contain the same characters, call strcmp(a, b) == 0. Use == on strings only when you really want to know whether two pointers refer to the very same memory.

Where String Literals Live in Embedded C Programming

On a desktop the linker puts literals in a read-only section of the executable. On a microcontroller the same section, usually called .rodata, is placed in flash. That has three practical consequences for C programming for embedded systems:

  • The text costs flash, not RAM. A hundred log messages can quietly consume kilobytes of program memory.
  • The pointer that refers to a literal costs only a few bytes of RAM (four on a 32-bit Cortex-M part).
  • Writing to a literal’s bytes is not allowed. We cover exactly what goes wrong in the next lecture.

Architecture note

On Harvard-architecture parts such as classic AVR, the CPU cannot read flash with ordinary pointer loads, so the toolchain copies literals into RAM at start-up unless you mark them with the vendor’s program-memory attribute. Check your target’s documentation before assuming literals are free of RAM cost.

Real-World Uses and Common Mistakes

Use 1

Printf format strings

Every printf("...") receives a pointer to a literal, so logging costs flash for each distinct message.

Use 2

Command tables

An array of const char * pointing at literals is the standard way to describe a serial console’s command names.

Use 3

Error text lookup

A table that maps an error code to a message literal keeps text out of the logic.

MistakeWhy it is wrongFix
Using == to compare stringsCompares addresses; result depends on the compilerUse strcmp
Assuming identical literals are separate (or shared)Unspecified by the standardNever depend on it
Holding a literal in a plain char *Invites an accidental writeDeclare it const char *
Printing an address with %uWrong on 64-bit systemsUse %p with a void * cast

Best Practices, Performance and Security

  • Declare pointers to literals as const char *. The compiler then rejects accidental writes.
  • When you use string literals in C, compile with -Wall -Wextra, and add -Wwrite-strings in C to get warnings when a non-const pointer receives a literal.
  • Performance: reusing the same literal costs nothing extra, but many nearly identical messages waste flash. Share common prefixes through format strings.
  • Security: never pass a literal you do not control as a printf format string. Use printf("%s", text), not printf(text).

Summary and Key Takeaways

  • String literals in C are arrays of char ending in a zero byte, written in double quotes.
  • In expressions it becomes a pointer to its first character, so *, [] and pointer arithmetic all work.
  • sizeof counts the terminator; strlen does not.
  • == compares addresses. Use strcmp for content.
  • Whether identical literals share storage is unspecified.

You now understand how string literals in C are stored and used whenever quoted text appears in your program. Next in this free embedded C course, we look at the rules that govern string literals: why you must not modify them, how a literal differs from a single character, how escape sequences work and how the compiler joins neighbouring literals.

Frequently Asked Questions

What are string literals in C?

String literals in C are sequences of characters inside double quotes, such as "GPIO". The quotes are not part of the text. The compiler stores the characters plus a terminating zero byte and gives you the address of the first character.

Is a string literal a pointer or an array?

It is an array of char. In most expressions that array automatically converts (decays) to a pointer to its first element, which is why you can assign a literal to a const char *. The exceptions are sizeof, the address-of operator and initialising a char array.

Why does == not compare two strings?

Applied to string literals or pointers, == compares addresses, not characters. Two pieces of text with identical letters can sit at different addresses, so use strcmp to compare content.

Are two identical string literals stored once or twice?

The C standard leaves it unspecified. Modern GCC at both -O0 and -O2 merges identical literals in one source file, while older compilers often stored each one separately. Never write code that depends on either behaviour.

Why can I write “firmware”[3]?

Because the literal decays to a pointer, and p[i] is defined as *(p + i). Indexing a literal directly is legal and gives the character at that position, here the letter m.

Where do string literals in C live on a microcontroller?

Typically in the read-only data section, which the linker places in flash. The pointer variable that refers to it lives in RAM, so the text costs flash space and the pointer costs a few bytes of RAM. Some architectures, such as classic AVR, copy literals to RAM unless told otherwise.

Topics Covered in This Lecture

string literals in Cstring constantconst char pointerstrcmp vs ==rodata flashembedded C programmingfree C tutorial

Keep Going With the Free C Programming Course

EmbeddedPathashala teaches C from the first printf to embedded-ready pointers and strings, completely free. Next: the rules of string literals, escapes and concatenation.

Need Help or More Information?

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

2 Comments

Leave a Reply

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