栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

【const与指针】

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【const与指针】

const与指针
  • 一、const与指针
    • 1.const在C和C++中的区别
      • 1.1 如果在C语言中使用const去定义变量,然后再去定义数组,则会提示:**类型错误**
      • 1.2 C编译
      • 1.3 C++编译
  • 二、const和指针的关系
    • 1. 常变量与指针
    • 2. 同类型指针的赋值兼容规程
    • 3. 练习
  • 总结


一、const与指针 1.const在C和C++中的区别

【注】const在C和C++中的使用方式不同,C语言中,使用const修饰变量时,是以变量为主的;但是在C++中,const修饰变量,是以“常性”为主的,也就是说,使用const定义变量之后,是以常性为主的,遇见常变量会用值去替换掉

常性替换是在编译阶段进行替换

#include 
// C  const
int main()
{
	const int n = 10;  // C语言中const修饰变量时,以变量为主,也就是说,const针对的是变量
	int arr[n] = { 1,2 };  // C语言中此定义错误,因为其会认为n就是一个变量,虽然加了const修饰,仍然是变量,定义数组时数组大小是一个大于零的整形常量,
	// 上述定义会出现类型错误,
	return 0;
}

// C++  const
#include 
using namespace std;
int main()
{
	const int n = 10;  // C++在修饰变量的时候,是以“常性”为主
	int arr[n] = { 1,2 };  // 在C++中此定义合法,会用整数值10取替换n,等价于:int arr[10] = { 1,2 };
	return 0;
}
1.1 如果在C语言中使用const去定义变量,然后再去定义数组,则会提示:类型错误

因为C的编译器会认为n是一个变量,即使用const去修饰,其仍然是一个变量,只不过const限制了其“写”操作

const int n = 5;
int b = n; // C语言中,从变量n这个内存空间取值赋值给整形变量b,是需要访问内存空间
int b = n; // 对于C++,在编译的过程中,遇见n就会将其替换成5

1.2 C编译

按照C的编译方法,虽然a用const修饰,但是可以通过p去改变a的值,在对内存进行访问,将a的值100(通过p去修改,此时为100)赋值给b,b的值也是100;所以按照C的编译方式,输出的结果为:100 100 100

【注】b = a; // C编译时,会借助一个“临时空间”,先将a的值取出来存放在临时空间,在将临时空间的值赋给b

1.3 C++编译


但是使用C++的方式编译,输出的结果为10 10 100。

  1. *p=100; // 将 *p的值改为100
  2. b = a; // C++编译时,直接将a的值替换成10,然后再将10赋值给b
  3. 所以输出为:10 10 100

【注】C++编译时,遇见const修饰的变量时(直接使用常变量这个值得时候),会先将其替换成具体的数值

二、const和指针的关系 1. 常变量与指针
#include 
int main()
{
	int a = 10, b = 10;
	int* p1 = &a;  // p1是一个普通指针
	const int* p2 = &a;  // 指向为常性(解引用为常性)const修饰的是“*”
	//int const* p2 = &a;  // 等价于const int* p2 = &a
	int* const p3 = &a;  // 指针变量自身为常性(const修饰的是指针p3)
	const int* const p4 = &a;  // 指向(解引用)和指针变量自身都为常性
}

int main()
{
	int a = 0;
	int* p1 = &a;  // OK
	const int* p2 = &a;  // OK
	int* const p3 = &a;  // OK
	const int* const p4 = &a;  // OK
	return 0;
}

对于使用C方式编译:

// 按照C编译方式,a为一个常变量,丢弃了“写”操作,只读
int main()
{
	const int a = 10;
	int* p1 = &a;  // error  编译不通过,因为可以使用普通指针解引用去改变a的值 --- 能力扩张
	const int* p2 = &a;  // ok  const修饰指向(*),所以不能通过p2解引用去修改a的值,但是指针p2本身可以修改
	int* const p3 = &a;  // error  const修饰指针p3,不允许修改p3,但是其指向,也就是通过对p3解引用修改a的值  --- 能力扩张
	const int* const p4 = &a;  // ok 指针本身和其指向均不能被修改
	int* p5 = (int*)&a;  // 强转,C语言中的“强盗”,虽然编译可以通过,但是不安全
}
2. 同类型指针的赋值兼容规程
// C编译方式
int main()
{
	int a = 10, b = 20;
	int* p = &a;  // 定义一个普通指针p指向a的地址
	int* s1 = p;  // ok  定义一个普通指针s1指向p指向的地址,也就是s1和p都指向a的地址
	const int* s2 = p;  // ok  const修饰指向,能力缩小
	int* const s3 = p;  // ok  指针s3为常性,但可以通过解引用修改a的值(允许)
	const int* const s4 = p;  // ok
}
3. 练习

练习1:

int main()
{
	int a = 10, b = 20;
	const int* p = &a;  // const修饰指向,不能通过对p解引用去修改a的值,但是可以修改指针p本身
	int* s1 = p;  // error  能力扩张,
	const int* s2 = p;  // ok  const修饰指向,即不能通过s2去修改a的值(s2和p都指向a),但是s2本身可以修改,s2的修改不影响p
	int* const s3 = p;  // error  const修饰指针s3,即可以通过对s3解引用去修改a的值(不允许),但s3本身不允许被修改
	const int* const s4 = p;  // ok
}

练习2:

int main()
{
	int a = 10, b = 20;
	int* const p = &a;  // const修饰指针p,即p本身不允许被修改,但是其指向可以被修改
	int* s1 = p;  // ok  定义一个指针s1指向a(和p都指向a),可以通过对s1解引用去修改a的值,也可以对s1本身进行修改,不会影响p
	const int* s2 = p;  // ok  const修饰指向,即不允许通过对s2解引用修改a的值,但是s2可以被修改,不影响p
	int* const s3 = p;  // ok  const修饰s3,即不允许修改s3本身,但是可以通过对s3解引用去修改a的值
	const int* const s4 = p;  // ok
}

总结
  1. 能力强的指针赋值给能力收缩的指针(能力收缩,允许)
  2. 能力弱的指针不能赋值给扩张的指针(能力扩张,不允许)
  3. 特别重要的一点就是,编译方式的不同,会导致不同的结果
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/836355.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号