In C/C++, the keyword const is used to define constants or restrict the modification permissions of variables/functions. Its usage is flexible and diverse, with the core function being to protect data from accidental modification, while also enhancing code readability and compile-time checking capabilities.
Usage in C
1. Defining Read-Only Variables
The const keyword in C is used to declare a variable that cannot be modified after initialization (read-only variable). The compiler will check and prevent direct assignment to it.
a. Example
#include <stdio.h>
int main()
{
// Define a read-only variable a, cannot be modified after initialization
const int a = 10;
// Error: the compiler will report an error
// (error: assignment of read-only variable 'a')
a = 20;
// Correct: can read
printf("%d\n", a);
return 0;
}
2. Combining with Pointers
Due to the different forms of const combined with pointers, their meanings and functions will also vary accordingly, so it is important to distinguish between “constant pointers” and “pointer constants”.
✧Constant Pointer: The content pointed to by the pointer is constant and cannot be modified through the pointer, but the pointer itself can point to other addresses.
➢Syntax: const data_type* pointer_name; or data_type const* pointer_name.
➢Memory Aid: const is on the left of *.
✧Pointer Constant: The pointer itself is constant, and once it points to a certain address, it cannot point to another address, but the content pointed to can be modified (provided the content is not constant).
➢Syntax: data_type* const pointer_name = initial_address;
➢Memory Trick: const is on the right of *.
✧Mnemonic Comparison Table

✧Example:
a) const int* p (constant pointer): Pointer p points to read-only content (cannot modify content through p), but p itself can point to other addresses.
b) int* const p (pointer constant): Pointer p itself is read-only (cannot modify p’s pointing), but can modify the pointed content through p.
c) const int* const p (constant pointer constant / pointer to constant): Both pointer p and its pointed content are read-only.
d) Example
int x = 10, y = 20;
const int* p1 = &x;
// Error: cannot modify pointed content
*p1 = 30;
// Correct: can modify pointing
p1 = &y;
int* const p2 = &x;
// Correct: can modify content
*p2 = 30;
// Error: cannot modify pointing
p2 = &y;
3. Modifying Function Parameters
When const modifies function parameters, it restricts the function from modifying that parameter internally (protecting the actual parameter), especially suitable for pointer parameters to prevent accidental modification of the data pointed to by the actual parameter.
✧Example
// const modifies pointer parameters: prevents function from modifying the content pointed to by the actual parameter
void print(const int* p)
{
// Error: cannot modify content pointed to by const pointer
*p = 100;
}
int main()
{
int a = 5;
// Correct: pass the address of a
print(&a);
return 0;
}
4. Modifying Function Return Values
Modifying function return values is similar to C++, refer to the following.
Usage in C++
C++ extends the usage of const in C based on its own features, and the usage is almost the same, but in C++, it means a constant (while in C it indicates read-only). The C++ compiler may optimize such variables to generate compile-time constants.
1. Defining Constants
// a is a constant, cannot be modified after initialization
const int a = 10;
// Error: const variable cannot be assigned
a = 20;
// Equivalent to const int b;
// (const and type positions can be interchanged)
int const b = 20;
✧Initialization Requirement: const variables must be initialized at the time of definition.
✧Scope: Follows the scope rules of ordinary variables, local const variables are only valid within the function, and global const variables default to having static characteristics, visible only in the current file.
2. Special Nature of Global const Variables
Global const variables default to having internal linkage (visible only in the current .cpp file), which is different from the external linkage of non-const global variables, and can avoid naming conflicts across files.
// file1.cpp
// Internal linkage, visible only in file1.cpp
const int g_val = 100;
// file2.cpp
// Error: cannot access const global variable from file1.cpp
// Explicitly declaring extern changes it to external linkage, accessible across files
extern const int g_val = 200;
3. Combining with References
References are essentially aliases for variables. When const modifies a reference, it indicates that the object pointed to cannot be modified through that reference (but the object itself may not be const)..
int a = 10;
// const reference, cannot modify a through ref_a
const int& ref_a = a;
// Error
ref_a = 20;
// Correct: a itself is not const, can be modified
a = 20;
const int b = 30;
// Correct: const reference can bind to const variable
const int& ref_b = b;
// Error: non-const reference cannot bind to const variable (will break const property)
int& ref_b2 = b;
✧Special Rule: const references can bind to temporary objects (non-const references cannot), and the lifetime of the temporary object will be extended to match that of the reference.
#include <iostream>
#include <string>
using namespace std;
string func()
{
// Return temporary object
return "hello";
}
int main()
{
// Correct, const reference binds to temporary object
const string& s = func();
// This will compile error
string& s = func();
// Output: hello
cout << s << endl;
return 0;
}
4. Modifying Function Parameters
When const modifies function parameters, it restricts the function from modifying that parameter, protecting the actual parameter from accidental modification, especially suitable for reference or pointer parameters (avoiding copies and preventing modification).
✧Modifying Value-Passing Parameters (syntax allowed, but not meaningful)
Value-passing parameters will generate copies, and when modified with const, it only restricts the function from modifying the copy, with no effect on the actual parameter, thus having limited practical use..
void func(const int x)
{
// Error: x is a copy, const restricts the function from modifying x
// x = 20;
}
✧Modifying Pointer/Reference Parameters (recommended)
For reference or pointer parameters, const can prevent the function from modifying the actual parameter while avoiding unnecessary copies. References are a new usage in C++, and the modification rules for pointers are consistent with C.
// const reference parameter: avoid copies, and cannot modify actual parameter
void print(const std::string& s)
{
// Error: cannot modify const reference
s = "hello";
}
// const pointer parameter: cannot modify actual parameter through pointer
void func(const int* p)
{
// Error
*p = 100;
}
5. Modifying Function Return Values
When const modifies function return values, it restricts the usage of the return value (e.g., cannot be assigned as an lvalue), commonly seen in scenarios returning pointers or references.
✧Return Value as const Variable
When the return value is of value type, modifying the return value with const will make the return value unmodifiable, but since it is a copy, the actual impact is minimal..
When the return value is of pointer type, const can prevent the caller from modifying the original data through the returned pointer.
const int* add(int a, int b)
{
static int value = 100;
return &value;
}
// Correct
const int* x = add(2, 3);
// Error
*x = 200;
✧Returning const Pointer/Reference (recommended)
When returning pointers or references, const can prevent the caller from modifying internal data through the return value (protecting private members of a class)..
class MyClass
{
public:
// Return const reference: caller cannot modify data
const int& GetData() const
{
return data;
}
private:
int data = 100;
};
MyClass obj;
// Correct: read data
int x = obj.GetData();
const int& y = obj.GetData();
// Error: cannot modify through const reference
y = 200;
6. Modifying Class Member Functions (Const Member Functions)
When const modifies class member functions, that function cannot modify the non-static member variables of the class, nor can it call non-const member functions (ensuring that the function does not change the object’s state).
✧Basic Usage: const is placed after the function parameter list, declaring it as a const member function.
✧Example
class MyClass
{
public:
MyClass(int v)
: value(v) {}
// Const member function: cannot modify member variables, cannot call non-const functions
int GetValue() const
{
// Error: cannot modify member variable
value = 200;
return value;
}
// Non-const member function: can modify member variables
void SetValue(int v)
{
value = v;
}
private:
int value;
};
7. Calling Restrictions for const and Non-const Objects
✧const Object: Can only call const member functions (ensuring that the object’s state is not modified).
✧Non-const Object: Can call both const and non-const member functions, and if there are overloads, the non-const version is called first.
✧Example
int main()
{
// const object
const MyClass c_obj(10);
// Correct: call const member function
c_obj.GetValue();
// Error: const object cannot call non-const function
c_obj.SetValue(20);
// Non-const object
MyClass obj(20);
// Correct
obj.GetValue();
obj.SetValue(30);
return 0;
}
8. Overloading const Member Functions
const can be used as a distinguishing condition for function overloading, and the const version and non-const version are different functions.
class MyClass
{
public:
MyClass(int v)
: value(v) {}
// const member function
int GetValue() const
{
return value;
}
// non-const member function
int GetValue()
{
return value;
}
private:
int value;
};
int main()
{
// const object
const MyClass c_obj(10);
// Correct: call const member function
c_obj.GetValue();
// non-const object
MyClass obj(20);
// Correct
obj.GetValue();
return 0;
}
9. const and constexpr (C++11 and later)
constexpr is a keyword introduced in C++11, used to declare compile-time constants (values that can be computed at compile time), while const only indicates read-only (may be initialized at runtime).
✧Differences between the two:
➢const: Cannot be modified after initialization, and the initialization value can be the result of runtime computation (e.g., const int x = rand();).
➢constexpr: Must determine the value at compile time, can be used in compile-time contexts (e.g., array sizes, template parameters).
✧Example
constexpr int add(int x, int y)
{
return x + y;
}
int main()
{
// Can be a compile-time constant
const int a = 10;
// Must be a compile-time constant
constexpr int b = 20;
int n = 5;
// Correct: c is a read-only variable (initialized at runtime)
const int c = n;
// Error: n is a runtime variable, cannot be used for constexpr
constexpr int d = n;
// Correct: computed at compile time as 5
constexpr int e = add(2, 3);
return 0;
}
10. const Modifying Static Members of Classes
When const modifies static member variables of a class, that variable is shared among all objects of the class, and its value cannot be modified. It must be declared within the class and initialized outside the class (C++17 allows inline initialization)..
✧Example
class MyClass
{
public:
// Declaration within the class
static const int _val;
// From C++17, can initialize directly
static constexpr int _cval = 100;
};
// External initialization (must, unless using constexpr + inline)
const int MyClass::_val = 100;
Differences between const in C and C++
1. Storage Type of const Variables
✧C Language: const variables default to external linkage (global const variables can be accessed by other files), and must explicitly add static to become internal linkage.
➢Example
// file1.c
// External linkage, accessible by other files
const int g_val = 10;
// file2.c
// Can access g_val from file1.c after declaration
extern const int g_val;
✧C++: Global const variables default to internal linkage (visible only in the current file), similar to the behavior of static const in C.
2. const Used to Define Array Length
✧C Language: Before C99, const variables could not be used to initialize array lengths (C99 introduced variable-length arrays (VLA) which can be used for local arrays).
➢Example:
const int n = 5;
// Supported in C99 and later (variable-length arrays), not supported in C89
int arr[n];
✧C++: If the const variable is a compile-time constant (e.g., const int n = 5), it can be used directly as an array length.
3. Implicit Conversion of const with Pointers
✧C Language: Allows implicit conversion of non-const pointers to const pointers (safe), but does not allow conversion of const pointers to non-const pointers (requires explicit casting).
➢Example:
int* p = NULL;
// Correct: non-const → const (safe)
const int* cp = p;
// Requires explicit casting (C allows, but dangerous)
const int* cp2 = NULL;
int* p2 = (int*)cp2;
✧C++: Similar rules, but stricter type safety checks (more compile-time warnings).
4. const and Function Return Values
✧C Language: Modifying function return values with const (especially for value types) has limited significance, only indicating that the returned copy cannot be modified (but the copy itself will be assigned to other variables).
const int add(int a, int b)
{
return a + b;
}
// Correct: x can be modified
int x = add(2, 3);
5. Different Meanings of Modifying Variables
✧C Language: const defines a “read-only variable” rather than a “constant”, and it still occupies memory.
✧C++: The meaning is a constant rather than “read-only”. Variables modified by const may be optimized into compile-time constants, and can be forcibly converted to bypass const restrictions (possible, but not recommended).
➢Example
const int a = 10;
// Forced conversion (dangerous)
int* p = (int*)&a;
// May compile, but behavior is undefined (a's value may remain unchanged)
*p = 20;
Summary
✧The core features and best practices of const:

✧Common Misunderstandings:
➢const is not “absolutely unmodifiable”: It is possible to bypass const restrictions through pointer casting (const_cast) (this behavior is undefined, not recommended).
const int a = 10;
int* p = const_cast<int*>(&a);
// Dangerous: may compile, but behavior is undefined (a may still be 10)
*p = 20;
➢Confusing const with pointers: Remember “const is close to whom, who cannot be modified (const is on the left of *, then the content cannot be changed, on the right of *, then the pointer itself cannot be modified).”
The C language supports the const keyword, primarily used to define read-only variables and protect the data pointed to by pointers, but there are differences in storage linkage, array initialization, etc., compared to C++. Attention should be paid to compatibility with platform and standard versions (C89/C99).
By using const appropriately, the robustness and maintainability of the code can be significantly improved, allowing the compiler to become the “first line of defense” to detect potential modification errors in advance. If you like it, please give a follow!