专栏首页PHP饭米粒10 个内存引发的大坑,你能躲开几个?(1)

10 个内存引发的大坑,你能躲开几个?(1)

对程序员来说内存相关的 bug 排查难度几乎和多线程问题并驾齐驱,当程序出现运行异常时可能距离真正有 bug 的那行代码已经很远了,这就导致问题定位排查非常困难,这篇文章将总结涉及内存的一些经典 bug ,快来看看你知道几个,或者你的程序中现在有几个。。。

返回局部变量地址

我们来看这样一段代码:

int fun() {  
  int a = 2;  
  return &a;
}
void main() {  
   int* p = fun();  
   *p = 20;
}

这段代码非常简单,func 函数返回一个指向局部变量的地址,main 函数中调用 fun 函数,获取到指针后将其设置为 20。

你能看出这段代码有什么问题吗?

问题在于局部变量 a 位于 func 的栈帧中,当 func 执行结束,其栈帧也不复存在,因此 main 函数中调用 func 函数后得到的指针指向一个不存在的变量

尽管上述代码仍然可以“正常”运行,但如果后续调用其它函数比如funcB,那么指针p指向的内容将被 funcB 函数的栈帧内容覆盖掉,又或者修改指针 p 实际上是在破坏 funcB 函数的栈帧,这将导致极其难以排查的 bug。

错误的理解指针运算
int sum(int* arr, int len) {
  int sum = 0;
  for (int i = 0; i < len; i++) {
      sum += *arr;
      arr += sizeof(int);
  }
  return sum;
}

这段代码本意是想计算给定数组的和,但上述代码并没有理解指针运算的本意。

指针运算中的加1并不是说移动一个字节而是移动一个单位,指针指向的数据结构大小就是一个单位。因此,如果指针指向的数据类型是 int,那么指针加 1 则移动 4 个字节(32位),如果指针指向的是结构体,该结构体的大小为 1024 字节,那么指针加 1 其实是移动 1024 字节。

从这里我们可以看出,移动指针时我们根本不需要关心指针指向的数据类型的大小,因此上述代码简单的将arr += sizeof(int)改为arr++即可。

解引用有问题的指针

C语言初学者常会犯一个经典错误,那就是从标准输入中获取键盘数据,代码是这样写的:

int a;
scanf("%d", a);

很多同学并不知道这样写会有什么问题,因为上述代码有时并不会出现运行时错误。

原来 scanf 会将a的值当做地址来对待,并将从标准输入中获取到的数据写到该地址中。

这时接下来程序的表现就取决于a的值了,而上述代码中局部变量a的值是不确定的,那么这时:

  1. 如果a的值作为指针指向代码区或者其它不可写区域,操作系统将立刻kill掉该进程,这是最好的情况,这时发现问题还不算很难
  2. 如果a的值作为指针指向栈区,那么此时恭喜你,其它函数的栈帧已经被破坏掉了,那么程序接下来的行为将脱离掌控,这样的 bug 极难定位
  3. 如果a的值作为指针指向堆区,那么此时也恭喜你,代码中动态分配的内存已经被你破坏掉了,那么程序接下来的行为同样脱离掌控,这样的bug也极难定位

----------伟大的分割线-----------

PHP饭米粒(phpfamily) 由一群靠谱的人建立,愿为PHPer带来一些值得细细品味的精神食粮!

饭米粒只发原创或授权发表的文章,不转载网上的文章

所发的文章,均可找到原作者进行沟通。

本文分享自微信公众号 - PHP饭米粒(phpfamily)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-02-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 10 个内存引发的大坑,你能躲开几个?(2)

    对程序员来说内存相关的 bug 排查难度几乎和多线程问题并驾齐驱,当程序出现运行异常时可能距离真正有 bug 的那行代码已经很远了,这就导致问题定位排查非常困难...

    桶哥
  • 10 个内存引发的大坑,你能躲开几个?(3)

    对程序员来说内存相关的 bug 排查难度几乎和多线程问题并驾齐驱,当程序出现运行异常时可能距离真正有 bug 的那行代码已经很远了,这就导致问题定位排查非常困难...

    桶哥
  • 你可能不知道大数据开发的10个技巧

    “当你不创造东西时,你只会根据自己的感觉而不是能力去看待问题。” – WhyTheLuckyStiff

    风火数据
  • 吹弹牛皮之Unity 性能分析-锁定内存泄漏

    承载千万家庭的高考莘莘学子刚刚为10年的寒窗苦拉上帷幕。鼓励我们的学子多多选择计算机专业。这里有拉格朗日函数的求解,有傅里叶级数的转换。奥秘万千,从笛卡尔坐标系...

    用户7698595
  • Android爬坑之旅:软键盘挡住输入框问题的终极解决方案

    开发做得久了,总免不了会遇到各种坑。 而在Android开发的路上,『软键盘挡住了输入框』这个坑,可谓是一个旷日持久的巨坑——来来来,我们慢慢看。

    用户2802329
  • 案例实战:每日上亿请求量的电商系统,JVM年轻代垃圾回收参数如何优化?

    按照惯例,我们接下来会用案例驱动来带着大家分析到底该如何在特定场景下,预估系统的内存使用模型。

    乔戈里
  • 高仿微信双击消息弹出可自由复制

    Enmmm,前几天突然才晓得微信还有一个双击消息弹出且提供自由复制的这么一个小功能,惊呆了,我滴天~!

    HLQ_Struggle
  • 一键获取免费真实的匿名代理

    專 欄 ❈夏洛之枫,从销售转为程序员,Python爬虫爱好者。 github: https://github.com/ShichaoMa/proxy_fact...

    Python中文社区
  • 天使投资人王利杰解读智能硬件创业趋势

    镁客网

扫码关注云+社区

领取腾讯云代金券