当前位置: 首页 > article >正文

【C语言】指针常量和常量指针

在C语言中,指针常量和常量指针是两个不同的概念:

指针常量(Constant Pointer)

定义:指针本身是常量,不能指向其他地址,但指针所指向的内容可以改变。
语法:type *const ptr

// 该指针是一个常量,int * const p = &y; // 不能使用 p=
int value = 10;
int anotherValue = 20;
int *const ptr = &value;  // 指针指向的地址不可变
						  // const 修饰 ptr,不能使用 ptr= 的方式修改值

*ptr = 15;  // 可以改变指针指向的值
// ptr = &anotherValue;  // 错误:不能改变指针的指向

常量指针(Pointer to Constant)

定义:指针指向的内容是常量,不能通过该指针修改内容,但指针本身可以指向其他地址。
语法:const type *ptrtype const *ptr

// 常量指针是一个指针,是一个指向常量的指针  const int *p // 不能使用 *p
int value = 10;
const int *ptr = &value;  // 指针指向的内容不可变
						  // const 修饰 *ptr,不能使用 *ptr = 的方式改变值

// *ptr = 15;  // 错误:不能通过指针修改指向的值
int anotherValue = 20;
ptr = &anotherValue;  // 可以改变指针的指向

二者的区别

  • 指针常量:指针的指向不可变,内容可变。
  • 常量指针:指针指向的内容不可变,指向可变。

指针常量和常量指针在内存中的存储方式主要区别在于对其内容或指向的限制, 而不是存储方式本身。两者都是指针,存储方式相同,但使用限制不同。

指针常量(Constant Pointer):

  • 存储:存储一个内存地址。
  • 限制:指针本身的地址不变,指向的内容可变。

常量指针(Pointer to Constant):

  • 存储:同样存储一个内存地址。
  • 限制:指针可以改变指向的地址,但不能通过指针修改指向的内容。

内存存储:

  • 存储位置: 指针变量本身存储在栈或静态区域中,指向的数据根据数据类型和分配方式可能存储在栈、堆或静态区域。
  • 大小: 指针的大小通常是固定的,取决于系统架构(如32位系统上为4字节,64位系统上为8字节)。

通过这两种指针的使用限制,可以控制数据的可变性,而不是影响其在内存中的物理存储方式。


指针常量和常量指针在实际编程中的应用示例:

指针常量的应用场景:

  • 用于需要固定指向某个变量的指针, 例如在函数内使用一个固定的缓冲区。
#include <stdio.h>

void modifyBuffer(char *const buffer) {
    // 可以修改缓冲区的内容
    buffer[0] = 'H';
    buffer[1] = 'i';

    // 不能将指针指向其他地址
    // buffer = anotherBuffer; // 错误
}

int main() {
    char buffer[10] = "Hello";
    modifyBuffer(buffer);
    printf("Buffer: %s\n", buffer);  // 输出: Hi
    return 0;
}

常量指针的应用场景:

  • 用于传递只读数据的指针,防止函数修改数据内容。
#include <stdio.h>

void printMessage(const char *message) {
    // 可以读取字符串
    printf("Message: %s\n", message);

    // 不能修改字符串内容
    // message[0] = 'h'; // 错误
}

int main() {
    const char *msg = "Hello, World!";
    printMessage(msg);
    return 0;
}

还有一些场景可以用到指针常量和常量指针:

  • 指针常量:
    • 固定资源管理: 指向固定的资源(如设备寄存器、配置结构),确保指向不变。
    • 多线程编程: 当多个线程访问同一共享资源时,使用指针常量保证指针本身不被修改。
  • 常量指针:
    • 函数参数保护: 用于函数参数,确保函数不会修改传入的数据(如配置数据、静态字符串)。
    • 只读缓存: 当指向的数据是缓存或预加载的数据,需要只读访问以提高安全性。
    • 接口设计: 在设计API时,使用常量指针可以明确传入的数据不会被修改,提高接口的可靠性。

在这些用法帮助确保数据的安全性和代码的稳定性,特别是在复杂或多线程的应用程序中。举个例子:

// 这是一个指针常量在多线程编程中的应用示例(下列使用方式在多线程编程中可以帮助确保数据结构的一致性和可靠性):
// 指针常量:SharedResource *const resource 确保线程函数中指针 resource 的地址不变。
// 共享资源:线程安全地访问共享数据 resource->data,避免指针被误修改导致的错误。

#include <stdio.h>
#include <pthread.h>

#define NUM_THREADS 2

// 共享数据
typedef struct {
    int data;
} SharedResource;

// 线程函数
void* threadFunction(void* arg) {
    SharedResource *const resource = (SharedResource *const)arg;  // 指针常量

    // 访问共享资源
    printf("Thread %ld accessing data: %d\n", pthread_self(), resource->data);

    // 确保指针不被改变
    // resource = NULL;  // 错误:不能改变指针的指向

    return NULL;
}

int main() {
    pthread_t threads[NUM_THREADS];
    SharedResource resource = {42};  // 初始化共享资源

    // 创建线程
    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_create(&threads[i], NULL, threadFunction, (void*)&resource);
    }

    // 等待线程完成
    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }

    return 0;
}

在多线程编程中,指针常量可以用于确保多个线程访问同一个共享资源时,指针本身的地址不被改变。这种用法在需要访问固定数据结构或配置的场景中尤为重要。

总之,只需要记住:

  • 指针常量:保证指针始终指向同一地址。
  • 常量指针:保护指向的数据不被修改。

就可以咯。

以上。

我是一个十分热爱技术的程序员,希望这篇文章能够对您有帮助,也希望认识更多热爱程序开发的小伙伴。
感谢!


http://www.kler.cn/a/404501.html

相关文章:

  • 国标GB28181视频平台EasyCVR视频融合平台H.265/H.264转码业务流程
  • 如何在Word文件中设置水印以及如何禁止修改水印
  • 一次需升级系统的wxpython安装(macOS M1)
  • Spring Cloud Alibaba、Spring Cloud 与 Spring Boot各版本的对应关系
  • MVC 模型:架构与原理
  • OpenMMlab导出Mask R-CNN模型并用onnxruntime和tensorrt推理
  • 从0开始机器学习--Day29--K-means算法以及PCA降维作业
  • 【Linux网络】自定义应用层协议 (序列化)
  • ATmaga8单片机Pt100温度计源程序+Proteus仿真设计
  • C/C++ 中的类型转换方式
  • 基于Qt/C++/Opencv实现的一个视频中二维码解析软件
  • Flutter在MaterialApp中的builder初始化多个包
  • Linux环境下的基础开发工具 -- 包管理器,vim,gcc/g++,make/makefile,git,gdb/cgdb
  • EcoVadis审核是什么?EcoVadis审核流程包括什么?
  • STM32H7开发笔记(2)——H7外设之多路定时器中断
  • 实验室管理解决方案:Spring Boot技术
  • 网络安全等级保护五个保护等级
  • 经验笔记:git checkout 与 git switch
  • 【智谱开放平台-注册_登录安全分析报告】
  • 单体架构和微服务架构到底哪个好?
  • 怎么编译OpenWrt镜像?-基于Widora开发板
  • Linux驱动编程 - kmalloc、vmalloc区别
  • 多线程中Callable和Runnable的对比
  • 力扣 LeetCode 106. 从中序与后序遍历序列构造二叉树(Day9:二叉树)
  • MySQL45讲 第二十八讲 读写分离有哪些坑?——阅读总结
  • 第 24 章 -Golang 性能优化