指针常量和常量指针的区别

 本文概述 

      楼主再次更新本文内容,如本文测试的结果或者表述有错处之处,还望大家批评与指正,谢谢!更改时间:2019.3.30

      备注:此文与一些相关的文章和部分教学视频不同之处就是:指针常量和常量指针的命名与本文讲述的相反,但含义以及作用是一样的。楼主主要是参考了一些比较经典的书籍来写本文的。对于命名相反的问题,还是望大家来分析一下,谢谢!(文章末尾专门对一些书籍的部分内容截图作为参考,但请大家不必对此钻牛角尖,因为楼主为此也花了较多的精力分析,结果仍然得不到答案,不是很值得)--2019.6.4

      我们较难理解指针常量和常量指针是因为使用他们时对其概念容易混淆,理不清这对“双胞胎”兄弟的用处与区别。所以,本文重新整理了下,楼主尽量把以前说得模糊(其实楼主当时对这对“双胞胎”还没学到家)的内容梳理得顺畅些。本文即将会从“常量”、“指针常量”、“常量指针”这三种类型之间关系的角度来进行解释,尤其是楼主会基于常量的基础上,来进行分析“指针常量”和“常量指针”的区别,这有助于大家容易辨别这对“双胞胎”各自的个性。与此同时,楼主会专门制作图片来对此加深理解。

    为了考虑大家快速理解代码,楼主尽量使编码规范些,下文假设编码命名如下:

1.普通变量.命名为为a,b,c之类的例如int a,char c。

2.普通指针变量命名为ptr.

3.指针常量的指针变量命名为PtrConst。

4.指向非常量的常量指针命名为ConstPtr。

5.指向常量的常量指针命名为ConstConstPtr。

5.如果在同一函数再用到相同类型指针,就编号区分,例如PtrConst,PtrConst2

正文

常量

假设大家都知道这个常量的意思,就是限定某变量的值不会被修改。

但是用在指针方面显然有点复杂的多,const限定在指针时,并不是直接限定指向某变量的值,而是限定指针解引用的操作。所以说const在指针的作用就在于解引用时是否修改指向的数据或者修改指向的地址。

指针常量

指向常量的指针,这里所说的“常量”其实在解引用时起到所谓常量的作用,并非是指向的变量就是常量,指向的变量既可以是非常量也可以是常量。总体意思是不能修改指向某变量的值。

const int *PtrConst;

int const *PtrConst;两者等价。

方便理解:

      我们都知道在一级指针int *ptr中,ptr是一个指针变量,而*ptr是ptr指向某变量的值。因此,我们可以分析指针常量的声明如下:

 从右往左看,PtrConst是一个指针变量,* PtrConst是指向某变量的值。而const作为常量修饰符,它修饰的是“int * PtrConst”或者“*PtrConst”,则认为const限定了PtrConst指向某变量的值。如图所示:

     在查询资料中,有很多人对指针常量产生误解,即误以为指针指向的变量一定是一个常量,但实际上并非如此。实际上,指针常量指向的变量既可以是常量,也可以是非常量。

    当然,对于非指针变量例如int a之类的,用const修饰,就是限定a本身存储的值,即常量a。然而,在指针常量中,对指针变量PtrConst用const修饰,在这里指针变量PtrConst并非常量,而是它指向的变量被修饰为“常量”(实际上指向的变量也不一定是常量,例如PtrConst指向的变量是a,则“常量”可以是int a,也可以是非常量const int a ,其在指针常量解引用中,作用效果还是一致的,下文会详细分析)。

如图所示:

指针常量可以改变指向:

指针常量不能修改指向的某变量的值:

运用代码如下:

指针常量可以改变指向:

int main()
{
	//在这里声明,a,b都既可以是常量const int也可以是非常量int
	int a=1;
	int b=2;
	int const *PtrConst=&a;
	cout<<"a::"<<a<<endl;
	cout<<"*PtrConst:"<<*PtrConst<<endl;

	PtrConst=&b;//指针常量可以由指向a改变为指向b
	cout<<"b:"<<b<<endl;
	cout<<"*PtrConst:"<<*PtrConst<<endl;
	return 0;
}

结果:

a:1
*PtrConst:1
b:2
*PtrConst:2

指针常量不能修改指向变量的值(当a是非常量时):

int main()
{
	//当a是非常量时
	int a=1;
	int *ptr=&a;
	int const *PtrConst=&a;
	cout<<"a::"<<a<<endl;
	cout<<"*ptr:"<<*ptr<<endl;
	cout<<"*PtrConst:"<<*PtrConst<<endl;
	//企图修改a的值
	*ptr=2;//正确
//	*PtrConst=2;//报错,error C3892: “PtrConst”: 不能给常量赋值
	cout<<"a:"<<a<<endl;
	cout<<"*ptr:"<<*ptr<<endl;
//	cout<<"*PtrConst:"<<*PtrConst<<endl;
	return 0;
}

结果:

a::1
*ptr:1
*PtrConst:1
a:2
*ptr:2

指针常量不能修改指向变量的值(当a是常量时):

int main()
{
	//当a是常量时
	const int a=1;
	int *ptr=&a;
	int const *PtrConst=&a;
	//企图修改a的值
	*ptr=2;//报错,“初始化”: 无法从“const int *”转换为“int *”
	*PtrConst=3;//报错,error C3892: “PtrConst”: 不能给常量赋值
	return 0;
//结论:
//*ptr报错原因就是数据类型不一致,但即使转换为const int*也报错提示为:不能给常量赋值
}

*****************************************************

常量指针

常量指针不能改变指向的变量(即不能改变指针保存的内容)。

  int *const ConstPtr=&a;//必须初始化,只能指向一个变量,绝不可再改变指向另一个变量。

方便理解:

我们都知道在一级指针变量int *ptr中,ptr是一个指针变量,*是一个指针符号。对于常量指针的声明有如下分析:

从右往左看,ConstPtr是个指针变量,const是常量,限定ConstPtr,因此ConstPtr保存的内容(即ConstPtr保存某变量的地址)不会被改变。(相似:int const  a,a的内容不变)

            这种指针在进行声明时,就一定要对其进行初始化,否则的话,编译时就会报错。因为如果它不进行初始化的话,那它根本就不存在只能指向固定变量的意义了。如果需要时它才被赋值,显然就相当于它起到能够指向另一个变量的作用,即改变指向任意变量,所以不初始化是没有意义的。(这段话可以忽略,先看懂后面所有文字,然后再回过头来看这段话,这样就不会容易搞懵了。)

-----------------------------------------

指向非常量的常量指针指向时(当a为非常量时):

指向非常量的常量指针指向时(当a为非常量时)代码如下:

int main()
{
	 int a=1;
	 int b=2;
	 //int *const ConstPtr;//报错,error C2734: “ConstPtr”: 如果不是外部的,则必须初始化常量对象
	 int *const ConstPtr=&a; //初始化,从ConstPtr产生到结束,一直指向a。
	// ConstPtr=&b;//报错:常量指针不可改变指向
	return 0;
}

指向非常量的常量指针指向时(当a为常量时):

指向非常量的常量指针指向时(当a为常量时)代码如下:

int main()
{
	const int a=1;
	int *const ConstPtr=&a; //报错,“初始化”: 无法从“const int *”转换为“int *const ”
	return 0;
//结论:报错原因就是指针指向的类型不一致。
//因为ConstPtr是指向非常量的常量指针,而a是常量类型的。
}

指向非常量的常量指针能修改a的值(当a为非常量时):

指向非常量的常量指针能修改a的值(当a为非常量时)代码如下:

int main()
{
	 int a=1;
	int *const ConstPtr=&a; 
	*ConstPtr=123;//正确,可以修改非常量a
	return 0;
}

指向非常量的常量指针(当a为常量时):

因为指向非常量的常量指针是int *const 类型的,而a作为常量是const int *类型的。因此,两者数据类型不相同,就就会报错。既然int *const ConstPtr=&a;就会报错,那么自然不可能会有对a的值进行操作了。要是与常量a的数据类型相同,并对其进行解引用,就会用到指向常量的常量指针,下文会讲到。

指向常量的常量指针

const  int *const ConstConstPtr;

其指向以及解引用的作用与指向非常量的常量指针是相同的,但不同的是:指向非常量的常量指针不可指向常量,而指向常量的常量指针均可指向非常量或常量。

代码如下:

int main()
{
	//当a为非常量时
	  int a=1;
	const int *const ConstPtr=&a; 
//	*ConstPtr =13;//报错,不能给“常量a”赋值
	//当b为常量时
	const int b=2;
	const int *const ConstPtr2=&b; 
//	*ConstPtr2 =13;//报错,不能给“常量a”赋值

//如何区分指向非常量的常量指针和指向常量的常量指针,本文末尾总结时将会讲到
//由结果可知:常量指针指向非常量和常量时,都是不可修改指向变量的值。
	return 0;
}

总结:

(1)声明时,根据常见以const限定的数据类型,来区分指针常量与常量指针的区别。

(2)不同的类型分为如下:

指针常量:指向非常量的指针常量,指向常量的指针常量

常量指针:指向非常量的常量指针,指向常量的常量指针

(3)指向规则:

指针常量:无论指向的变量是否是常量,都可以指向,可修改指向。

常量指针:

一定要初始化,并且该指针从产生到销毁都只能指向一个对象。

指向非常量的常量指针:当指向的变量是非常量时,可以指向当指向的变量为常量,不可指向,更不用说对其进行解引用。

指向常量的常量指针:无论指向的变量是否是常量,均可指向。

(4)改变指向某变量的值情况:

指针常量:可以改变指向某变量的值。

常量指针:

指向非常量的常量指针:不可改变

指向常量的常量指针:不可改变

(因为本文是之前复习到指针时写的文章,可能会存在错误的地方,所以此后有时间再认真检查一遍本文内容。如果发现有错误的地方或者觉得废话过多,我将会重新总结这个知识点。记录于2021.3.14)

书本的部分内容截图所示

图1来源--《C++程序设计语言》第5.4.1。

 

图1

图2是常量指针。--来源《C++编程思想》第8.2.2

图2

图3是指向const的指针,也就是指针常量。来源--《C++编程思想》第8.2.1

图3

图4是指针常量。来源--《C/C++程序员面试宝典》。

图4

图5是常量指针。--来源《C/C++程序员面试宝典》。

图5

图6指针常量。--来源《Primer C++第5版》第2.4.2

图6

图7常量指针。--来源《Primer C++第5版》第2.4.2

图7

图8--来源《深入理解C指针》。

图8

图9--来源《深入理解C指针》

图9

      说明:楼主发现还有其他书籍对这两个指针命名都是一样的,就不知道为何会出现在其他教学视频和大多数文章里描述的命名相反的情况。不知道谁对谁错,但不管怎么样,弄懂其含义和作用才是至关重要。对于命名相反的问题,楼主就不必再对此钻牛角尖了。

<think>好的,我现在需要帮用户理解指针常量常量指针区别。首先,用户提供的四个引用都详细讨论了这两个概念,所以我应该仔细参考这些资料来确保回答的准确性。 首先,我要明确两者的定义。根据引用3,指针常量指针的指向不可变,但内容可以变。而常量指针则是指针指向的内容不可变,但指向可以改变。这一点是关键,用户可能容易混淆两者的名称实际含义。 接下来,我需要对比它们的语法结构。引用2提到指针常量的写法是int *const p,而常量指针是const int *p或int const *p。这里的const位置不同,决定了修饰的是指针本身还是指针指向的内容。用户可能对语法细节不太清楚,所以需要明确说明。 然后,应用场景用法也很重要。比如指针常量常用于需要固定指针地址的情况,比如硬件寄存器操作,而常量指针用于保护数据不被修改,比如函数参数传递。引用4中的例子显示,如果尝试修改指针常量的指向会导致错误,这可以用来举例说明。 另外,用户可能会混淆两者的名称,因为“指针常量”听起来像是“指针常量”,而“常量指针”听起来像是“指向常量指针”,但实际上名称实际作用是相反的。需要强调这一点,帮助用户记忆。 还需要考虑用户可能的疑问,比如如何区分两者的写法。引用2提到可以通过口诀“const在*前是常量指针,const在*后是指针常量”,这样的记忆方法对用户可能有帮助。 最后,确保回答结构清晰,分点对比,并给出示例代码,帮助用户理解。同时生成相关问题,引导用户深入学习,比如应用场景、常见错误等。</think>### 指针常量常量指针区别及用法(C语言) #### 一、核心区别总结 | **特性** | **指针常量** | **常量指针** | |----------------|---------------------------|---------------------------| | **定义核心** | 指针的地址不可变 | 指向的数据不可变 | | **语法格式** | `int *const p = &a;` | `const int *p = &a;` | | **可修改性** | 地址固定,内容可变 | 地址可变,内容不可变 | | **错误示例** | `p = &b;`(地址不可改) | `*p = 20;`(内容不可改) | #### 二、详细对比分析 1. **指针常量(Pointer Constant)** - **定义**:指针本身是常量,即指针存储的地址不可修改,但可以通过指针修改指向的内容。 - **语法**:`type *const 指针名` ```c int a = 10, b = 20; int *const p = &a; // p的地址固定为&a *p = 15; // 正确:修改a的值为15 p = &b; // 错误:无法修改指针地址 [^4] ``` - **用途**:硬件寄存器映射、固定地址操作场景。 2. **常量指针(Constant Pointer)** - **定义**:指针指向的数据是常量,不能通过该指针修改数据,但可以修改指针指向的地址。 - **语法**:`const type *指针名` 或 `type const *指针名` ```c int x = 5, y = 6; const int *p = &x; // p指向x,但*x不可通过p修改 p = &y; // 正确:修改指针指向y *p = 8; // 错误:无法修改y的值 [^3] ``` - **用途**:函数参数传递(保护原始数据),如`void print(const char *str)`。 #### 三、记忆技巧 - **口诀**:**const在*前是常量指针,const在*后是指针常量** [^2] - **类比**: - 指针常量:家门锁死(地址固定),但屋内物品可换(内容可变)。 - 常量指针:屋内物品锁死(内容固定),但可搬去其他房子(地址可变)。 #### 四、综合示例代码 ```c #include <stdio.h> int main() { int num1 = 10, num2 = 20; // 常量指针:指向的数据不可变 const int *ptr1 = &num1; ptr1 = &num2; // 正确:改变指向 // *ptr1 = 30; // 错误:无法修改数据 // 指针常量指针地址不可变 int *const ptr2 = &num1; *ptr2 = 30; // 正确:修改num1的值 // ptr2 = &num2; // 错误:无法改变地址 // 指向常量指针常量(双const) const int *const ptr3 = &num1; // ptr3 = &num2; // 错误:地址不可改 // *ptr3 = 40; // 错误:数据不可改 return 0; } ``` #### 五、常见问题 1. **为什么字符串赋值可能引发错误?** - 若声明为`char *const str = "apple";`,尝试`str = "orange";`会触发错误,因为指针地址不可变[^4]。 2. **如何选择使用哪种指针?** - 需要保护数据时用常量指针(如函数参数)。 - 需要固定地址时用指针常量(如硬件操作)。
评论 40
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值