NULL 指標兩三事
Posted on September 16th, 2007 at 21:51 by fr3@K

最近被我面試的十來位應徵者, 除了一位之外, 都不清楚以下兩個 pointer to NULL (指向 0 的指標) 的基本特性:

  • delete 一個指向 NULL 的指標是安全的
  • 以一個指向 NULL 的 C-style 字串為參數呼叫 strlen 會造成死機 (segmentation fault, access violation or whatever)


在公司標準的試卷上有一題是實作一個 string class, 包含 operator= 在內的幾個主要 member function:

    
    class String
    {
    public:
      // ...
      String& operator=(const String& other);
    
    private:
      char* data_;
    };
    

於是就常會在答案卷看到類似下面這樣, 有趣的 String::operator= 實作:

    
    String& String::operator=(const String& other)
    {
      if(this == &other)
        return *this;
      if(data_ != NULL)
        delete [] data_;
    
      data_ = new char[strlen(other.data_) + 1];
      strcpy(data_, other.data_);
      return *this;
    }
    

看似小心翼翼地在 delete 之前檢查 String::data_ 是否為 NULL (即便毫無意義), 卻又天真地完全不理會呼叫 strlen 時參數為 NULL 的後果.

del.icio.us:NULL 指標兩三事 digg:NULL 指標兩三事 spurl:NULL 指標兩三事 newsvine:NULL 指標兩三事 furl:NULL 指標兩三事 Y!:NULL 指標兩三事 黑米共享書籤:NULL 指標兩三事 推推王:NULL 指標兩三事
Previous Post
« WP-Notable - Patched to Support funP and HEMiDEMi «
Next Post
» 變更原代碼授權 »

6 Comments »

Comment #3804

我還沒想過 strlen 給他一個 = NULL 的指標會當掉的問題ㄝ,
這不是 strlen 自己要去檢測的嗎。
這有是歷史的淵源嗎???

不然通常我自己寫的函式都會先來個 if( p == NULL) return; 這類的,
還是這樣是多餘是不好的行為呢??

還有~~你們應該是想看看有沒有人會提出用 \’0′ 結尾字串比較不好的論點吧。

Comment by 烤布雷 — September 18, 2007 @ 16:47


Comment #3805

我還沒想過 strlen 給他一個 = NULL 的指標會當掉的問題ㄝ,
這不是 strlen 自己要去檢測的嗎。
這有是歷史的淵源嗎???

這段有沒有歷史故事我是不知道. 對我而言, 這是經過理性考量後的合理行為.

不然通常我自己寫的函式都會先來個 if( p == NULL) return; 這類的,
還是這樣是多餘是不好的行為呢??

假設在一種應用, 指向 NULL 的 string 是一種不合理 (或是一種錯誤) 的狀態. 試想一下一個 string 在經過許多層 function 一個呼叫另外一個的一連串處理. 要求每一層 function 都去驗證這個 string 是否指向 NULL 可說是:

  • 無謂的負擔. 經過上層檢查後再由下層一再重複同樣的檢查, 這不符合 C/C++ 的哲學
  • 若測試 string 指向 NULL 的結果為 true, 則可能需要增加一種錯誤狀況的回報. 也等於增加了上層錯誤處理的複雜度

應該由最上層開始處理的 function 測試一次, 然後對下面所有層的 function 保證傳遞的 string 不會指向 NULL 便可. 但這種保證只能是由 programmer 來拍胸脯保證. (其實沒有多大實質效用) 下層 function 可用 assert 來確認上層給保證的有效. 這個方式既保障了一定程度的安全, 也能在 NDEBUG (Release) 模式下省去重複的檢查:

    
    void bar(const char* str)
    {
      assert(str != NULL);
      size_t len = strlen(str);
      // ...
    }
    
    

還有~~你們應該是想看看有沒有人會提出用 \’0′ 結尾字串比較不好的論點吧。

'\0' 做為字串的結尾是歷史的遺蹟, 也在某種程度上是合理的結果. 除了到了最底層得跟 C 的 library 介面時, 我不太用 C-style string, 也沒什麼特別的想法. 分享一下你的看法吧.

Comment by fr3@K — September 18, 2007 @ 18:08


Comment #3806

嗯~~感謝你這麼精闢的分析

Comment by 烤布雷 — September 18, 2007 @ 19:28


Comment #3903

哈哈,我也属于你第一句中的9/10,谢谢帮助纠正。

Comment by func — October 12, 2007 @ 17:48


Comment #4399

考量到不同 compiler/stdlib 的實作,一開頭的兩個「基本特性」其實都不一定成立。:-)

Comment by jeffhung — May 6, 2008 @ 12:07


Comment #4400

的確不符合這兩個特性的 stdlib 是肯定有的. 就像 new 失敗時的確也有 stdlib 會傳回 null, 而不 throw 出 bad_alloc.

雖然沒有十足把握, 如果我沒記錯的話它們都是 standard 裡面定義的 behavior. They are (supposely) the proper behaviors to expect from a standard conforming compiler/stdlib. 但也正如 jeffhung 所說的, 凡事都會有例外的. :)

Comment by fr3@K — May 6, 2008 @ 18:19


Comments RSS TrackBack URI

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>