What is C String Literal Rules- Best 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 3 of 7

C String Literal Rules

Why literals are read-only, how a literal differs from a character, and how escapes and concatenation work.

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

What You Will Learn

  • Why a C literal must never be modified, and what actually happens if you try
  • The two roles a literal can play: a pointer expression and an array initialiser
  • The difference between a character constant 'b' and a string literal "b"
  • Escape sequences for backslash and double quotes inside a literal
  • Adjacent literal concatenation and line continuation
  • How to copy a literal into a writable array and when to use each form

Prerequisites

  • Lecture 2: string literals and pointers
  • Basic understanding of printf and the char type

In this free C programming course lecture we cover the C string literal rules that every embedded developer needs: what you may do with a literal, what you must never do, and how to write awkward characters such as quotes and backslashes. This free C tutorial ends with a real crash you can reproduce yourself, because seeing a segmentation fault once is the best way to remember the rule for good.

The Golden Rule of C String Literals

Never change the bytes of a string literal. The C standard says the result of attempting to modify one is undefined. Compilers put literals in read-only memory so the program can share them and so that flash devices need not keep them in RAM. Some old compilers happened to allow writes, and that is where the habit of hacking literals came from, but it is not portable and never was.

The crash program below makes a pointer to a literal and writes to it. Save it as literal_crash.c.

#include <stdio.h>

int main(void)
{
    char *p = "GPIOA";      /* points at the literal itself, not a copy */

    puts("before write");
    fflush(stdout);
    p[4] = 'B';             /* undefined behaviour: literal is read-only */
    puts("after write");
    return 0;
}
gcc -std=c17 -Wall -Wextra -o literal_crash literal_crash.c
./literal_crash

Expected output on Linux:

before write
Segmentation fault (core dumped)

The program compiles without a single warning, yet dies at the write. Now rebuild with one extra flag and let the compiler explain the danger:

gcc -std=c17 -Wall -Wextra -Wwrite-strings -o literal_crash literal_crash.c
literal_crash.c: In function 'main':
literal_crash.c:5:15: warning: initialization discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]

Make the compiler your safety net

Declare the pointer as const char *p = "GPIOA";. With that one keyword, the write p[4] = 'B'; becomes a compile error instead of a run-time crash, which is exactly when you want to find the mistake.

Literal as Array Initialiser: The Exception

There is one place where a literal does not become a pointer: when it initialises a char array. In char pins[] = "GPIOA"; the literal only supplies the starting values. The compiler creates an array of six bytes that belongs to you and fills it in. That array is ordinary writable memory, so changing it is perfectly fine.

Pointer to a literal versus array initialised by a literal

Declarationconst char *p = “GPIOA”;char pins[] = “GPIOA”;
What p / pins isa pointer (4 or 8 bytes)an array of 6 bytes
Where the text livesread-only data, sharedyour own writable copy
Can you modify the text?No, undefined behaviourYes
RAM costpointer only6 bytes (plus the flash copy of the initial values)

The first form is cheap on RAM but read-only. The second costs RAM and gives you a private copy. In embedded C programming, choose the first for fixed messages and the second only when you truly need to edit the text.

Character Constants Versus String Literals

Single quotes and double quotes look alike but create different things. 'b' is one integer value, the code of the letter b (98 in ASCII). "b" is an array of two chars: the letter and the zero terminator. Passing one where the other is expected is a classic beginner bug, and the compiler often only warns.

FormType in CsizeofValue / contents
'b'int4 on typical platforms98
"b"array of 2 char2‘b’ then 0

Escapes and Concatenation in String Literals

Inside a literal the backslash starts an escape sequence, so a real backslash must be written twice. A real double quote must be preceded by a backslash or it would end the literal early. Two adjacent literals are merged by the compiler, which lets you break a long message across several source lines without any run-time cost. A backslash as the very last character on a line also continues the literal, but any indentation on the next line becomes part of the text, so concatenation is almost always the cleaner choice.

Save this as literal_rules.c:

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

int main(void)
{
    /* 'b' is one integer value, "b" is a two-byte array */
    printf("'b' as number   : %d\n", 'b');
    printf("sizeof('b')     : %zu\n", sizeof('b'));
    printf("sizeof(\"b\")     : %zu\n", sizeof("b"));

    /* Escapes inside a literal */
    printf("Path: C:\\logs\\uart.txt\n");
    printf("He typed \"reset\" twice\n");

    /* Adjacent literals are joined at compile time */
    const char *banner = "Boot" " " "stage" " " "OK";
    printf("banner          : %s (length %zu)\n", banner, strlen(banner));

    /* Backslash at end of line continues the literal; indentation would
       become part of the text, so the next line starts at column 0 */
    const char *long_msg = "Part one, \
part two";
    printf("long_msg        : %s\n", long_msg);

    /* Array initialised from a literal: a private, writable copy */
    char pins[] = "GPIOA";
    pins[4] = 'B';
    printf("pins            : %s (sizeof %zu)\n", pins, sizeof pins);
    return 0;
}
gcc -std=c17 -Wall -Wextra -o literal_rules literal_rules.c
./literal_rules

Expected output:

'b' as number   : 98
sizeof('b')     : 4
sizeof("b")     : 2
Path: C:\logs\uart.txt
He typed "reset" twice
banner          : Boot stage OK (length 13)
long_msg        : Part one, part two
pins            : GPIOB (sizeof 6)

What to notice

  • The banner has 13 characters: Boot, a space, stage, a space, OK. The three pieces were joined at compile time.
  • long_msg prints as one line because the backslash-newline pair is removed before the literal is processed.
  • pins changed from GPIOA to GPIOB, and its size is 6: five letters plus the terminator.
  • The two escapes printed one backslash per pair and a pair of real quotes around reset.

Real-World Cases and Common Mistakes

Case 1

File paths on Windows tools

Host-side utilities that print paths need doubled backslashes inside literals.

Case 2

JSON or AT command strings

A modem command such as AT+CWJAP needs quotes inside the text, written with escaped double quotes.

Case 3

Long help screens

Adjacent literals let a firmware console print a tidy multi-line help text from readable source lines.

MistakeResultFix
Writing into char *p = "text"Crash or silent corruptionUse const char * or a char array
Using 'text' for a stringMulti-character constant, implementation-defined valueUse double quotes
Forgetting to double a backslashWrong escape sequence or compiler warningWrite \\
Indenting a continued literalSpaces become part of the textUse adjacent literals instead
Octal digit after \0 in a literal"\012" is one newline character, not NUL and 12Keep digits apart with concatenation

Best Practices, Performance and Security

  • Default to const char * for pointers to literals and -Wwrite-strings in your build flags.
  • Use an array initialised from a literal only when you need an editable copy, and note that every call of a function with a local char buf[] = "..." copies the bytes again.
  • Performance: on a microcontroller, a static const char msg[] = "..." stays in flash and is never copied, while a local array copy costs stack space and cycles.
  • Security: writing through a pointer into read-only memory is a bug that attackers cannot use, but a crash in a safety-critical device is still a failure. Catch it at compile time.

Summary and Key Takeaways

  • Never modify a literal. Declare pointers to literals as const char *.
  • A literal that initialises a char array only supplies initial values; the array is yours to edit.
  • 'b' is an integer, "b" is a two-byte string.
  • Use \\ and \" for a backslash and a double quote inside text.
  • Adjacent literals are joined at compile time with one terminator at the end.

With the literal rules in hand, you are ready to create string variables of your own. The next lecture of this free embedded C course shows how to declare, initialise and size writable string variables safely, and how sizeof and strlen differ for them.

Frequently Asked Questions

Can I modify a string literal in C?

No. Modifying one is undefined behaviour. On Linux the literal sits in read-only memory and the write crashes the program with a segmentation fault. On a microcontroller the write may fault, be ignored or corrupt flash behaviour depending on the part.

What is the difference between ‘b’ and “b”?

'b' is a single character constant with the numeric value 98 (type int in C). "b" is a string literal, an array of two chars holding the letter and a zero byte. They are not interchangeable.

How do I put a backslash or a double quote inside a string?

Escape them with a backslash: \\ produces one backslash and \" produces one double quote. Without the escape, a lone quote ends the literal and a lone backslash starts an escape sequence.

How does the compiler join two string literals?

When string literals sit next to each other separated only by whitespace, the compiler concatenates them into one literal and adds a single terminator at the end. This happens at compile time and costs nothing at run time.

Why can I change the characters of char pins[] = “GPIOA”?

Because the literal is only used to supply the initial values. The array pins is a separate, writable object that you own. The literal itself, if it exists in memory at all, is never touched.

Why does gcc not warn when I assign a literal to a char pointer?

In C the literal has type char array, so the assignment is legal. Add -Wwrite-strings and gcc warns that the initialisation discards const, which is exactly the protection you want.

Topics Covered in This Lecture

C string literal rulesread-only string literalescape sequencesconst charsegmentation faultfree C programming course

Keep Going With the Free C Programming Course

EmbeddedPathashala teaches C from the first printf to embedded-ready pointers and strings, completely free. Next: declaring and initialising string variables safely.

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 *