【C语言深度剖析】深入理解const的用法(趣味小故事解析)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 【C语言深度剖析】深入理解const的用法(趣味小故事解析)

文章目录

1、const的用法

const是constant的缩写,意思是“恒定不变的”,它是定义只读变量的关键字。

  • const:修饰变量
  • const:修饰指针

2、修饰变量

其实修饰变量很好理解,用const定义的变量的值是不允许改变的,不允许给它重新赋值,即使是赋相同的值也不可以。

所以说它定义的是只读变量;

这也就意味着必须在定义的时候就给它赋初值,如果程序中试图改变它的值,编译的时候就会报错。

代码示例:

int main()
{
  int n = 10;
  n = 20;//把20赋值给n
  printf("%d\n", n);
  return 0;
}

运行结果:

image.png

那如果我不希望n的值被改变呢?

这时候就需要我们的const

代码示例:

int main()
{
  const int n = 10;
  n = 20;//把20赋值给n
  printf("%d\n", n);
  return 0;
}

运行结果:

image.png

这时候运行就会报错;

懂了吗?

3、修饰指针

const放在*号左边

我们再来看一段代码

int main()
{
  const int n = 10;
  int* p = &n;
  *p = 20;
  printf("n=%d\n", n);
  return 0;
}

运行结果:

image.png

咦?为什么改变了呢?

我们想要的结果是,不能改变n的值,结果用指针的方法竟然可以修改!!!

打个比方:我不允许你从大门进来,结果你翻窗户进来了

那么我们是不允许这种事情发生的!

所以我们对代码进行修改:

int main()
{
  const int n = 10;
  const int* p = &n;
  *p = 20;
  printf("n=%d\n", n);
  return 0;
}

运行结果:

image.png

此时运行编译就会报错;

左值指定为const对象,*p就不能被修改了

所以const放在*号的左边,修饰的是*p;修饰的是指针所指向的对象不能再被改变了;

const放在*号右边

那么当const放在*号的右边呢?

再来看一段代码:

int main()
{
  int m = 100;
  const int n = 10;
  const int* p = &n;
  p = &m;
  printf("%d\n", &m);
  printf("%d\n", p);
  return 0;
}

运行结果:

image.png

可以看到虽然*p不能被修改,但是p可以被修改;

所以我们对代码进行修改:

int main()
{
  int m = 100;
  const int n = 10;
  int* const p = &n;
  p = &m;
  printf("%d\n", &m);
  printf("%d\n", p);
  return 0;
}

运行结果:

image.png

所以const放在*号的右边,修饰的是p;修饰的是指针变量不能再被改变了;

4、小故事

其实const修饰变量很好理解,但是修饰指针理解起来还是有点困难;

所以我举个例子吧!

如图:

image.png

此时 p = &n,说明女孩p和男孩n之间建立了男女关系;

image.png

当建立好关系以后,女孩就对男孩说:”旁边有家奶茶店,你给我买杯奶茶吧“

因为喝一杯奶茶要10元钱,意味着:*p = 0;就相当于把男孩的10元钱花掉了;

此时男孩心想:”哎呀,要花我10元钱呀,不行,我不愿意!“;

那么男孩就很聪明,在*号的左边加了一个const

image.png

这时候,女孩想喝奶茶也喝不上;男孩在兜里把10元钱拽的紧紧的!

于是乎,女孩就生气了呀,心想:”连10元钱的奶茶都不请,我得换男朋友了!“

此时女孩发现有一个男孩m,兜里有100元,也愿意请我喝奶茶;

image.png

那么p = &m这个动作就可以换男朋友了;

虽然女孩不能影响男孩n兜里的钱,但是女孩可以换男朋友;

女孩现在不指向男孩n了,而是去指向男孩m了:

image.png

此时男孩n慌了,心想:”这不行呀!既然你要换男朋友,那么我们再约定一下!“

男孩n对女孩说:”我可以请你喝奶茶,但是你不能换男朋友!”

既然不能换男朋友,那么我就要限制p,于是把const移到了*号的右边:

image.png

此时*p = 0可以执行,但是p = &m不能执行;

但是如果你遇到了一个男朋友:const int* const p = &n;那么你可以放弃了!

因为在*号的左右各加一个const,表示:这个男孩既不请你喝奶茶,又不让你换男朋友!

这下李姐了吗?

5、总结

  • const int* pconst放在了*的左边,修饰的是*p,使得*p不能通过p来改变,但是p可以被改变;
  • int* const pconst放在了*的右边,修饰的是pp不能被改变,但是*p可以被改变
  • const int* const pp*p都不能被修改;

6、思考

理解了const修饰 变量 和 修饰 指针的含义后,那么看看下面这段代码的意思呢?

代码示例:

int main()
{
  int a = 10;
  int* pa = &a;
  const int* const* const ppa = &pa;
  return 0;
}

我是这样理解的:

*ppapa

**ppaa

也就是二级指针本身指向不能改,二级指针所指向的指针的指向也不能改

哈哈哈,是不是有点绕…

相关文章
|
2月前
|
IDE 编译器 开发工具
【C语言】全面系统讲解 `#pragma` 指令:从基本用法到高级应用
在本文中,我们系统地讲解了常见的 `#pragma` 指令,包括其基本用法、编译器支持情况、示例代码以及与传统方法的对比。`#pragma` 指令是一个强大的工具,可以帮助开发者精细控制编译器的行为,优化代码性能,避免错误,并确保跨平台兼容性。然而,使用这些指令时需要特别注意编译器的支持情况,因为并非所有的 `#pragma` 指令都能在所有编译器中得到支持。
131 41
【C语言】全面系统讲解 `#pragma` 指令:从基本用法到高级应用
|
2月前
|
JSON Shell Linux
dockerfile 用法全解析
Dockerfile指令简介:`FROM`基于Alpine镜像;`WORKDIR`设置工作目录;`COPY`复制文件;`ADD`支持URL;`RUN`运行命令;`CMD`容器启动时执行;`ENTRYPOINT`与`CMD`组合执行;`EXPOSE`声明端口;`VOLUME`映射文件;`ENV`设置环境变量;`ARG`构建参数;`LABEL`元数据;`ONBUILD`触发命令;`STOPSIGNAL`停止信号;`HEALTHCHECK`健康检查;`SHELL`默认Shell。Alpine仅5M,小巧高效。
58 4
dockerfile 用法全解析
|
2月前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
176 14
|
2月前
|
存储 算法 C语言
【C语言】深入浅出:C语言链表的全面解析
链表是一种重要的基础数据结构,适用于频繁的插入和删除操作。通过本篇详细讲解了单链表、双向链表和循环链表的概念和实现,以及各类常用操作的示例代码。掌握链表的使用对于理解更复杂的数据结构和算法具有重要意义。
697 6
|
2月前
|
存储 网络协议 算法
【C语言】进制转换无难事:二进制、十进制、八进制与十六进制的全解析与实例
进制转换是计算机编程中常见的操作。在C语言中,了解如何在不同进制之间转换数据对于处理和显示数据非常重要。本文将详细介绍如何在二进制、十进制、八进制和十六进制之间进行转换。
79 5
|
2月前
|
C语言 开发者
【C语言】断言函数 -《深入解析C语言调试利器 !》
断言(assert)是一种调试工具,用于在程序运行时检查某些条件是否成立。如果条件不成立,断言会触发错误,并通常会终止程序的执行。断言有助于在开发和测试阶段捕捉逻辑错误。
55 5
|
23天前
|
存储 算法 C语言
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
55 23
|
23天前
|
算法 C语言
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
本文档介绍了如何编写两个子函数,分别求任意两个整数的最大公约数和最小公倍数。内容涵盖循环控制与跳转语句的使用、最大公约数的求法(包括辗转相除法和更相减损术),以及基于最大公约数求最小公倍数的方法。通过示例代码和测试说明,帮助读者理解和实现相关算法。最终提供了完整的通关代码及测试结果,确保编程任务的成功完成。
52 15
|
23天前
|
C语言
【C语言程序设计——函数】亲密数判定(头歌实践教学平台习题)【合集】
本文介绍了通过编程实现打印3000以内的全部亲密数的任务。主要内容包括: 1. **任务描述**:实现函数打印3000以内的全部亲密数。 2. **相关知识**: - 循环控制和跳转语句(for、while循环,break、continue语句)的使用。 - 亲密数的概念及历史背景。 - 判断亲密数的方法:计算数A的因子和存于B,再计算B的因子和存于sum,最后比较sum与A是否相等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台对代码进行测试,预期输出如220和284是一组亲密数。 5. **通关代码**:提供了完整的C语言代码实现
56 24
|
19天前
|
存储 C语言
【C语言程序设计——函数】递归求斐波那契数列的前n项(头歌实践教学平台习题)【合集】
本关任务是编写递归函数求斐波那契数列的前n项。主要内容包括: 1. **递归的概念**:递归是一种函数直接或间接调用自身的编程技巧,通过“俄罗斯套娃”的方式解决问题。 2. **边界条件的确定**:边界条件是递归停止的条件,确保递归不会无限进行。例如,计算阶乘时,当n为0或1时返回1。 3. **循环控制与跳转语句**:介绍`for`、`while`循环及`break`、`continue`语句的使用方法。 编程要求是在右侧编辑器Begin--End之间补充代码,测试输入分别为3和5,预期输出为斐波那契数列的前几项。通关代码已给出,需确保正确实现递归逻辑并处理好边界条件,以避免栈溢出或结果
52 16

推荐镜像

更多