和指针联用有佷微妙的地方,之前一直佷晕,现在来继续研究下。诸如以下:
1 | int const; |
与宏定义的区别
宏定义 #define | const 常量 |
---|---|
宏定义,相当于字符替换 | 常量声明 |
预处理器处理 | 编译器处理 |
无类型安全检查 | 有类型安全检查 |
不分配内存 | 要分配内存 |
存储在代码段 | 存储在数据段 |
可通过 #undef 取消 | 不可取消 |
功能
const
是一种处理符号常量的方法,以 const
声明的变量,一般首字母大写,声明之后无法被修改。相比于 define
,const
会显式的指定类型。
- 修饰变量,说明该变量不可以被改变;
- 修饰指针,分为指向常量的指针(pointer to const)和自身是常量的指针(常量指针,const pointer);
- 修饰引用,指向常量的引用(reference to const),用于形参类型,即避免了拷贝,又避免了函数对值的修改;
- 修饰成员函数,说明该成员函数内不能修改成员变量。
第 1,3,4 条容易理解,主要是第二条。看一个简单的例子:
1 | char greeting[] = "Hello"; |
具体解读
const默认作用于其左边的东西。左边没东西的情况下,作用于其右边的东西。1
简单的修饰指针:
const int* p
,只有右边有东西,修饰的为int
,所以数值不能被修改。在与*
结合,意思是*p
不能被修改,其它的都可以。即不可通过该指针改变其指向的内容,但可改变指针本身所指向的地址。int const* p
,先作用于左侧的int
为int const
,在叠加上右侧的*
,所以修饰的为int* p
,所以,*p
不能被修改,其它的都可以。即不可通过该指针改变其指向的内容,但可改变指针本身所指向的地址。也就是,和上面的是一样的。int* const p
,左边是*
,所以const
作用于指针,指向一个int
变量。即不可以修改p
,但可以修改*p
,即不可改变指向的地址。
中等难度的修饰指针:
const int* const p
,对于第一个const
,左边没东西,修饰右边的int
,指向的值不能修改;对于第二个const
修饰*
,指针不能修改。即不可改变指针本身所指向的地址,也不可通过指针改变其指向的内容。同int const* const p
。
如何分析满天飞的 const
指针:
int const* const* p
,第一个const
修饰int
,第二个const
修饰第一个*
,也就是,指向const int* const
的指针,最后一个*
没有被修饰,因此可以指向同类型的其它变量。int const* const* const
就不可以了。- 之后再出现此类情况,也可以慢慢分析满天飞的
const
和指针。
一些例子
为了更好的理解上述内容,这里来举一些例子。常见的一般有两种选择:
- 常指针指向一个变量,防止修改指针修改变量值
- 常指针指向一个常量
- 非常指针指向常量(错误)
先看第一种情况:解引用只是取出指向内存区域的值,因此指向内存区域的值是可以直接修改的,但不能通过指针修改。
1 |
|
对于第二种情况:不能修改变量,也不能修改常量。
1 |
|
对于第三种情况:修改指针来修改常量会显得佷荒谬,因此编译会直接报错:
1 |
|
二级指针
之前说到,常指针可以指向变量,但是涉及二级指针后,情况又会发生逆转。
1 |
|
如果上述代码通过,那么完全可以通过 p2
指针修改常量。因此我们可以得到以下结论:
- 如果数据类型是指针,非
const
数据的地址只能赋值给非const
指针,如二级指针中,p1 = &p2
是错误的。 - 若数据类型本身不是指针,可以将
const
数据或非const
数据的地址赋给指向const
的指针,但指针可以修改,指向别的值。因此,const
修饰的数组不能传参给非常量指针。
references
- 1.https://www.zhihu.com/question/443195492 ↩