const关键字在C语言中到底有何特殊作用?

99ANYc3cd6
预计阅读时长 17 分钟
位置: 首页 C语言 正文

const 是 C 语言中的一个关键字,它的全称是 "constant"(常量),它的核心作用是限定一个变量为只读,即告诉编译器,这个变量的值在初始化之后就不能再被修改了。

c语言 const 关键字
(图片来源网络,侵删)

这听起来简单,但 const 在 C 语言中的用法非常灵活,也常常是初学者的难点,下面我们从浅入深,结合实例来彻底搞懂它。


const 的基本用法:修饰普通变量

这是最常见、最直观的用法。

const int a = 10;
// 或者
int const a = 10;

这两种写法是完全等价的,都表示 a 是一个整型常量,一旦初始化后,任何试图修改 a 的行为都会导致编译错误。

const int a = 10;
a = 20; // 错误!编译器会报错:assignment of read-only variable 'a'

关键点:

c语言 const 关键字
(图片来源网络,侵删)
  • const 修饰的变量不是常量,而是一个“只读变量”。
  • 它的值在编译时并不一定是已知的(比如通过函数初始化),但它一旦被赋值,就不能再改变。
  • const 变量仍然有自己的存储空间,它不是一个纯粹的文本替换(不像 C++ 中的 const 或 C 中的 #define)。

const 与指针:最复杂的部分

const 和指针结合时,情况就变得复杂了。const 的位置不同,其修饰的对象也不同,主要有以下四种情况:

const 修饰指针指向的数据(最常用)

const int *ptr;
// 或者
int const *ptr;
  • 含义ptr 是一个指向整型常量的指针。
  • 限制:不能通过 ptr 来修改它所指向的值。ptr 本身可以指向其他内存地址。
  • 例子
int a = 10;
int b = 20;
const int *ptr = &a; // ptr 指向 a
*ptr = 30; // 错误!不能通过 ptr 修改 a 的值,因为 a 在 ptr 看来是只读的。
ptr = &b; // 正确!ptr 可以指向 b,因为它本身不是 const

const 修饰指针本身(不常用)

int * const ptr = &a;
  • 含义ptr 是一个本身是常量的指针。
  • 限制ptr 必须在声明时初始化,之后不能再指向其他地址,可以通过 ptr 来修改它所指向的值。
  • 例子
int a = 10;
int b = 20;
int * const ptr = &a; // ptr 必须初始化
ptr = &b; // 错误!ptr 本身是 const,不能再指向别处
*ptr = 30; // 正确!可以通过 ptr 修改 a 的值

const 同时修饰指针本身和它指向的数据

const int * const ptr = &a;
  • 含义ptr 是一个指向整型常量的、本身也是常量的指针。
  • 限制ptr 本身不能改变指向,也不能通过 ptr 修改它所指向的值,这是一个“只读”的指针。
  • 例子
int a = 10;
int b = 20;
const int * const ptr = &a;
ptr = &b; // 错误!ptr 本身不能改变
*ptr = 30; // 错误!不能通过 ptr 修改 a 的值

指针指向 const 数据

int a = 10;
const int ca = 20;
int *ptr = &ca; // 错误!不能将 const int* 的地址赋给 int*,这会绕过 const 的限制
  • 含义:这是一个安全规则,C 语言禁止将一个 const 对象的地址赋给一个非 const 的指针。
  • 原因:如果允许这样做,你就可以通过这个非 const 指针去修改 const 对象的值,这就破坏了 const 的初衷,带来了安全隐患。
  • 如何解决? 如果确实需要用一个指针去操作一个 const 变量,应该使用第一种情况的指针。
const int ca = 20;
const int *ptr = &ca; // 正确

const 与函数参数

将函数参数声明为 const 是一种非常好的编程实践,主要有两个好处:

  1. 防止函数内部意外修改参数的值
  2. 允许传入 const 变量作为实参,扩大了函数的适用范围。
// 一个函数,用于打印一个整数数组
void print_array(const int *arr, int size) {
    // arr 是一个指向 const int 的指针
    // 这保证了在 print_array 函数内部,我们不会意外地修改数组内容
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
        // arr[i] = 0; // 错误!不能修改
    }
    printf("\n");
}
int main() {
    int my_array[] = {1, 2, 3, 4, 5};
    const int const_array[] = {10, 20, 30};
    print_array(my_array, 5);     // 正常,传入普通数组
    print_array(const_array, 3);  // 正常,传入 const 数组
    // print_array 的参数不是 const int*,那么调用 print_array(const_array, 3) 就会编译错误
}

const 与函数返回值

将函数的返回值声明为 const,可以防止返回值被意外修改。

const int get_max(int a, int b) {
    return (a > b) ? a : b;
}
int main() {
    // 假设 get_max 返回一个很大的值,我们想用它作为某个数组的索引
    const int max_val = get_max(100, 200);
    // max_val = 150; // 错误!max_val 是 const
    // 如果函数返回的是一个非常量对象,例如一个结构体
    // const struct MyStruct s = get_struct();
    // 这样可以防止 s 被意外修改。
}

const 与全局/静态变量

const 用于全局或静态变量时,它意味着这个变量的作用域仅限于当前文件(内部链接),并且其值不能被修改。

c语言 const 关键字
(图片来源网络,侵删)
// file1.c
const int global_const = 100;
// file2.c
extern int global_const; // 如果这样声明,链接时会报错,因为类型不匹配
// 正确的 extern 声明应该是:
extern const int global_const;
// 任何试图修改 global_const 的代码都会编译错误

注意:全局 const 变量和全局 #define 宏有本质区别:

  • const int GLOB = 10;:有存储空间,类型安全,有作用域。
  • #define GLOB 10:简单的文本替换,无类型,无作用域。

const#define 的区别

特性 const 变量 #define
类型 有类型,编译器会进行类型检查 无类型,只是简单的文本替换
作用域 有作用域(由 或文件决定) 无作用域,从定义处到文件末尾都有效
存储 通常分配存储空间(除非是优化掉的只读变量) 不分配存储空间,只是替换
调试 在调试器中可见,可以查看其值 在预处理阶段被替换,调试器中不可见
安全性 类型安全 不安全,可能产生意想不到的替换结果

在 C 语言中,优先使用 const,而不是 #define 来定义常量,除非你需要做一些 const 无法做到的事情(比如定义宏函数)。


const 的进阶:C++ 中的 const 与 C 语言的对比

重要提示:C 语言中的 const 和 C++ 中的 const 是有区别的!很多 C++ 程序员会混淆这一点。

C++ 中,const 变量更接近于真正的“常量”,编译器可能会将 const 变量直接替换成其值(类似 #define),const 变量可以用于定义数组大小等需要编译时常量的地方。

// C++ 代码
const int SIZE = 100;
int arr[SIZE]; // 合法,因为 SIZE 是编译时常量

C 语言 中,const 变量不一定是编译时常量,它只是一个只读变量,你不能用它来定义数组大小。

// C 语言代码
const int SIZE = 100;
int arr[SIZE]; // 错误!C 语言要求数组大小必须是编译时常量,而 const int 不是

在 C 语言中,如果想要一个编译时常量,应该使用 enum#define

// C 语言中的正确做法
#define SIZE 100
int arr[SIZE];
// 或者使用 enum
enum { SIZE = 100 };
int arr[SIZE];

const 位置 含义 示例
const int a; a 是一个只读的整型变量 a = 10; (ok), a = 20; (error)
const int *ptr; ptr 是一个指向只读整型的指针 *ptr = 10; (error), ptr = &b; (ok)
int * const ptr; ptr 是一个本身只读的指针 *ptr = 10; (ok), ptr = &b; (error)
const int * const ptr; ptr 是一个指向只读整型的、本身也只读的指针 *ptr = 10; (error), ptr = &b; (error)

掌握 const 是写出健壮、安全、可读性高的 C 代码的重要一步,记住它的核心思想:“承诺不修改”,通过 const,你可以向编译器和代码的阅读者清晰地表达你的意图。

-- 展开阅读全文 --
头像
scanf返回值究竟该怎么用?
« 上一篇 03-15
织梦文章属性字母简写有何规律或作用?
下一篇 » 03-15

相关文章

取消
微信二维码
支付宝二维码

目录[+]