避免指针问题的最佳实践

时间:2009-09-16 13:28:33

标签: c pointers

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

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

带代码的实际例子更可取。

9 个答案:

答案 0 :(得分:23)

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

  1. 内存泄漏 - 您在方法中分配指针,然后让它超出范围而不正确释放它。现在,指向堆上内存的指针已丢失,但内存仍保持分配状态。释放这种记忆现在非常困难。 More info from Wikipedia.

  2. 访问冲突 - 您创建一个指针,指向您无权访问或不存在的内存地址。指针只是整数,可以像任何其他数字一样操纵。当您尝试取消引用无效指针时,程序将暂停。 More info from Wikipedia.

  3. 空指针错误 - 这是访问冲突的特例。 “停放”指针的正确方法是将其值设置为零或null,以使其不指向任何特定的位置。尝试取消引用空指针将停止程序。 More info from Wikipedia.

  4. 缓冲区溢出 - 为30个字符的字符缓冲区分配指针。然后,您继续将用户输入(从套接字,文件,控制台等)流入此缓冲区。如果未能正确实现缓冲区边界检查,则程序可能会将超过30个字符放入缓冲区。这将破坏存储器中缓冲区附近存储的所有数据,并可能使您遭受恶意代码攻击。 More info from Wikipedia.

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

  6. 以空值终止的字符串问题 - 当期望以null结尾的字符串的字符串库函数被送入非空终止的字符指针时,会发生这些错误。字符串库函数将继续一次处理一个字符,直到找到null为止 - 无论在哪里。 A joke best illustrates this bug.

答案 1 :(得分:18)

Compiler Complaint

来自http://xkcd.com

我想我的字面意思是

答案 2 :(得分:3)

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

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

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

答案 3 :(得分:3)

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

否则,您需要一个关于传递指针的清晰设计以及负责清理该内存的代码。如果您最终遇到的情况是您不知道哪个代码将是最后一个使用内存&应该清理,然后你有一个设计气味,你需要修复,以保持你的理智。

答案 4 :(得分:2)

  • 永远不要忽视任何警告。
  • 使用static analysis tools之类的Splint

  • 最重要的是:使用dynamical analysis tools - 他们经常警告错误使用指针,打破数组边界等等'我确保在这些上没有错误,即使程序似乎正在运行。 ..

答案 5 :(得分:2)

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

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

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

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

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

答案 6 :(得分:1)

我不知道你是否仍然可以这样做,但我记得几年前我们会通过擦除整个RAM来制作一个崩溃系统的脚本。这是我们这样做的方式。

int *i;

while(1){
   *i = 0;
   i++;
}

至少我记得我们是这样做的。我相信它现在不会起作用。

答案 7 :(得分:1)

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

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

答案 8 :(得分:0)

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

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