使用指针时DO和Donts

时间:2009-11-12 12:31:26

标签: c++ c pointers

这是一个简单而重要的问题。在C和C ++中使用指针时有什么做和不做的,以确保在AIX上避免SEGMENTATION FAULT?

哪里char *比字符数组更受欢迎?

10 个答案:

答案 0 :(得分:18)

C ++特定

  • 避免手动管理内存,而是使用RAII容器,例如std::auto_ptrboost::scoped_ptrboost::shared_ptr和等效的数组容器。更简单,通常std::vector工作正常,并且根本不需要任何指针使用。最后,您可以传递引用,而不是将指针传递给大型或可修改的数据结构。指针可以表示数组,而引用可以避免这种歧义。
  • 索引数组是大多数指针算法的理想替代品。它通常不比指针算法慢,这通常更容易出错,更难以阅读和维护。一般来说,不要以牺牲可读性为代价进行微观优化。
  • 调用正确的释放例程: delete[]仅用于通过new ...[]分配的数组,delete仅用于指向单个对象的指针,free(...)仅用于通过C api分配的内存(例如malloc(..))。这些不能混淆; C ++释放例程包括析构函数调用,因此需要正确调用。
  • 显式初始化并设置无意义的指向NULL的指针。调试意外的空取消引用比不正确的内存访问更容易。可以解除分配NULL指针,因此您不需要使用检查来破坏析构函数以避免这种情况。如果您过早地delete一个对象,那么您应该将其指针设置为NULL,以避免双重删除相同的指针并避免意外解除引用悬空指针。
  • 如果您正在使用C ++继承并且正在覆盖析构函数,请阅读虚拟析构函数;这些是正确性所必需的(简而言之,基类必须明确地将析构函数标记为虚拟)。
  • 如果您必须手动管理内存,请注意谁“拥有”指针。只有所有者才能释放指针所指向的对象或数组,并且在所有者delete指向它之后,没有其他对象可以使用该对象。 boost::shared_ptr是一个无障碍的低开销容器,当你需要共享一个指针时通常很好。

答案 1 :(得分:12)

  1. 始终确保您的指针已初始化
  2. 始终知道分配的内存区域的长度
  3. 使用指针时始终检查NULL值
  4. 使用后始终删除指针
  5. 永远不要覆盖指针末端的内存
  6. 永远不要相信提供给您的方法的有效性指针
  7. 永远不要将用户输入放在指针中(例如获取)
  8. 切勿将malloc / free与new / delete
  9. 混合使用
  10. 永远不要使用malloc
  11. 分配指向类对象的指针
  12. 永远不要使用免费的
  13. 释放类对象指针

    最后但并非最不重要

    永远不要使用指针,除非你必须...... 有(const)引用可以避免传递给函数和STL容器的对象的复制构造以及其他存储要求的字符串并使用smart(boost) :: shared_ptr)指针,如果你真的需要指针而不想手工跟踪它们。

答案 2 :(得分:3)

在C

  • 不要指向你没有“拥有”的记忆。
  • 不要取消引用NULL指针。
  • 在您不需要资源时免费提供资源。
  • 不要忘记你的指针(注意失败的reallocs)。
  • 请勿滥用void*
  • 不要混用指针类型:char*double**不同。
  • 检查返回指针的函数的返回值。

答案 3 :(得分:2)

编写符合标准的代码。这应该照顾平台。还有很多其他问题。并使用const。这会解决更多问题。

答案 4 :(得分:1)

我前段时间加入了一个项目,其中一些优秀的开发人员只使用了裸指针。即使他们具有出色的技能,他们的程序(在Windows / Linux / HP-UX上运行)也会不时导致段错误,并且存在一些内存泄漏。

据我所知,如果一个程序很大且有线程,很难找到与指针相关的所有错误,除非你绝对需要一个裸指针,否则你应该使用Boost.Smart_ptr

答案 5 :(得分:1)

在C ++中总是使用虚拟析构函数。 如果删除基类,这将确保调用派生类的destuctor。如果你不这样做,派生类做了一些分配,你将没有机会清理它。

答案 6 :(得分:1)

注意:C特定答案 - >

以下是此细分违规或细分错误的常见原因:

printf或scanf语句中的格式控制字符串不正确: 确保格式控制字符串具有相同数量的转换说明符(%'),因为printf或scanf分别具有要打印或读取的参数,并且说明符与要打印或读取的变量类型匹配。这也适用于fprintf和fscanf。

忘记使用“&”关于scanf的参数: 函数scanf将格式控制字符串和变量的地址作为参数,它将放置它所读取的数据。“&” (地址)运算符用于提供变量的地址。常常忘记使用“&”与scanf调用中的每个变量。省略“&”可能导致分段违规。

访问超出数组的范围: 确保您没有违反正在使用的任何阵列的边界;即,您没有使用小于其最低元素的索引或大于其最高元素的索引的值来预订数组。

在访问指针之前无法初始化指针: 在被访问之前(即,出现在赋值的右侧),必须为指针变量分配有效地址(即,出现在赋值的左侧)。确保已初始化所有指针以指向有效的内存区域。适当的指针初始化可以通过多种方式完成。示例如下所列。

错误使用“&” (地址)和“”(解除引用)运算符: 确保您了解这些运算符的工作原理。知道何时应用它们以及何时不应用它们。如上所述,常常忘记使用“&”与scanf调用中的每个变量。请记住,scanf需要它正在读取的变量的地址。特别是,知道什么时候“&”并且“”是绝对必要的,并且最好避免使用它们。

解决问题:

检查程序中使用指针,下标数组或使用地址运算符(&)和解除引用运算符(*)的每个位置。每个都是导致分段违规的候选者。确保您了解指针和相关运算符的使用。 如果程序使用了许多指针并且出现了很多&和*,然后添加一些printf语句来查明程序导致错误的位置并调查该语句中涉及的指针和变量。

请记住,用于调试目的的printf语句应该在其格式控制字符串的末尾有一个换行符(\ n),以强制刷新打印缓冲区。

答案 7 :(得分:0)

所有权问题通常是最困难的:您的设计应该已经决定了。 拥有对象应该负责销毁它。

但是我已经看过场景仍然被称为被破坏的对象 - 也就是悬空指针。您的设计也应考虑“有效性”。对删除对象的每个引用都应明显无效。如果我没弄错的话,weak_ptr班可以推迟这个决定。

答案 8 :(得分:0)

不要做边界检查。

答案 9 :(得分:0)

对于“哪个char *比字符数组更受欢迎?”的回答并不是真的。问题,但最近有点我正在审查的人是“sizeof”。

考虑一下:

char *a = new char[3];
char b[3];

在许多地方,您以类似的方式使用“a”和“b”。 当您执行以下操作时,问题就会出现:

strncpy(b, some_string, sizeof(b));    
strncpy(a, some_string, sizeof(a));

我想这个故事的寓意是:小心sizeof()。保持大小不变​​可能更好。