2014-05-24 50 views
0

我在C(見Class in C (not C++))創建這個類,我想這樣做:使用的memcpy與結構字段

void assignModel(Car *this, char *model) 
{ 
    // Is a string, so I need null all the space 
    memcpy(this->model, '\0', sizeof(this->model)); // Error in execution time 
    strncpy(this->model, model, strlen(model)); // Yes, it's insecure :) 
} 
+3

敢肯定你的意思'memset',不'memcpy'。我可以想出幾種比這裏採取的方法更好的方法,特別是因爲後者不僅不安全,而且因爲目標緩衝區大小完全避免,顯然是*有目的*。 – WhozCraig

+0

注意,如果'strlen(model)> sizeof this-> model',這會導致緩衝區溢出,並且在相等情況下它不會生成以null結尾的字符串。 –

+0

'this-> model'是一個數組,對吧? – dasblinkenlight

回答

2

memcpy預計,第二個參數指向一個地方存儲從你想採取的數據。 '\0'不指向內存:當它轉換爲void*時,它變成NULL。解除引用NULL會導致未定義的行爲,從而導致您看到的執行時錯誤。

如果你想設置零到一個特定的領域,用memset代替memcpy

memset(this->model, 0, sizeof(this->model)); // this->model is an array 

然而,填補了陣列零是在您的情況不必要的:如果你正確地複製字符串,你止跌不必填寫零來獲得終結者。這裏的問題是 - 當你做到這一點,

strncpy(this->model, model, strlen(model)); 

空終止是寫入this->model陣列,留下串終結處理。您的代碼用於通過用零填充陣列來「彌補」這個缺點。但是,當strlen(model)與您可以寫入this->model數組的字符總數相同時,這會使字符串未終止。

要解決這個問題,我會用strlcpy如果你的系統提供了它(注意 - 它不是C標準的一部分)。

strlcpy(this->model, model, sizeof(this->model)); 

如果您的系統沒有它,你可以按如下模擬其效果:

int len = min(sizeof(this->model)-1, strlen(model)); 
memcpy(this->model, model, len); 
this->model[len] = '\0'; 

編輯:感謝大家誰對這個評論!

+0

不知道爲什麼有人低估了這個(儘管我更喜歡看成語memset(&x,0,sizeof x)' - 這對任何對象都是可用的,而memset(a,o,sizeof a)'只是正確的iff'a'是一個數組) –

+1

如果'sizeof(this-> model)'大於'model'允許的可讀區域,這個「安全」memcpy版本將會調用UB。 (不,我沒有DV,不知道誰做過)。 – WhozCraig

+0

OOOOhhh,0h,0h 0h ... ;-) @MattMcNabb – alk

0

這裏有一個更好的方式做什麼(我覺得)你想做的事:

void assignModel(Car * const this, const char * const model) 
{ 
    snprintf(this->model, sizeof(this->model), "%s", model); 
} 

這有幾個優點:

  • 它不會溢出目的地(不像strcpy()
  • 如果源字符串太長,結果會被截斷,但(不像strncpy())它仍然有'\ 0'終止符
  • 它避免了不必要的memset()
  • 它避免了不必要的strlen()
  • 我加了一些const所以編譯器將捕獲一些愚蠢的錯誤,像源和目標混合起來。

在大多數情況下, snprintf(foo, sizeof(foo), ...) 具有比各自strcpy()strncpy()更好的行爲。