Question

char * const vs const char * in C and C++

cpointersconstants

Question

What is the difference between these two declarations in C or C++?

char * const pointer;
const char *pointer;

Specifically, which part is constant in each declaration: the pointer itself or the character data it points to?

Short Answer

By the end of this page, you will be able to read const in pointer declarations, determine whether a pointer can be reassigned or whether its pointed-to data can be changed, and choose the appropriate declaration for function parameters and variables.

Concept

const means that something cannot be modified through that name or expression. With pointers, there are two possible things that can be constant:

  1. The pointed-to value — the character data.
  2. The pointer variable — the memory address stored in the pointer.

A pointer declaration has both parts:

char *pointer;
  • char describes the data at the address.
  • pointer stores the address.

The location of const tells you what is protected.

const char *pointer;

The characters are read-only through pointer, but the pointer may later store a different address.

char * const pointer = buffer;

The pointer must keep the same address after initialization, but the characters in the buffer may be changed.

This distinction matters because APIs often need to express intent. A function that only reads text should accept const char *, preventing accidental edits to its input. A pointer that must always refer to one specific buffer can be declared char * const.

Mental Model

Think of a pointer as a sticky note containing a house address, and the characters as the items inside the house.

  • const char * means: you may move the sticky note to another house, but you are not allowed to change items in the current house through this note.
  • char * const means: the sticky note must keep the same address, but you may change items in that house.
  • const char * const means: the note cannot move, and the items cannot be changed through it.
Take Quiz

Syntax and Examples

The easiest reading rule is: start at the variable name and move outward.

char * const fixed_pointer = buffer;

fixed_pointer is a const pointer to char. Its address cannot change.

char buffer[] = "cat";
char other[] = "dog";

char * const fixed_pointer = buffer;
fixed_pointer[0] = 'C';  // Valid: changes buffer to "Cat"

// fixed_pointer = other; // Error: fixed_pointer itself is const
const char *read_only_pointer = "cat";

read_only_pointer is a pointer to const char. The pointer may change, but modifying a character through it is forbidden.

const char *read_only_pointer = "cat";
const char *other = "dog";

read_only_pointer = other; // Valid: pointer now refers to "dog"

// read_only_pointer[0] = 'C'; // Error: pointed-to char is const

You can make both parts constant:

const char * const fixed_read_only_pointer = "cat";

// fixed_read_only_pointer = "dog";       // Error
// fixed_read_only_pointer[0] = 'C';       // Error

In C, const char * and char const * mean exactly the same thing. Many developers prefer const char * because it reads naturally as “pointer to constant characters.”

Step by Step Execution

Consider this C example:

#include <stdio.h>

int main(void) {
    char name[] = "Ada";
    char city[] = "Rome";

    char * const current_name = name;
    const char *label = "Name";

    current_name[0] = 'E';
    label = city;

    printf("%s: %s\n", label, current_name);
    return 0;
}

Step by step:

  1. name is a writable character array containing "Ada".
  2. city is another writable character array containing "Rome".
  3. current_name is initialized with the address of name. Its address is now fixed because the pointer is const.
  4. label initially points to the string literal "Name". Its pointed-to characters are const through label.
  5. current_name[0] = 'E' is valid because current_name points to writable characters. name becomes "Eda".
  6. label = city is valid because label itself is not constant; it can point elsewhere.
  7. The program prints:
Rome: Eda

The code could not reassign current_name, and it could not modify characters through label.

Real World Use Cases

  • Read-only text parameters: Functions that inspect text without editing it should use const char *.

    size_t text_length(const char *text);
    
  • String literals: A string literal should be treated as read-only. In C++, assigning one to char * is invalid; use const char *.

    const char *message = "File not found";
    
  • Fixed output buffer pointer: Within a function, char * const can state that the function will write into one selected buffer and should not redirect the pointer.

    void make_uppercase(char * const buffer);
    
  • Embedded and systems code: A pointer to memory-mapped data may be fixed, while access to the data is controlled separately. Qualifiers communicate those constraints.

  • Library interfaces: const helps callers and maintainers understand whether a function might alter their data.

Take Quiz

Real Codebase Usage

In production code, const char * is much more common than char * const in public function declarations because read-only input is a frequent requirement.

Read-only function input

#include <stdio.h>

void print_status(const char *message) {
    if (message == NULL) {
        return;
    }

    puts(message);
}

The const contract says print_status will not change the caller's text through message.

Mutable buffer with validation

#include <ctype.h>
#include <stddef.h>

void uppercase_ascii(char *text) {
    if (text == NULL) {
        return;
    }

    for (size_t i = 0; text[i] != '\0'; i++) {
        text[i] = (char)toupper((unsigned char)text[i]);
    }
}

This parameter is char * rather than const char * because the function intentionally changes the buffer.

Using a const pointer locally

void replace_spaces(char *text) {
    if (text == NULL) {
        return;
    }

    char * const start = text;

    for (; *text != '\0'; text++) {
        if (*text == ' ') {
            *text = '_';
        }
    }

    /* start still holds the original buffer address. */
}

Here, start documents that the original address should not be reassigned. This can be useful locally, though it is less common than a pointer-to-const parameter.

Top-level const on a function parameter is usually not part of the function's external interface. For example, these declarations describe the same callable function type:

void process(char *text);
void process(char * const text);

The second form only restricts how text may be used inside the function implementation.

Common Mistakes

Confusing a constant pointer with a pointer to constant data

This declaration does not make the characters constant:

char * const pointer = buffer;

It only prevents pointer from being assigned a new address.

Attempting to write through const char *

const char *text = "hello";
// text[0] = 'H'; // Invalid

Use a writable array if you need to edit text:

char text[] = "hello";
text[0] = 'H';

Treating string literals as writable

This is unsafe in C and invalid in C++:

char *text = "hello";

A string literal must not be modified. Prefer:

const char *text = "hello";

Forgetting initialization for a const pointer

A const pointer must receive its address when declared:

char buffer[10];
char * const pointer = buffer;

This is invalid because there is no later opportunity to assign the pointer:

// char * const pointer;

Assuming const always makes an object completely immutable

const char *pointer prevents modification through that pointer. The underlying data may still be writable through another non-const pointer.

char buffer[] = "cat";
const char *reader = buffer;
char *writer = buffer;

writer[0] = 'C'; // Valid
/* reader now observes "Cat". */

Do not use this fact to bypass an object's intended read-only contract.

Comparisons

DeclarationCan reassign the pointer?Can modify characters through the pointer?Meaning
char *pYesYesPointer to mutable characters
const char *pYesNoPointer to read-only characters
char * const pNoYesFixed pointer to mutable characters
const char * const pNoNoFixed pointer to read-only characters

const char *p and char const *p are identical. Only the style differs.

Also distinguish a pointer from an array:

char text[] = "hi";        // Array storage; elements are writable
const char *text2 = "hi";  // Pointer to read-only characters

An array name cannot be reassigned, but that is an array rule, not the same as declaring a const pointer.

Take Quiz

Cheat Sheet

char *p;

Pointer can move; characters can change.

const char *p;
char const *p;

Pointer can move; characters cannot change through p.

char * const p = buffer;

Pointer cannot move; characters can change.

const char * const p = "text";

Pointer cannot move; characters cannot change through p.

Rules:

  • const before the base type applies to pointed-to data: const char *.
  • const after * applies to the pointer: char * const.
  • A const pointer needs an initializer.
  • Use const char * for text that a function only reads.
  • Treat string literals as read-only; use const char * for them.
  • const char * does not guarantee that the underlying object can never change; it only prevents writes through that pointer.

FAQ

Is const char * the same as char const *?

Yes. Both declare a pointer to constant char data.

Can I change the pointer in const char *p?

Yes. p may point to a different character sequence. Only *p is read-only through p.

Can I change the pointer in char * const p?

No. The address stored in p is constant after initialization.

Can I modify a string literal through char * const?

No. char * const makes the pointer fixed; it does not make the pointed-to memory writable. Writing to a string literal has undefined behavior in C and is not allowed in C++.

Why does char * const need an initializer?

Because a const pointer cannot be assigned after it is declared. It must receive its one permitted address immediately.

Should a function parameter use char * const?

It can be useful inside an implementation, but callers generally do not see a difference. const char * is more important in an API because it tells callers their input will not be modified.

Does const char * make the original array constant?

No. It only prevents changes through that particular pointer. Other writable references to the same array can still modify it.

Take Quiz

Mini Project

Description

Create a small C program that separates read-only labels from a writable text buffer. It demonstrates a common pattern: display text from a const char * and transform caller-provided text through a char * parameter.

Goal

Print a read-only label and convert a mutable message buffer to uppercase without changing the label.

Requirements

Create a function that accepts const char * and prints a label. Create a function that accepts char * and converts its text to uppercase. Store the label as a string literal through a const char *. Store the message in a writable character array. Print the message before and after converting it.

Take Quiz

Keep learning

Related questions

View more