• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

SOC/IP验证工程师

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

const int *ptr,int *const ptr和int const *ptr的区别

C语言中const与指针的三种形式深度解析

在C语言中,const关键字与指针的组合使用是理解指针和常量概念的关键,也是面试和实际开发中的常见考点。下面详细解析三种形式的区别:

graph TD A[const与指针组合] --> B[const int *ptr] A --> C[int *const ptr] A --> D[const int *const ptr] B --> E[指针指向的内容不可变] C --> F[指针本身不可变] D --> G[指针和内容都不可变]

1. const int *ptr(指向常量的指针)

本质:

  • 指针指向的内容不可变
  • 指针本身可以改变指向

示例:

int value = 10;
const int *ptr = &value;  // 指向整型常量的指针

// *ptr = 20;   // 错误:不能通过ptr修改内容
value = 20;     // 正确:原始变量可变
printf("%d", *ptr); // 输出20

int another = 30;
ptr = &another; // 正确:指针可以指向新地址
// *ptr = 40;   // 错误:仍不能修改内容

等价形式:

int const *ptr; // 与const int *ptr完全相同

应用场景:

// 函数参数保护原始数据
void print_data(const int *data, size_t size) {
    for(size_t i=0; i<size; i++) {
        // data[i] = 0; // 禁止修改
        printf("%d ", data[i]);
    }
}

int arr[] = {1,2,3};
print_data(arr, 3); // 安全传递数组

2. int *const ptr(常量指针)

本质:

  • 指针本身不可变
  • 指针指向的内容可以改变

示例:

int a = 5, b = 10;
int *const ptr = &a; // ptr是常量指针

*ptr = 15;     // 正确:可以修改指向的值
printf("%d", a); // 输出15

// ptr = &b;   // 错误:不能改变指针指向

应用场景:

// 硬件寄存器映射
#define STATUS_REG ((volatile int *const)0x40001000)

void check_status() {
    if(*STATUS_REG & 0x01) {
        printf("Ready");
    }
    // STATUS_REG = (int*)0x...; // 禁止修改指针
}

// 固定缓冲区处理
char buffer[1024];
char *const fixed_ptr = buffer;

process_data(fixed_ptr); // 保证始终处理同一缓冲区

3. const int *const ptr(指向常量的常量指针)

本质:

  • 指针本身不可变
  • 指针指向的内容也不可变

示例:

const int value = 100;
const int *const ptr = &value; // 双重const

// *ptr = 200; // 错误:不能修改内容
// ptr = NULL; // 错误:不能修改指针

const int another = 200;
// ptr = &another; // 错误:指针不可变

应用场景:

// 只读配置表(存储在ROM中)
const struct Config {
    int version;
    char model[20];
} device_config = {2, "AX-100"};

const struct Config *const config_ptr = &device_config;

// 系统常量定义
const char *const OS_NAME = "Embedded Linux";
// OS_NAME[0] = 'e'; // 错误
// OS_NAME = "Unix";  // 错误

对比总结表

特性 const int *ptr int *const ptr const int *const ptr
指针是否可变 可以改变指向 不可改变指向 不可改变指向
内容是否可变 不可通过指针修改 可通过指针修改 不可通过指针修改
初始化要求 无需立即初始化 必须初始化 必须初始化
常见用途 函数参数保护 固定地址访问 只读全局常量
内存保护级别 内容保护 指针保护 双重保护
能否指向非常量 可以 可以 可以
能否指向常量 可以(推荐) 危险(需强制转换) 可以(推荐)

记忆技巧

1. "左定值,右定向"规则

  • const在*左边 → 指向的内容不可变
  • const在*右边 → 指针本身不可变
  • const在*两边 → 都不可变
const int *p;   // const在左 → 内容不可变
int const *p;   // const在左 → 内容不可变(同上)
int *const p;   // const在右 → 指针不可变
const int *const p; // 两边都有 → 都不可变

2. 英文读法理解

  • const int *ptr → "pointer to constant int"
  • int *const ptr → "constant pointer to int"
  • const int *const ptr → "constant pointer to constant int"

重要注意事项

1. 类型转换风险

const int value = 100;
int *ptr = (int*)&value; // 强制转换去除const
*ptr = 200; // 未定义行为!可能导致崩溃

printf("%d vs %d", value, *ptr); 
// 可能输出:100 vs 200(编译器优化)

2. 函数返回值的const

// 返回指向常量的指针
const char *get_version() {
    static const char ver[] = "V1.2.3";
    return ver;
}

// 调用
const char *v = get_version();
// v[0] = 'X'; // 错误

3. 多级指针中的const

const int **pptr;    // 指向指针的指针,该指针指向常量
int *const *pptr;    // 指向常量指针的指针
int **const pptr;    // 常量指针,指向指针的指针

实际应用案例

案例1:安全字符串处理

size_t safe_strlen(const char *str) {
    const char *p = str; // 指向常量的指针
    while(*p) p++;
    return p - str;
}

char msg[] = "Hello";
// 保护原始字符串不被修改
size_t len = safe_strlen(msg); 

案例2:硬件寄存器访问

// 只写寄存器(指针可变,内容可写)
volatile uint32_t *const TX_REG = (uint32_t*)0x4000C000;

// 只读寄存器(指针可变,内容只读)
volatile const uint32_t *RX_REG = (uint32_t*)0x4000C004;

void send_data(uint32_t data) {
    *TX_REG = data; // 写入寄存器
}

uint32_t receive_data() {
    return *RX_REG; // 读取寄存器
}

案例3:配置管理系统

typedef struct {
    const char *const name; // 不可变的字符串指针
    const int id;           // 不可变的ID
    int value;              // 可变的数值
} ConfigItem;

// 配置表(双重const保护)
const ConfigItem *const config_table[] = {
    &(ConfigItem){"Timeout", 101, 30},
    &(ConfigItem){"Retries", 102, 3},
    NULL
};

void print_config() {
    for(const ConfigItem *const *p = config_table; *p; p++) {
        // (*p)->name = "New"; // 错误
        // (*p)->id = 200;     // 错误
        (*p)->value = 40;    // 允许修改值
        printf("%s: %d\n", (*p)->name, (*p)->value);
    }
}

总结

理解三种const指针形式的关键:

  1. const int *ptr - 保护指向的数据
  2. int *const ptr - 保护指针本身
  3. const int *const ptr - 双重保护

正确使用const指针可以:

  • 提高代码安全性
  • 增强代码可读性
  • 帮助编译器优化
  • 明确接口契约
  • 保护硬件寄存器

掌握这些区别是成为专业C程序员的重要一步,尤其在系统编程、嵌入式开发和安全性要求高的场景中至关重要。

posted on 2025-06-23 22:55  SOC验证工程师  阅读(72)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3