Practical Insights on C Language: A Summary of const Usage

Scan to follow Chip Dynamics , say goodbye to “chip” congestion!

Practical Insights on C Language: A Summary of const UsagePractical Insights on C Language: A Summary of const UsageSearch WeChatPractical Insights on C Language: A Summary of const UsageChip DynamicsPractical Insights on C Language: A Summary of const Usage

After a long afternoon of coding, during debugging, I found: “Hey? I clearly didn’t touch this variable, why did its value suddenly change?!” How can we intercept such low-level bugs in advance? Don’t panic! Today we will introduce the “anti-slip artifact” in the C language—const.

What is const?

In one sentence: const is the “read-only mode switch” in C language. Variables modified by it are like being encased in bulletproof glass—you can see them, but you cannot change them. Next, let’s take a detailed look at const.

Underlying Principles of const

At a low level, the compiler places const variables in the “read-only memory page”. If you forcefully modify them (for example, by using pointers to hack), the program may crash directly.

However! Important point: const in C language is not an absolute “iron wall”. Using pointer type casting can bypass the restrictions (for example, int* hack = (int*)&const_var; *hack = 100;), but this is considered “hacking behavior” and can lead to undefined behavior (it may crash, or it may silently change without error, which is both mysterious and dangerous).

In summary: const is a gentleman’s agreement that “prevents gentlemen but not rogues”, but in 99% of normal coding scenarios, it is reliable enough.

const and Variables

const variables have a “tsundere attribute”: they must be initialized; they must have an initial value at birth, otherwise the compiler will report an error directly.

// Regular variable, can be modifiedint a = 10; // const variable, initialized successfully, stable!const int b = 20; // Error! const variable must be initialized (compiler: if you don't give an initial value, how can I protect you?)const int c;  

Why must it be initialized? Because the design logic of const is “read-only”; if there is no initial value, then this variable loses its meaning (we can’t let the user guess its value, right?).

const and Pointers

Pointers are the soul of C language and also the disaster area for const. When const and pointers are combined, four combinations will appear.

Combination 1: Pointer to const

Syntax: const int* p; or int const* p; (both forms are equivalent, just remember that const is on the left of *).

Characteristics:

  • Protects the data pointed to: the target value cannot be modified through the pointer (*p cannot be modified)

  • Does not protect the pointer itself: the pointer can point to other addresses (p can point to other addresses)

int x = 10;int y = 20;const int* p = &x; // p points to x, and cannot change the value of x*p = 30;  // Error! Cannot modify the value of x through p (the door is locked)p = &y;   // Legal! p can change its pointing (the key is changed)

Combination 2: const Pointer

Syntax: int* const p; (const is on the right of *).

Characteristics:

  • Protects the pointer itself: the pointer address cannot be changed (p cannot be modified)

  • Does not protect the data pointed to: the data content can be modified (*p can be modified)

int x = 10;int* const p = &x; // p can only point to x, cannot change its pointing*p = 30;  // Legal! Can modify the value of x (the door is not locked)p = &y;   // Error! p cannot change its pointing (the key is fixed)

Combination 3: Pointer to const const Pointer

Syntax: const int* const p; (const is on both sides of *).

Characteristics:

  • Protects the data pointed to: cannot modify the value through the pointer (*p cannot be modified)

  • Protects the pointer itself: cannot change the pointer’s pointing (p cannot be modified)

int x = 10;const int* const p = &x; // p can only point to x, and cannot change the value of x*p = 30;  // Error! The door is lockedp = &y;   // Error! The key is fixed

Summary of const and Pointers

Declaration Form

Can the pointer change?

Can the content be modified?

int* p

Yes

Yes

const int* p

Yes

No

int* const p

No

Yes

const int* const p

No

No

Tip: Remember “const is close to whom, locks whom”. If const is on the left of *, it locks the content; if on the right, it locks the pointer itself; if on both sides, it locks everything!

const and Arraysint const a[5] and const int a[5]

int const a[5] and const int a[5] are completely equivalent! They both mean: declare an array containing 5 elements, each of which is of type const int (read-only integer). The position of const does not affect the semantics—whether const is on the left or right of int, it modifies the type of the array elements (int).

int const a[5] = {1, 2, 3, 4, 5};  // Writing 1: const on the left of intconst int b[5] = {6, 7, 8, 9, 10}; // Writing 2: const on the right of int// Attempt to modify elements (will all report errors!)a[0] = 100;  // Error! a is a const int array, elements cannot be modifiedb[1] = 200;  // Error! b is the same

Regular Arrays vs. const Arrays

Regular arrays (like int d[5]) have modifiable elements, while const arrays (like int const e[5]) have “read-only” elements. A comparison table is more intuitive:

Type

Can elements be modified?

Must be initialized?

int a[5]

Yes

No

int const a[5]

No

Yes

const in Functions

Using const in functions can greatly enhance the safety and readability of the code. It acts like a protective shield for the function.

Function Parameters: Protecting Input Data from Modification

If your function does not need to modify the input parameters, you must use const to modify them! This has two benefits:

  • Preventing accidental changes: if you accidentally modify the parameter while writing code, it will directly report a compilation error;

  • Clarifying intent: it tells the caller “this function will not modify your data”, providing a sense of security.

// Regular version (dangerous! may accidentally modify the string)void print_str(char* str) {    str[0] = 'H';  // Accidentally changed the first character to H, original string is corrupted!    printf("%s", str);}// const version (safe!)void print_str(const char* str) {    // str[0] = 'H';  // Error! const parameter cannot be modified    printf("%s", str);}int main() {    char msg[] = "hello";    print_str(msg);  // Outputs hello (original string not modified)    return 0;}

Function Return Values: Preventing Users from Modifying Returned Data

If a function returns a pointer or reference, using const can prevent users from modifying the data after obtaining it.

// Assume this is a function that reads a configuration file, returning a pointer to the configuration valueconst int* get_config(const char* key) {    static int value = 100;  // Assume the value read from the file    return &value;  // Return const pointer, preventing user modification}int main() {    const int* max_users = get_config("max_users");    // *max_users = 200;  // Error! Cannot modify the content pointed to by const pointer    printf("max_users: %d", *max_users);  // Correctly outputs 100    return 0;}

Note: If the returned pointer is to a local variable, it is inherently unsafe (local variables will be destroyed), so const cannot save you here, so never do this!

Pitfall GuidePitfall 1: Array size cannot use regular const

const int N = 10;  // N is not a constant expression!int arr[N];        // C89 compilation error

Solution:

#define N 10; int arr[N];

Pitfall 2: const variable unsuitable scenarios

For example, defining array sizes, switch case values, enumeration constants, etc., these scenarios require “compile-time constants”, while const variables in C language do not count (they do in C++).

const int SIZE = 5;int arr[SIZE];  // C89 error, C99 allows (variable-length arrays)switch (x) {    case SIZE:  // Error! case label must be a constant expression        break;}

Solution:

  • Use #define to define true constants;

Pitfall 3: Forcibly modifying const variables

Although using pointer type casting can modify const variables, this leads to undefined behavior (Undefined Behavior, UB)—the compiler may crash directly, or it may silently modify without error, or even produce strange bugs elsewhere.

const int MAX = 100;int* hack = (int*)&MAX  // Forcefully type casting pointer (dangerous!) *hack = 200;             // Undefined behavior! May crash, or may modify successfully printf("%d", MAX);     // May output 100 (compiler optimization), or may output 200 (mysterious)

In summary: never attempt to modify const variables, this is a red line in C language!

Conclusion

const may seem simple, but it is one of the most practical “bug prevention tools” in C language. However, please remember the following points:

  1. const variables must be initialized;

  2. Use const to protect function parameters and return values that do not need modification;

  3. Avoid the three major pitfalls of array sizes, constant expressions, and forced modifications.

Writing code is not just about completing it, but about writing it correctly, stably, and in a way that reassures others. const is not mandatory, but it can upgrade your code from usable to reliable. Next time you write code, remember to put a const seal on your variables and add a protective shield to your function parameters and return values. When you debug late at night and no longer crash due to variable changes, and when your submitted code is praised by colleagues for its stability—you will thank yourself for carefully reading this article today.

Practical Insights on C Language: A Summary of const Usage

If you find this article helpful, click Like”, Share”, Recommend”!

Leave a Comment