C 语言中const与指针:三种常见写法辨析

摘要: const int *pint const *p 含义相同,表示「通过指针不能修改所指对象」;int * const p 表示「指针本身不可再指向别处」。本文用经典与拓展示例说明差异,并给出工程实践建议。

关键词: C 语言、const、指针、只读视图、常量指针

一、核心结论(速查)

写法 一句话含义
const int *grape 指向只读 int 的指针 :不能通过 grape 修改那个 int,但 grape 可以指向别的地址。
int const *grape 与上一行完全相同 ,仅 const 与类型名的书写顺序不同。
int * const grape_jelly 常量指针,指向可改 intgrape_jelly 不能再指向别处,但可以通过它修改指向的 int

记忆口诀(看 *const 的相对位置):

  • const* 左边 → 数据只读;const* 右边 → 指针只读

二、const int *int const *(等价)

2.1 语义

指针的类型是「指向 const int」,即 通过该指针不能修改所指内存中的 int

这不代表「内存里一定是常量」------对象本身可能是普通变量,只是 当前这个指针通道不允许写

2.2 经典例子:只读函数参数

标准库中大量接口用此约定表达「只读缓冲区」:

c 复制代码
size_t strlen(const char *s);  /* 实现中承诺不通过 s 修改字符串 */

void print_values(const int *p, size_t n)
{
    size_t i = 0;

    for (i = 0; i < n; i++) {
        printf("%d ", p[i]);   /* 可以读 */
        /* p[i] = 0; */         /* 编译错误:不能通过 p 写 */
    }
}

2.3 经典例子:指针可改指向,不可改目标

c 复制代码
void example_read_only_view(void)
{
    int a = 1;
    int b = 2;
    const int *grape = &a;

    /* *grape = 10; */   /* 错误:不能通过 grape 修改所指 int */
    grape = &b;          /* 正确:grape 本身不是 const 指针,可以改指向 */
}

2.4 拓展:const int * 指向非 const 变量

c 复制代码
void example_alias_read_only(void)
{
    int x = 5;
    const int *p = &x;   /* 合法:用「只读视图」观察 x */

    /* *p = 1; */        /* 错误:不能通过 p 写 */
    x = 1;               /* 合法:仍可直接改 x(不经过 p) */
}

2.5 拓展:两种写法等价

c 复制代码
const int *p1;
int const *p2;   /* 与 p1 类型相同 */

团队可统一一种风格(例如始终写 const int *),避免无谓争论。

三、int * const(常量指针)

3.1 语义

指针变量本身是常量 :定义后不能再让该指针指向别的地址(必须在定义时给出合法初值,除非在特殊上下文如函数参数中另有规则)。
仍可通过该指针修改所指的 int

3.2 经典例子:固定指向某缓冲区

c 复制代码
void example_const_pointer(void)
{
    int buffer[4] = {1, 2, 3, 4};
    int * const grape_jelly = buffer;  /* 始终指向 buffer 首元素 */

    grape_jelly[0] = 99;   /* 正确:修改的是 int 对象 */
    *grape_jelly = 100;    /* 同上 */

    /* grape_jelly++; */              /* 错误:不能移动指针 */
    /* grape_jelly = &buffer[1]; */   /* 错误:不能改指针的值 */
}

3.3 经典例子:函数内锁定指针形参(实现细节)

c 复制代码
void bump_first(int * const p)
{
    if (p == NULL) {
        return;
    }
    (*p)++;            /* 可以修改指向的 int */
    /* p++; */         /* 错误:不能修改 p 本身 */
}

3.4 拓展:与数组名的类比

在多数表达式中,数组名会退化为指向首元素的指针,但数组名不是可赋值的左值:

c 复制代码
void example_array_name(void)
{
    int arr[3] = {0, 0, 0};

    /* arr = NULL; */   /* 错误:不能对数组名整体赋值 */
}

思路上与「指针不可改指向」有相似之处,但数组名与 int * const 在标准中的规则并不完全相同,类比有助于直觉理解。

四、三种组合对照表

声明 能否改指针指向的地址 能否通过指针改所指 int
const int *p 不能
int * const p 不能
const int * const p 不能 不能

拓展:const int * const

c 复制代码
void example_both_const(void)
{
    const int x = 42;
    const int * const grape = &x;

    /* grape = &x; */     /* 错误:指针常量 */
    /* *grape = 0; */     /* 错误:指向 const int */
}

五、如何读复杂声明

  1. 螺旋法则 / 先右后左 :从标识符出发,向右读,遇到 ) 或边界再向左读,交替进行。
  2. 简化规则const 默认修饰其左侧紧邻的类型;若左侧没有可修饰成分,则修饰右侧。

掌握后可以继续分析 const int **int * const * 等多级指针,原则是 逐层、逐个 const* 分析

相关推荐
ZK_H2 小时前
嵌入式c语言——关键字其6
c语言·开发语言·计算机网络·面试·职场和发展
ambition202423 小时前
从暴力搜索到理论最优:一道任务调度问题的完整算法演进历程
c语言·数据结构·c++·算法·贪心算法·深度优先
cmpxr_3 小时前
【C】原码和补码以及环形坐标取模算法
c语言·开发语言·算法
yashuk3 小时前
C语言实现PAT练习及算法学习笔记,还有SQLite介绍
c语言·sqlite·开源项目·算法学习·pat练习
ACP广源盛139246256734 小时前
破局 Type‑C 切换器痛点@ACP#GSV6155+LH3828/GSV2221+LH3828 黄金方案
c语言·开发语言·网络·人工智能·嵌入式硬件·计算机外设·电脑
爱编码的小八嘎4 小时前
C语言完美演绎7-10
c语言
hhh3u3u3u6 小时前
Visual C++ 6.0中文版安装包下载教程及win11安装教程
java·c语言·开发语言·c++·python·c#·vc-1
泛凡(Linyongui)6 小时前
PY32F002B实践之二--宠物腹背理疗仪项目介绍及头文件解析
c语言·keil·py32·32位单片机·腹背理疗仪项目实践
网域小星球9 小时前
C 语言从 0 入门(十四)|文件操作:读写文本、保存数据持久化
c语言·开发语言·文件操作·fopen·fprintf