在扩展void指针的动态数组后初始化新分配的内存

时间:2013-03-02 11:03:02

标签: c

我正在学习Zed Shaw的艰苦学习方法。我对ex34中函数定义的代码感到困惑。在ex34中,Zed教我们如何实现动态数组。 darray.h中的代码:

typedef struct DArray {
  int end;
  int max;
  size_t element_size;
  size_t expand_rate; /* it's 300 by default. */
  void **contents;
} DArray;

DArray *DArray_create(size_t element_size, size_t initial_max);
int DArray_expand(DArray *array);
/* other operations... */

代码让我感到困惑的是darray.c:

DArray *DArray_create(size_t element_size, size_t initial_max)
{
  DArray *array = malloc(sizeof(DArray));
  array->max = initial_max;
  array->contents = calloc(initial_max, sizeof(void *));
  array->end = 0;
  array->element_size = element_size;
  array->expand_rate = DEFAULT_EXPAND_RATE; /* defined in header, which is 300 */

  return array;
}

static inline int DArray_resize(DArray *array, size_t newsize)
{
  array->max = newsize;
  void *contents = realloc(array->contents, array->max * sizeof(void *));
  array->contents = contents;
  return 0;
}

int DArray_expand(DArray *array)
{
  size_t old_max = array->max;
  DArray_resize(array, array->max + array->expand_rate);
  memset(array->contents + old_max, 0, array->expand_rate + 1); // confused

  return 0;
}
/* Definitions of other operations... */

The link of the exercise...

所以我的问题是,为什么memset调用的DArray_expand的第三个参数是array->expand_rate + 1而不是array->expand_rate?我认为扩展后数组的长度为400(假设初始长度为100),范围从contents[0]contents[399]。需要初始化的元素范围从contents[100]contents[399],然后memset的第三个参数应为array->expand_rate,即300.有人可以向我解释一下吗?

感谢您编辑我的帖子。我忘了我可以使用内联代码md语法。


编辑:我对此代码中使用memset感到困惑。我计算机上的memset手册页说:

  

memset()函数将值为c的len个字节(转换为unsigned char)写入字节串b。

我已经google了memset的实现。我从这个链接得到了这个:

C standard library:string.h:memset

#include <stddef.h> /* size_t */
void *memset(void *s, int c, size_t n)
{
    unsigned char* p=s;
    while(n--)
        *p++ = (unsigned char)c; // This line confused me..
    return s;
}

在我的操作系统(Darwin 12.0.0)中,sizeof(void *)sizeof(int *)的值为8.我已经尝试了一些。我的操作系统中各种指针的大小似乎都是8.如果指针的大小是8,那么这段代码会发生什么:

*p++ = (unsigned char)c; /* the value of c is 0. size of 
                            unsigned char is 1 in my OS */

如果Zed的代码有错误,你能告诉我如何解决它吗?

2 个答案:

答案 0 :(得分:1)

+1可能至少是疯子或代码味道。此外,memset函数写入n个字节:

  

memset()函数填充内存区域的前n个字节   由s指向的常量字节c

因此,它应该是array->expand_rate * sizeof(void *)


此外,memset为0并不是一种使指针为NULL的防弹方法。在一些奇特的架构 all-bits-0 doesn't necessarily mean NULL

答案 1 :(得分:0)

你说得对,声明错了

memset(array->contents + old_max, 0, array->expand_rate + 1);

这可能导致访问超出数组的范围

应该是

memset(array->contents + old_max, 0, array->expand_rate * sizeof(void *));

修改 另外,如上面的cnicutar所述,它应该是array->expand_rate * sizeof(void *)。在看到cnicutar的回答之后,我错过了这一点并进行了修改。