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呼び出された byの 3 番目の引数DArray_expandarray->expand_rate + 1代わりにあるのはarray->expand_rateなぜですか? 展開後の配列の長さは 400 (初期の長さが 100 の場合)contents[0]からcontents[399]. 初期化する必要がある要素は から までの範囲でありcontents[100]contents[399]の 3 番目の引数は 300 であるmemset必要がarray->expand_rateあります。誰かに説明してもらえますか?

私の投稿を編集してくれてありがとう。インライン コード md 構文を使用できることを忘れていました。


編集: このコードでも memset を使用していることに混乱しています。私のコンピューターの memset の man ページには、次のように書かれていました。

memset() 関数は、len バイトの値 c (unsigned char に変換) をバイト文字列 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;
}

私のOS(Darwin 12.0.0)では、との値sizeof(void *)sizeof(int *)8です。もう少し試してみました。私のOSのすべての種類のポインターのサイズは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() 関数は、s が指すメモリー領域の最初の n バイトを定数バイト c で埋めます。

そのため、可能性が高いはずarray->expand_rate * sizeof(void *)です。


さらに、memsetto 0 はポインタを NULL にする完全な方法ではありません。一部の特殊なアーキテクチャでは、オールビット 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 に答える