The first one creates a pointer that points to the string literal "hello", which is probably stored in non-writable memory in the executable image of the program. Even if it isn't, you are not allowed to modify the contents of that array.

The second one creates an automatic array1 (on the stack (usually, but that is implementation-defined)) and initialises it with the string "goodbye". It is equivalent to

char const b[] = {'g', 'o', 'o', 'd', 'b', 'y', 'e', 0};

So while "goodbye" is immutable because it is a string literal which is char const[8] and stored in non-writable memory, the array b is an automatic1 array that is immutable because you marked it const, but you could remove the const from the variable declaration to make the array's contents mutable. You are only initialising the contents of the array with the contents of the array "goodbye".

You are not allowed to modify either of them because they are both const char[], but the second one could be changed to char[] to be mutable, while the first one could not.

See this answer for more info: https://stackoverflow.com/a/9106798/726361


1 As R. Martinho Fernandes pointed out in the comments, the syntax T x[] = ... could also create a static array (not automatic but static (in the executable image usually, but that's implementation defined)) if it is at namespace scope, and it's only an automatic array otherwise.

Answer from Seth Carnegie on Stack Overflow
Top answer
1 of 5
21

The first one creates a pointer that points to the string literal "hello", which is probably stored in non-writable memory in the executable image of the program. Even if it isn't, you are not allowed to modify the contents of that array.

The second one creates an automatic array1 (on the stack (usually, but that is implementation-defined)) and initialises it with the string "goodbye". It is equivalent to

char const b[] = {'g', 'o', 'o', 'd', 'b', 'y', 'e', 0};

So while "goodbye" is immutable because it is a string literal which is char const[8] and stored in non-writable memory, the array b is an automatic1 array that is immutable because you marked it const, but you could remove the const from the variable declaration to make the array's contents mutable. You are only initialising the contents of the array with the contents of the array "goodbye".

You are not allowed to modify either of them because they are both const char[], but the second one could be changed to char[] to be mutable, while the first one could not.

See this answer for more info: https://stackoverflow.com/a/9106798/726361


1 As R. Martinho Fernandes pointed out in the comments, the syntax T x[] = ... could also create a static array (not automatic but static (in the executable image usually, but that's implementation defined)) if it is at namespace scope, and it's only an automatic array otherwise.

2 of 5
7

A string literal has type char const[N]; of course a name of this type may decay to a char const*.

Now:

  1. A char array may be initialised by a string literal (8.5.2/1), and since you cannot otherwise copy or assign arrays, it follows that this initialisation implements a copy. You're free to do with the new, mutable array whatever you like.

    char str[6] = "hello";
    
  2. Conversely, when initialising a pointer, you're obtaining a pointer that's the result of the string literal's immutable array type decaying.

    char const* str = "hello";
    

    There is no new array here. Just copying a pointer to the existing, immutable data.

🌐
Reddit
reddit.com › r/cpp_questions › what makes a literal string become immutable?
r/cpp_questions on Reddit: What makes a literal string become immutable?
August 12, 2023 -

I tried this:

char MS[] = "Hello"; // MUTABLE String
char *IS = "Hello"; // IMMUTABLE String !!

MS[0] = 'M';
IS[0] = 'I'; // Crashes!

Why is the pointer String IS immutable while the MS one isn't? Any specifics about this situation?

🌐
Cornell Computer Science
cs.cornell.edu › courses › cs3410 › 2026sp › rsrc › c › string.html
Strings - CS 3410 Spring 2026
The const shows up here because the characters in a string literal cannot be modified. A mutable string has type char*, without the const. How can you declare a mutable string with a string literal, if string literals are always const? Here’s a trick you can use: remember that, in C, an array is like a pointer to its first element.
🌐
Substack
andrewjohnson4.substack.com › andrew’s substack › understanding how c strings are stored in the data section of a c program
Understanding How C Strings Are Stored in the Data Section of a C Program
October 24, 2024 - These literals are immutable and shared between functions or code blocks if they have the same value. Read-Write Strings: Global and static strings are placed in the read-write section, as these are mutable.
🌐
Reddit
reddit.com › r/programminglanguages › mutable or immutable strings?
r/ProgrammingLanguages on Reddit: Mutable or Immutable strings?
November 22, 2021 -

What are the advantages of representing strings with an immutable data strucure?

A few good points i've read:

  • Easier to compare (compare by pointer)

  • Less expensive to copy

  • String pool cuts down the use of memory

Other than that, most other arguments are about immutable objects in general, ie. thread safety, optimizations, easier to reason, etc

That said, i'm considering to represent strings internally with a Mutable data structure, essentially, the string type is an alias to []byte (dynamic size byte array or byte slice), and as such is completely mutable. And here is why:

  • Fits better with the type system (specially with generics1), since all operations on slices can be done with strings

  • Less confusion on why you can mutate an item in a slice but not on a string

  • Less runtime complexity

Additionally, since function parameters are immutable by default in my language, we can pass slices by reference, not needing a copy. If you need to mutate an argument, however, i'm still deciding, either you need to explicitly pass a pointer to the value you want to mutate or you must specify that particular parameter as mutable.

1 - There are 5 (and only 5) typeclasses in my language: anything -> comparable -> orderable -> numerical -> integer. Each typeclass has associated operators. User defined types are automatically assigned to this typeclasses if they can be ordered, compared, etc. The language has an 'append' operator: a .. b appends b to the end of a, this operation is supported by both strings and slices. If strings are not slices, then i would need yet another typeclass to represent appendables. With strings being aliases, it's trivial to write generic algorythms that work in both slices and strings:

generic ReverseInPlace over T
    fn(list:&[]T) {
        var start = 0,
            end   = (@list).length;

        for start < end {
            val temp <- (@list)[start];
            (@list)[start] <- (@list)[end];
            (@list)[end] <- temp;

            start <- start + 1;
            end <- end - 1;
        }
    }

Edit: Thank you for all your input, after careful consideration, i decided to issue a compiler warning whenever string is indexed or mutated in place. That way the user will still be aware of string encodings but the type will fit well within the type system, without creating a special case. string is an alias to []byte but with training wheels, since the compiler knows this particular set of bytes is talking about the mess that is the human language. I'm sorry if that's not the outcome you expected, but in my view it's what best fits the language.

Top answer
1 of 12
79
essentially, the string type is an alias to []byte Lol, I love the optimism. Unfortunately, your "strings are an array of characters/bytes/runes/whatever" assumption doesn't hold once you leave the world of ASCII. If you are using UTF-8 to encode your strings then replacing a u character with ü means you need to create a new copy of the string because the former is encoded as 0x55 while the latter is encoded as 0xC3 0xBC. If you decide to use UTF-16, you can say that string is an alias for u16[]. This mostly works, except there are more than 65536 unicode characters so you still need some form of variable-length encoding. Variable length encodings mean that "simple" operations like "get the 5th letter" require iterating through the entire string. Treating strings as arrays of unicode code points without any variable-length shenanigans (i.e. u32[]) gives you constant-time indexing again, but at the cost of 2-4x memory usage. Even then, treating strings as arrays of unicode code points isn't valid because a single "glyph" (single pictogram you might draw) may be composed of multiple code points. For example, the ü from earlier could have been written as combination of u and an umlaut accent. Individual programs can get away with being sloppy around handling unicode, but not a programming language. I'd take a note out of Go and Rust's book and treat strings as immutable, mostly opaque, UTF-8 bytes. TL;DR: Strings aren't arrays. Treating strings as arrays will teach your users bad habits. Modifying an existing string in place is not always possible. Welcome to the mess that is human language 🙂
2 of 12
25
Seems like you’re conflating immutable strings with string pooling. I think immutable strings make sense, but deterministic string pooling is going to be a cache and synchronisation worst-case scenario. I can’t imagine going with that option on modern architectures. But then you don’t get benefits like pointer comparison.
🌐
Daniel Lemire's blog
lemire.me › blog › 2017 › 07 › 07 › are-your-strings-immutable
Are your strings immutable? – Daniel Lemire's blog
July 10, 2017 - Arguably, the most important non-numeric type in software is the string. A string can be viewed as an array of characters so it would not be unreasonable to make it mutable, but strings are also viewed as primitive values (e.g., we don’t think of “Daniel” as an array of 6 characters).
🌐
Quora
quora.com › What-is-the-reason-why-strings-are-not-mutable-in-C
What is the reason why strings are not mutable in C++? - Quora
What is the reason why strings are not mutable in C++? But… they are mutable, unless you explicitly tell the compiler that it has to be constant: a code like [code]#include #include int main(){ std::string word="hello"; std::cout
Find elsewhere
🌐
Techbuddies
techbuddies.io › home › all posts › working with the infamous strings in c made easy
Working with the Infamous Strings in C Made Easy - Techbuddies Studio
October 8, 2025 - As there is no native string data ... mark the end of a string. Depending on how you declare this “string”, it can be either mutable or immutable....
🌐
SCSynth
scsynth.org › questions
Why are strings immutable? - Questions - scsynth
May 17, 2024 - I’m sure that I’m missing something here… but why are strings immutable. In other languages, you want immutable strings so you can intern them and making their hashes equivalent. This isn’t necessary in supercollider because we have explicitly interned strings (Symbol).
🌐
Code with C
codewithc.com › code with c › c++ tutorial › are c++ strings mutable? understanding their characteristics
Are C++ Strings Mutable? Understanding Their Characteristics - Code With C
December 22, 2023 - Then, we access and modify the first character of str by using the [] operator, setting it to 'J'. This operation confirms that strings in C++ are mutable, allowing individual characters to be changed.
Top answer
1 of 3
9

This issue is strongly connected to the notion of what it means to be an instance of a class. In strict Object-Oriented terms, a class has an associated invariant: a predicate which always holds true on exit from a (public) method of the class. Such a notion is central in ensuring that inheritance is well-defined, for example (it's part of the Liskov Substitution Principle).

One of the most pernicious issues with Java is that it is difficult to prevent client code from breaking class invariants.

For example, consider the following 'ZipCode' class:

class ZipCode {
    private String zipCode;

    public ZipCode(String value){
        if(!isValidZipCode(value))
            throw new IllegalArgumentException();
        zipCode = value;
        assert(invariant());
    }

    public String get() { return zipCode; }

    public boolean invariant() {
        return isValidZipCode( zipCode );
    }
}

If String were not immutable, it would be possible for a user of ZipCode to call 'get' and change the characters at any subsequent time, thereby breaking the invariant and destroying the conceptual integrity offered by the encapsulation of the ZipCode concept.

Since this kind of integrity is essential to ensuring that large systems are valid, this answer to your question really begs the wider one of:

"Why doesn't Java support an analog of C++ const, or at least offer immutable versions of more of it's library classes?"

2 of 3
7

Things like strings and dates are naturally values. In C++ terms, we expect them to have a copy constructor, an assignment operator, and an equality operator, but we never expect to take their address. Hence, we don't expect them to be individually allocated on the heap. Virtual methods make no sense.

Domain objects are naturally references. C++ ones have no copy constructor, assignment operator, or equality operator (they are equal only if identical). We can take their address and we do expect them to be heap allocated. Methods are generally virtual.

Java has no value classes, only reference ones. Values are faked with immutable objects. This is true for strings, but not, unfortunately, for dates. The mutability of Java dates has caused frequent problems, and is now deprecated. Mutable values can't be used as a basis for a hash, for example.

🌐
CodeHS
codehs.com › tutorial › 12677
Tutorial: String Basics in C++ | CodeHS
Click on one of our programs below to get started coding in the sandbox
🌐
YouTube
youtube.com › thenewboston
Objective C Programming Tutorial - 55 - Mutable Strings - YouTube
Source Code: https://github.com/thenewboston-developersCore Deployment Guide (AWS): https://docs.google.com/document/d/16NDHWtmwmsnrACytRXp2T9Jg7R5FgzRmkYoDt...
Published   May 29, 2010
Views   23K
Top answer
1 of 2
44

Historically (perhaps by rewriting parts of it), it was the contrary. On the very first computers of the early 1970s (perhaps PDP-11) running a prototypical embryonic C (perhaps BCPL) there was no MMU and no memory protection (which existed on most older IBM/360 mainframes). So every byte of memory (including those handling literal strings or machine code) could be overwritten by an erroneous program (imagine a program changing some % to / in a printf(3) format string). Hence, literal strings and constants were writable.

As a teenager in 1975, I coded in the Palais de la Découverte museum in Paris on old 1960s era computers without memory protection: IBM/1620 had only a core memory -which you could initialize thru the keyboard, so you had to type several dozens of digits to read the initial program on punched tapes; CAB/500 had a magnetic drum memory; you could disable writing some tracks thru mechanical switches near the drum.

Later, computers got some form of memory management unit (MMU) with some memory protection. There was a device forbidding the CPU to overwrite some kind of memory. So some memory segments, notably the code segment (a.k.a. .text segment) became read-only (except by the operating system which loaded them from disk). It was natural for the compiler and the linker to put the literal strings in that code segment, and literal strings became read only. When your program tried to overwrite them, it was bad, an undefined behavior. And having a read-only code segment in virtual memory gives a significant advantage: several processes running the same program share the same RAM (physical memory pages) for that code segment (see MAP_SHARED flag for mmap(2) on Linux).

Today, cheap microcontrollers have some read-only memory (e.g. their Flash or ROM), and keep their code (and the literal strings and other constants) there. And real microprocessors (like the one in your tablet, laptop or desktop) have a sophisticated memory management unit and cache machinery used for virtual memory & paging. So the code segment of the executable program (e.g. in ELF) is memory mapped as a read-only, shareable, and executable segment (by mmap(2) or execve(2) on Linux; BTW you could give directives to ld to get a writable code segment if you really wanted to). Writing or abusing it is generally a segmentation fault.

So the C standard is baroque: legally (only for historical reasons), literal strings are not const char[] arrays, but only char[] arrays that are forbidden to be overwritten.

BTW, few current languages permit string literals to be overwritten (even Ocaml which historically -and badly- had writable literal strings has changed that behavior recently in 4.02, and now has read-only strings).

Current C compilers are able to optimize and have "ions" and "expressions" share their last 5 bytes (including the terminating null byte).

Try to compile your C code in file foo.c with gcc -O -fverbose-asm -S foo.c and look inside the generated assembler file foo.s by GCC

At last, the semantics of C is complex enough (read more about CompCert & Frama-C which are trying to capture it) and adding writable constant literal strings would make it even more arcane while making programs weaker and even less secure (and with less defined behavior), so it is very unlikely that future C standards would accept writable literal strings. Perhaps on the contrary they would make them const char[] arrays as they morally should be.

Notice also that for many reasons, mutable data is harder to handle by the computer (cache coherency), to code for, to understand by the developer, than constant data. So it preferable to have most of your data (and notably literal strings) stay immutable. Read more about functional programming paradigm.

In the old Fortran77 days on IBM/7094, a bug could even change a constant: if you CALL FOO(1) and if FOO happened to modify its argument passed by reference to 2, the implementation might have changed other occurrences of 1 into 2, and that was a really naughty bug, quite hard to find.

2 of 2
3

Compilers couldn't combine "more" and "regex", because the former has a null byte after the e while the latter has an x, but many compilers would combine string literals which matched perfectly, and some would also match string literals that shared a common tail. Code which changes a string literal may thus change a different string literal which is used for some entirely different purpose but happens to contain the same characters.

A similar issue would arise in FORTRAN prior to the invention of C. Arguments were always passed by address rather than by value. A routine to add two numbers would thus be equivalent to:

float sum(float *f1, float *f2) { return *f1 + *f2; }

In the event that one wanted to pass a constant value (e.g. 4.0) to sum, the compiler would create an anonymous variable and initialize it to 4.0. If the same value was passed to multiple functions, the compiler would pass the same address to all of them. As a consequence, if a function which modified one of its parameters was passed a floating-point constant, the value of that constant elsewhere in the program could get changed as a result, thus leading to the saying "Variables won't; constants aren't".

🌐
D Programming Language
dlang.org › blog › 2021 › 05 › 24 › interfacing-d-with-c-strings-part-one
Interfacing D with C: Strings Part One | The D Blog
May 24, 2021 - The C char* can be encoded as UTF-8, ... types are dynamic arrays with immutable contents, i.e., string is an alias to immutable(char)[]. C strings are mutable by default....
🌐
Hacker News
news.ycombinator.com › item
Why (are mutable strings insane)? | Hacker News
September 21, 2013 - The problem with strings being mutable by default is that one has to do a lot of defensive copying to avoid unexpected behavior. Mutable strings do have their place, inside a function that's building up a string, before that string is visible to any other part of the program.
🌐
Quora
quora.com › Does-C-has-concept-of-mutable-and-immutable-values-like-Python
Does C has concept of mutable and immutable values like Python? - Quora
Answer (1 of 2): Yes. There is a concept of mutable and immutable in C. The keyword called const gives you immutability. whenever you specify this keyword before any variable datatype declaration, e.g. const int x = 10; This means you can't change the value of x. If you try to do so then comp...