Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.
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.
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:
| Literal | Characters stored | Bytes in memory |
|---|---|---|
"V" | V | 2 (V and the terminator) |
"Embedded C" | E m b e d d e d, space, C | 11 |
"2345" | four digit characters, not a number | 5 |
"" | nothing | 1 (only the terminator) |
"id=%d\n" | a printf control string is also just text | 7 |
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
| Where | Object | Holds |
|---|---|---|
| Flash (read-only data) | the literal’s array | E m b e d d e d space C and a zero byte |
| RAM | pointer variable msg | the 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
*msgandmsg[9]give the first and last letters, and*(msg + 4)gives the fifth letter (count from index 0).sizeofof the literal is 11 because it counts the terminator, whilestrlensays 10 because it does not."firmware"[3]and3["firmware"]print the same letter. The second form is legal becausea[b]means*(a + b)and addition is symmetric. Never write it in real code; it only proves the rule.p1 == p2reported 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 == a2reported 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
| Case | p1 and p2 (pointers to literals) | a1 and a2 (arrays) |
|---|---|---|
| Objects holding the text | one or two, compiler decides | always two |
| == compares | addresses | addresses |
| Result is reliable? | No | Always false for different arrays |
| To compare the text use | strcmp | strcmp |
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
Printf format strings
Every printf("...") receives a pointer to a literal, so logging costs flash for each distinct message.
Command tables
An array of const char * pointing at literals is the standard way to describe a serial console’s command names.
Error text lookup
A table that maps an error code to a message literal keeps text out of the logic.
| Mistake | Why it is wrong | Fix |
|---|---|---|
Using == to compare strings | Compares addresses; result depends on the compiler | Use strcmp |
| Assuming identical literals are separate (or shared) | Unspecified by the standard | Never depend on it |
Holding a literal in a plain char * | Invites an accidental write | Declare it const char * |
Printing an address with %u | Wrong on 64-bit systems | Use %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-stringsin 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), notprintf(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. sizeofcounts the terminator;strlendoes not.==compares addresses. Usestrcmpfor 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
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