避免指针问题的最佳实践

与指针有关的程序员错误的实际结果是什么?

当程序员创建指针错误时会发生什么“不良影响”?

带代码的实际例子是优选的。

当指针被滥用时可能出错的事情:

  1. 内存泄漏 – 您在方法中分配一个指针,然后让它超出范围而不正确地释放它。 现在,指向堆上内存的指针已丢失,但内存仍保持分配状态。 释放这种记忆现在非常困难。 来自维基百科的更多信息。

  2. 访问冲突 – 您创建一个指向您无权访问或不存在的内存地址的指针。 指针只是整数,可以像任何其他数字一样操纵。 当您尝试取消引用无效指针时,程序将暂停。 来自维基百科的更多信息。

  3. 空指针错误 – 这是访问冲突的特例。 “停放”指针的正确方法是将其值设置为零或为零,以使其不指向任何特定的位置。 尝试取消引用空指针将停止您的程序。 来自维基百科的更多信息。

  4. 缓冲区溢出 – 为30个字符的字符缓冲区分配指针。 然后,您继续将用户输入(从套接字,文件,控制台等)流入此缓冲区。 如果您未能正确实现缓冲区边界检查,那么您的程序可能会将超过30个字符放入缓冲区。 这将破坏存储器中缓冲区附近存储的所有数据,并可能使您面临恶意代码攻击。 来自维基百科的更多信息。

  5. 内存损坏 – 指针只是一个整数,包含它指向的内存地址。 作为一个整数, 指针算术可用于以各种有趣的方式操纵指针的值。 如果指针计算出错,可能会产生细微的错误。 指针现在将指向内存中的某个未知位置,并且在取消引用时可能发生任何事情。

  6. 以空值终止的字符串问题 – 当期望以空字符结尾的字符串的字符串库函数被送入非空终止的字符指针时,会发生这些错误。 字符串库函数将继续一次处理一个字符,直到找到null为止 – 无论在哪里。 一个笑话最能说明这个错误。

Compiler Complaint

来自http://xkcd.com

我想我正在逐字地提出插图请求

这一切都归结为访问未指定的内存区域。 在分配区域外读/写,取消引用未初始化的指针。 基本上就是这样。

还有一种误解了指向的对象的类型,但这通常需要一些努力才能逃脱,而不会被编译器大吼大叫。

和内存泄漏,但这是不同的故事,它是关于分配,而不是指针本身。

只是初始化指针变量和良好的清理将消除99%的问题 。 通过良好的清理,我的意思是; 释放内存并将指针变量设置为null。

否则,您需要一个关于传递指针的明确设计以及负责清理该内存的代码。 如果您最终遇到的情况是您不知道最后一个使用内存的代码并且应该进行清理,那么您会有一种设计气味,您需要修复它才能维护理智。

  • 不要忽视任何警告。
  • 使用像Splint这样的静态分析工具 。

  • 最重要的是:使用动态分析工具 – 它们经常警告错误使用指针,打破数组边界等等’我确保在这些工具上没有错误,即使程序似乎正在工作……

取消引用错误指针时的结果是未定义的,因此根据定义当你弄乱指针时会发生任何事情。 这就是为什么你应该尽可能避免使用它们。

C-ish语言是围绕指针的使用而设计的,它们现在占主导地位,所以这对某些人来说听起来像是疯狂的建议。 我建议大家研究一下旨在最大限度地减少指针使用并检查常见错误的语言,比如Ada。

我最喜欢的指针节点如下:我曾经在佛罗里达州的一个小组工作,在新墨西哥州的Kurtland空军基地(大部分位于非洲大陆的另一边)维持着3个heliocpoters的网络飞行模拟。 有一天出现了一个崩溃的bug。 本地网站技术无法修复它,所以一个月左右后,我们的一名工程师飞过去看它。 两个星期后,他陷入了困境,所以另一个人被拉了进来。又过了一个月,我们的顶级工程师也飞了过去帮忙。

再过一个月(公司一直支付3人住在酒店,租车,每隔几个周末飞回来),他们追查了这个问题。 原来,有人在数组末尾索引一个(C也没有索引检查)。 然后他们抓住坐在那个位置的废话,将它传递给网络上的第二台机器,它正在使用该值作为数组索引。 由于该代码也在C中,再次没有检查。 它抓住那个位置的废话并将它发送到第三台机器。 那台机器使用废话作为指针并尝试取消引用它。 繁荣

因此,一台计算机上的代码中的错误导致两台计算机从网络中删除。 花费了数千美元和几个月的宝贵时间来追踪它。 所有这些都是因为他们使用的语言没有范围检查。

原始指针是邪恶的。 没有办法知道它们是否有效(悬空指针),如果它们已经被初始化(如果在初始化时没有设置为NULL,它们可能看起来实际上指向某些东西)并且很不清楚谁有责任释放资源他们指向(例如调用者检索或返回指针的函数)。

没有智能指针,我不会过一天。 std :: auto_ptr当我转移所有权(明确责任),boost :: shared_ptr当所有权被共享时,boost :: weak_ptr当有人只是“观察”资源时。

最佳做法是尽可能避免使用指针。 对于大部分软件,请使用托管语言,对于访问系统资源或效率所必需的小部件,只能使用托管语言。 换句话说,C应该被认为与汇编语言大致相同。

(我帮助关闭的原始问题“不是一个真正的问题”是完全不同的,太宽泛而无用。)