深入 C 语言和程序运行原理
于航
PayPal 技术专家
21121 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 49 讲
深入 C 语言和程序运行原理
15
15
1.0x
00:00/00:00
登录|注册

08|操控资源:指针是如何灵活使用内存的?

arr[3]3[arr] 的等价性
避免重复释放
及时释放内存
非同一数组内元素的指针运算
返回局部变量的指针
未初始化的指针
动态生成数据
数据生存期
使用 mallocfree
动态分配和释放
使用 cmpsetg 指令实现
比较指针的地址值
指针间求差
自增/自减
加法/减法
指针可以指向数组元素
数组是连续的内存区域
丢失大小和类型信息
传递数组到函数
通过 leamov 指令实现
解引用运算符 *
取地址运算符 &
可以添加 const 限制操作
使用 * 符号
C语言中指针的多种用途
精细化内存管理
指针的强大与风险
数组下标与指针的关系
堆指针的生命周期管理
避免未定义行为
堆内存与栈内存的区别
堆内存的特点
关系运算
算数运算
数组与指针的关系
数组退化为指针
取地址与解引用
定义指针变量
总结
思考题
使用指针的注意事项
堆内存指针
指针的其他运算
指针与数组
指针的基本使用
C语言中指针的使用

该思维导图由 AI 生成,仅供参考

你好,我是于航。
“指针”是 C 语言为我们提供的最为强大的武器之一。借助指针,我们可以更加灵活地使用应用程序所享有的内存。
不同于 Python、Java 等语言,C 语言为我们提供了这样一种能力:可以让程序员根据需要,主动选择使用“按值传递”或“按指针传递”这两种不同的数据引用方式。通常,按值传递会涉及原始数据的复制过程,因此在某些情况下,可能会引入额外的性能开销。而按指针传递则使程序内存中的“数据共享”成为了可能。
这一讲,就让我们来一起看下,在 C 语言中指针都有哪些使用方式,以及在语法背后,这些方式都是如何通过机器指令来实现的。

指针的基本使用

使用 C 语法定义变量时,通过为类型说明符添加额外的 “ * ” 符号,我们可以定义一个指向该类型数据的指针。不仅如此,通过添加额外的 const 关键字,我们还能够限制使用该指针变量时所能够进行的操作类型。
比如在下面这个例子中,我们便定义了这样的一个指针。通过添加 const 关键字,编译器限制了对指针 npA 的使用,使得它自身无法被重新赋值,并且也无法通过它来修改所指向的数据。
指针不仅在 C 语言中的使用方式很简单,它在机器指令层面的实现也十分简单。还记得我们在 03 讲 中最后介绍过的取地址 “&” 与解引用 “*” 运算符吗?通过使用这两个运算符,我们便能够完成对指针的最基本,也是最重要的两个操作,即取值与赋值。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

C语言指针的基本使用方式、指针与数组的关系、指针的算数与关系运算,以及堆内存指针的灵活操控能力是本文的重点内容。文章详细介绍了指针的基本使用、指针与数组的关系以及指针的其他运算,为读者提供了全面的指针知识。指针的灵活性使得程序员可以更加灵活地使用内存,但需要注意避免一些操作,如解引用未初始化的指针、函数返回指向其内部局部变量的指针等。此外,对堆指针进行有效的生命周期管理也是需要注意的问题。文章还介绍了堆内存的重要性,以及堆内存相对于栈内存的优势,如动态生成数据、灵活的生存期等。总之,本文通过介绍C语言中指针的基本使用方式、指针与数组的关系、指针的算数与关系运算以及堆内存指针的灵活操控能力,为读者提供了全面的指针知识,并强调了指针使用中需要注意的问题。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入 C 语言和程序运行原理》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(14)

  • 最新
  • 精选
  • sky
    有个疑问,算数运算一节,右侧汇编代码样例中sub rbp 32,说明栈分配了32字节,但二维数组实际只占4*6=24字节,剩余8字节是做什么用的?

    作者回复: 这是一个好问题!实际上这是由于 SysV 规范要求在函数调用前,栈顶需要在 16 字节的边界对齐(我们曾在第 05 讲中提到过)。因此由于这里在栈中需要存放 6 个元素,需要至少 24 字节的空间。所以为了对齐到 16 字节,rsp 的值要减少至少 32 字节。

    2021-12-25
    2
    13
  • Joker
    老师,将二维数组指针等同于二级指针是否不太准确呢?因为从本质上来说二者是有根本区别的,二维数组名对应的地址值和arr[0][0]的地址值是一样的,只不过两者对应的指针类型一个为int (*)[3],一个为int *。而二级指针为指针的指针,在此处对应的类型应该是int **。所以我认为二维数组指针本质上还是一个一级指针,不知道我这样的理解有没有问题?

    作者回复: 感谢指正!你理解的没错,两者之间确实有些差异,我来修改一下表述。

    2022-05-16
    5
  • 纳兰容若
    老师您好 向您请教一下arr[3] == 3[arr]的问题 我实际运行的结果是两者是相等的 arr[3] 不应该是 [arr地址 + 3 * sizeof(int)]位置的数值么 3[arr] 是 [3 + arr地址]?[3 + arr地址 * sizeof(int)]?位置的数值 两者为什么会相同呢 还是我理解错了

    作者回复: 这里不要从 C 代码的形式上扣哈,可以直接看编译器产物的结果。你会发现 3[arr] 与 arr[3] 产生的机器代码是完全一致的。因为编译器在解析 C 代码时可以通过判断括号左侧和括号内的值是不是 Constant Value 来判断当前这个值是应该作为索引,还是数组首地址来使用。

    2022-04-13
    4
    1
  • zxk
    老师,关于 ”在某些特定的使用方式下,编译器会将数组类型退化为指针类型“,那这个是属于使用不当,还是一种优化手段?不太明白这个行为会有什么后果及应用场景。

    作者回复: 好问题。我们这里讲到的“数组退化到指针”实际上是 C 语言在设计上的一种性质,并不是使用不当或者优化手段。这个性质出现的原因要追溯到 C 语言的前身 B 语言中的类似设计上。在大多数场景下,需要注意问题就是变量性质(数组大小、数组类型)的丢失。

    2022-01-22
    1
  • I
    答案是5,arr+1为arr1 0,然后再加一为1 1,所以为5

    作者回复: 答案正确!

    2021-12-24
    2
    1
  • Victor
    虽然编译过了,但这个可读性太差了

    作者回复: 哈哈哈是的,所以正常项目中不要使用哈。

    2021-12-26
  • qinsi
    因为 a[i] = *(a + i) 所以 x[y[i]] = x[*(y + i)] = x[*(i + y)] = x[i[y]] = *(x + i[y]) = *(i[y] + x] = i[y][x] 在用到多级间接下标时可以避免嵌套中括号
    2021-12-25
    5
  • =
    printf("%d\n", *(*(arr + 1) + 1)); // 结果为5 arr+1后,二级指针指向arr[1] *(arr+1)后,一级指针指向arr[1][0] *(arr + 1) + 1后,一级指针指向arr[1][1] *(*(arr + 1) + 1))后,解引用出结果5 文末的代码可以编译通过,而且arr[3]
    2022-01-07
    1
    4
  • 无双BaOY_WHA
    arr[3] 和 3[arr] 映射到汇编代码上是一样的。但没见过 3[arr] 这种写法…
    2021-12-24
    2
  • Geek_00a01d
    思考题 交作业 相等 printf("%d", arr[3] == 3[arr]); warning: self-comparison always evaluates to true [-Wtautological-compare] 由上面同学的解答可知 arr[3]= *(arr+3) = *(3+arr) = 3[arr]
    2022-12-20归属地:河南
收起评论
显示
设置
留言
14
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部