const int * p (或 int const* p) 和 int * const p以及const int * const p(或int const * const p)区别
一、何为const
const修饰变量只是让变量变为“只读”,这里的“只读”其实就是只读变量,本质上还是在内存中开辟一个地方来存放它的值,不过由于其特性,我们一般称之为常量。
- 例如const 修饰局部变量,则是在栈空间上开辟内存
- const 修饰全局变量或静态变量(局部或全局),则在静态区开辟内存。
你会发现,const修饰的变量和普通的变量在内存上的分配没什么区别
只不过这个“只读变量”的值,由编译器限定或保护不允许被修改。对于不同的编译器版本而言有不同手段
。
对于老式的c标准编译器(这个版本的语言经常被称作"ANSI C",或有时称为"C89"(为了区别C99))
而言,做的事情很简单。只是在编译的时候检查该变量除首次定义外,在使用时是否作为左值,不做左值就不会被赋值,不被赋值就不会被修改。并不是将该变量存储于常量区,其根本就不是个常量,本质上来讲就是个变量,编译器不过是在编译的时候保证其不被赋值即可。
但是,运行时依旧可以通过指针获取改只读变量的地址,并修改只读变量的值。
因此,现在编译器gcc做了改进
,不仅在编译的时候做检查,在运行时也做了限制 ,比如,使用指针间接修改只读变量的值,编译时可以通过检查,但是运行时会出现段错误导致崩溃。
二、 const int * p (或 int const* p)
1、const int * p (或 int const* p)
读者会发现,这里使用的是“或”,之所以使用的是或,是因为这二者没差别,即等价
const int XXX
,const
和int
不管谁先谁后,都是在修饰XXX
因此这里const修饰的是* p
,指针指向的变量具有了“只读”属性。
const int* p=&a; //指针指向的变量具有了“只读”属性
eg:
#define CONFIG_DEBUG
int a, b;
const int * p = &a; //指针p指向的变量具有了“只读”属性
p = &b; //操作成功
#ifdef CONFIG_DEBUG
*p = 666; //操作失败,指向的地址中的内容不可更改
#endif
2、int * const p
const修饰的是p
,
此时这个指针变量就成为了一个只读指针变量,即指针只能唯一的指向一个地址,但是这个地址所对应的内存单元中的内容可以被修改
int* const p = &a; //只读指针变量
eg:
//如果不想要看到错误信息的话,注释掉#define CONFIG_DEBUG这句
#define CONFIG_DEBUG
int a, b;
int * const p = &a; // 定义了一个只能指向a的地址的指针
*p = 666; //操作成功
#ifdef CONFIG_DEBUG
p = &b; //操作失败,只读指针变量的内容,即指向的地址不可更改
#endif
3、const int * const p(或int const * const p)
const int * const p = &a;
#include <stdio.h>
#define CONFIG_DEBUG
int main()
{
int a = 1;
int b = 100;
const int * const p = &a;
printf("a = %d\n", *p);
#ifdef CONFIG_DEBUG
*p = 101;
p = &b;
#endif
}
const.c:12:5: error: assignment of read-only location ‘*p’
*p = 101;
^
const.c:13:4: error: assignment of read-only variable ‘p’
p = &b;
^
根据报错信息可以发现,
- 指针p指向的变量具有了“只读”属性。
- 只读指针变量的内容,即指向的地址不可修改。
本文参考了 https://blog.csdn.net/weibo_dm/article/details/80445205