1

我正在学习 Zed Shaw 的 Learn C the Hard Way。我对 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... */

练习链接...

memset所以我的问题是,为什么被调用的第三个参数DArray_expandarray->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 个字节写入字节串 b。

我用谷歌搜索了 memset 的实现。我从这个链接得到这个:

C 标准库: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;
}

在我的操作系统(达尔文 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 的代码有错误,你能告诉我如何修复它吗?

4

2 回答 2

1

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

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

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


此外,memset到 0 并不是使指针为 NULL 的防弹方法。在一些奇特的架构上,all-bits-0 并不一定意味着NULL.

于 2013-03-02T11:09:13.120 回答
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 的回答后,我错过了这一点并对其进行了修改。

于 2013-03-02T11:10:29.253 回答