关于C#:避免指针问题的最佳实践

Best practices to avoid problems with pointers

本问题已经有最佳答案,请猛点这里访问。

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

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

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


指针使用不当时可能出错的事情:

  • 内存泄漏-您在一个方法中分配一个指针,然后让它超出范围而不正确地解除分配它。指向堆上内存的指针现在丢失,但内存仍在分配中。现在释放内存非常困难。来自维基百科的更多信息。

  • 访问冲突-创建一个指针,指向您无权访问或不存在的内存地址。毕竟指针只是整数,可以像其他数字一样被操作。当您试图取消对无效指针的引用时,程序将停止。来自维基百科的更多信息。

  • 空指针错误-这是访问冲突的特殊情况。正确的方法是将指针"停"到零或零,这样它就不会指向任何特定的对象。试图取消对空指针的引用将停止您的程序。来自维基百科的更多信息。

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

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

  • 以空结尾的字符串问题-当期望以空结尾的字符串的字符串库函数被送入非以空结尾的字符指针时,就会出现这些错误。字符串库函数将继续处理字符,一次处理一个字符,直到找到一个空值——无论在哪里。一个笑话最能说明这个错误。


  • Compiler Complaint

    来自http://xkcd.com

    我想我是按照字面上的插图要求。


    只要初始化指针变量并进行良好的清理,就可以消除99%的问题。我的意思是,通过良好的清理,释放内存并将指针变量设置为空。

    否则,您需要一个清晰的设计来传递指针,以及什么代码负责清理内存。如果你最终陷入一种不知道什么代码将是最后一个使用内存的情况,那么你就有了一种设计的味道,为了保持你的理智,你需要修复它。


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

    还有对所指向的对象类型的误解,但这通常需要一些努力才能避免被编译器大喊大叫。

    内存泄漏,但情况不同,这是关于分配,而不是指针本身。


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

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

    我最喜欢的指针轶事是:我曾经在佛罗里达州的一个小组工作,该小组在新墨西哥州的库尔德兰空军基地(大部分在大陆的另一边)维持了一个对3名日射波探测仪的网络飞行模拟。有一天突然出现了一个碰撞虫。当地的网站技术人员无法修复它,所以大约一个月后,我们的一个工程师飞来查看它。两周后,他被弄糊涂了,另一个被拉了进来。又过了一个月,我们的高级工程师也飞来帮忙。

    一个多月后(公司一直为住在酒店的3个人买单,租车,每两个周末飞回来),他们找到了问题所在。结果发现有人正在索引一个超过数组末尾的索引(C也没有索引检查)。然后他们抓起放在那个位置的垃圾,通过网络把它传递给第二台机器,然后它将这个值用作数组索引。因为该代码也在C中,所以再次没有检查。它抓住那个地方的垃圾,把它送到第三台机器上。那台机器用这个废话作为指针,试图把它解引用。繁荣。

    因此,一台机器上的代码中的一个错误导致了一次崩溃,两台机器从网络中删除。数千美元和几个月的宝贵时间被浪费掉了。因为他们使用的语言没有范围检查。


    • 不要忽视任何警告。
    • 使用夹板之类的静态分析工具。

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


    原始的指针是邪恶的。无法知道它们是否有效(悬空指针),是否已初始化(如果在初始化时未设置为空,则它们可能显示为实际指向某个对象),并且不清楚谁有责任释放它们指向的资源(例如调用方检索或返回指针的函数)。

    没有聪明的指点,我一天也活不下去。std::auto_ptr当我转移所有权时(明确责任),boost::shared_ptr当所有权被分享时,boost::weak_ptr当某人只"观察"资源时。


    我不知道你是否还能做到这一点,但我记得几年前,我们做了一个脚本,通过擦除整个RAM来破坏系统。我们就是这样做的。

    1
    2
    3
    4
    5
    6
    int *i;

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

    至少我记得我们是这样做的。不过,我相信现在不行。


    最佳实践是尽量避免使用指针。对于大部分软件,使用托管语言,对于访问系统资源或效率所必需的小部分,只使用C语言。换言之,C应该被视为与汇编语言大致相同的语言。

    (我帮助完成的原始问题"不是真正的问题"非常不同,而且太宽泛,无法发挥作用。)