将memcpy与结构字段一起使用

时间:2014-05-24 11:06:38

标签: c structure memcpy

我在C中创建了这个(参见Class in C (not C++)),我想这样做:

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 :)
}

2 个答案:

答案 0 :(得分: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));

null终止符写入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';

编辑:感谢所有对此发表评论的人!

答案 1 :(得分: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()更好。