多年前学 C 时经常混淆如数组指针及指针数组这一类名词的概念,在编程的时候遇到麻烦,前些日子阅读《C++ Primer》时再一次回忆起这一问题,因此打算做个笔记记录一下。在网上搜索这类概念时也发现网上的文章说法不一,当然大多数只是在名称混淆,在对具体声明的含义进行分析时还是能分析准确的。本笔记也不深究名称的正确性,主要还是辨析具体含义。
1.指向常量的指针与常量指针:
指向常量的指针(pointer to const):令指针指向常量,指向常量的指针不能用于改变其所指对象的值。想要存放常量对象的值,只能使用指向常量的指针。
const int a = 0;
const int *p = &a;
p = &b;//正确, p 可以修改
*p = 1;//错误,*p 不可修改
注意:允许一个指向常量的指针指向一个非常量对象。
int b = 3;
p=&b ;//正确,但是不能通过 p 改变 b 的值
常量指针(const pointer):指针本身是一个常量,常量指针必须初始化,初始化后其值就不能改变了,这里的值指的是存放在指针中的那个地址。即不变的是指针本身而非指向的那个值。
把*放在 conet 关键字之前用以说明指针是一个常量:
int a = 0;
int * const p = &a;
*p = 1; //正确,*p 可以修改
p ++; //错误,p不可以修改
还有一种,即指向常量对象的常量指针:
const int * const p = &a; // 此时*p 和 p均不可改变了。
指针本身是个常量,其指向对象的值能否修改的问题还是依赖于所指对象的类型。
注意,按照《C++ primer》的翻译,“pointer to const” 为“指向常量的指针”,"const pointer"为“常量指针”,并没有提到所谓的“指针常量”。我在查阅了网上众多文章后还是决定用《C++ Primer》的说法来进行记忆。个人认为也没有必要深究名称,在写代码时能够根据想表达的意思写出准确的声明,或是面对声明能够准确理解其含义,才是最好的。
2.指针数组与数组指针:
指针数组:存放指针的数组,即其首先是一个数组,而数组的元素是指针。
int *p[10];
//一个一维指针数组,其每一个元素均为指针
//由于数组元素均为指针,因此p[i]是指第i+1个元素的指针
注意:int *p[10] 和 int *(p[10])是一样的,[ ]优先级高于*
char *p[2] = {"hello", "world"};
//这里p就是一个指针数组,它有2个元素,每个元素是一个char * 类型的指针
//这些指针指向对应的字符串
当然还可定义多维指针数组,分析方法类似,这里不进行赘述。
数组指针:指向数组的指针,其本质为指针。
int (*p)[10];
//指向一个含有10个整数的数组(首地址)
《C++ Primer》中似乎并未明确提及“指针数组”及“数组指针”这样的概念,仅提到“定义一个存放指针的数组”及“定义数组的指针”。个人认为没有必要死记名词概念,我们应该去理解具体的含义,做到能看懂复杂的声明,并能够根据自己的想法写出正确的声明。 对于复杂数组声明的分析,《C++ Primer》给出了一个好用的方法,就是从数组的名字开始按照由内向外的顺序进行阅读。
总结
常量、引用、数组、指针,各种排列组合组成复杂的概念,让人头晕。因此若是都像这篇笔记一样对容易混淆的概念一个个辨析一个个记忆,不仅工作量大,而且说实话学习效果可能不是很好。可能一时半会理解了,过段时间又忘了。最好的方法还是多实践,通过实践对概念进行理解才是最好的。
参考资料:
[1]:《C++ Primer(第五版)》2.4节和3.5节
这东西就不按照参考文献的格式写了,本身也就是记个笔记,不想这么麻烦。