常量指针和指针常量
令人痛苦的概念
-
C语言中有些概念的区分实在让人非常痛苦,即使是学了很长时间的C语言,也可能还没弄清楚这些概念,比如今天要讲的指针常量和常量指针,还有指针数组和数组指针。。。,我查了好多博客论坛,也没有发现有一个统一的解释,有的说是从左往右哪个在前就先读哪个,也有的说是从右往左读…,实在是让人很晕。现在我们就来理一理指针常量和常量指针这两个概念,看看是否能搞清它们之间的修饰关系。
-
常量指针:先说说常量指针,如果按照从左往右,谁在前先读谁的说法,应该是这样的声明,以
int
型为例:
const int *p1;
按C语言的语法,这应该是一个指向常量的指针(可能因为这个原因,我们给它起名叫常量指针),本身可以变化,其本质是个指针变量:
const int a = 10;
const int *p1 = &a;
/* 也可以像下面这样, 先声明再定义
const int *p1;
p1 = &a;
*/
*p1 = 20; // 不合法,*p==a,a是const, 不能变
int b = 20;
p1 = &b; // 可以,虽然a不能变,但p可以不指向a,指别的地方
现在来分析一下修饰结构,我们遇到一个名词时要理解它,就是按照修饰结构来理解的。按照中文的习惯,常量用于修饰指针,也就是常量型的指针,即这本质是个指针,但这个指针是个常量的,比如一个地址0x0000fef5,这是指针的值,这个值是不能变的,但0x0000fef5这个地址上存放的数据可以变,可以是1,也可以是2 …,这就与上面的定义矛盾了,上面说的是指向的内容是个不能变的常量,但它可以不指向那里,再指其他地方。如果我们要将它理解成 一个常量的指针,即指向一个常量型的指针, 这就对了,到底怎么理解呢?难道我们遇到一个词,还要分析一下可能出现的修饰情况吗?
- 指针常量:下面再讲讲指针常量,还是按照从左往右的顺序,这样声明:
int *const p2;
不看名称,仅按C语言的语法,p2
本身是个常量,是不可变的,永远指向一个地方(假设为0x0000fe58),在声明的同时必须要初始化:
int c = 30;
int *const p2 = &c;
p2++; // 不合法,p2的指向不能变
(*p2)++; // 可以,注意加括号,自增运算符和取地址运算符优先级相同,但运算的顺序是从右到左,此时 c==31
再来分析它的修饰关系,指针来修饰常量,也就是指针型的常量,本质是个常量,但其类型是指针型(类似于int 常量,float常量等), 这样说来倒也可以说得通。
简单的记法
如果按照上面这样的分析去记这些概念,未免太繁琐了,经常容易混淆,还容易遗忘。
我们的目的不是为了弄清常量指针和指针常量这两个概念的修饰关系,而是为了遇到它们时可以理解其含义,上面的两个说法都是我们根据英文自己翻译过来的,倒不如直接按照英文说法来记。
英文中对应的两个概念是 const pointer
和 pointer to const
// const pointer
int a = 10;
int *const pa = &a; // 声明同时初始化
// pointer to const
const b = 20;
const int *pb = &b;
请不要尝试去翻译上面的两个词,越翻译越混乱,不如直接按照英文的说法来记忆,见到了可以对号入座,我们的目的就达到了。
中文还是不太严谨的,遇到不清楚的概念,还请直接查它们的英文原版释义,毕竟…机器是外国人发明的,当然用他们的语言最容易理解这些概念.