模仿redis字典部分代码:dict.c
但是会报段错误,疑惑中
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct dictEntry {
int key;
} dictEntry;
typedef struct dictht {
dictEntry **table;
int d_val;
} dictht;
typedef struct dict {
dictht ht[2];
} dict;
dictEntry *dictAddRaw(dict *d, void *key)
{
dictEntry *entry;
entry = zmalloc(sizeof(*entry));
}
zmalloc 和malloc一样,
问题是一般分配内存都是
entry = zmalloc(sizeof(entry));
为什么redis
entry = zmalloc(sizeof(*entry));
假设add_ht传入的参数d已经被初始化,指向已经分配的内存空间,这个时候ht->table是一个指向指针的指针,初始化时候的值为0. ht->table = dict_entry这个语句行dict_entry指针的值付给ht->table, 虽然类型不匹配,一个是指针,一个是指向指针的指针,但是由于ht->table是合法的,所以还不会出现内存访问错误。ht->table[0] 所做的是取ht->table的值(为0),然后加上 0 * sizeof(dict_entry *)的offset,然后将得到的地址作为将要存储dict_entry值的内存地址,类似于下面的操作
*(ht->table + 0 * sizeof(dict_entry *) = dict_entry;
由于这个时候ht->table的值为0,那么这个操作的最终内存地址也是0,这样就产生了内存访问错误。
第3版本,这次应该没问题了
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct dictEntry {
int key;
} dictEntry;
typedef struct dictht {
dictEntry **table;
int d_val;
} dictht;
typedef struct dict {
dictht ht[2];
} dict;
dict *dictCreate();
int dictInit(dict *d);
static void dictReset(dictht *ht);
dict *dictCreate()
{
dict *d = malloc(sizeof(*d));
dictInit(d);
return d;
}
int dictInit(dict *d)
{
dictReset(&d->ht[0]);
dictReset(&d->ht[1]);
return 0;//ok
}
static void dictReset(dictht *ht)
{
ht->table = malloc(sizeof(dictEntry **));//必须这么写
ht->d_val = 0;
}
static void add_ht(dict *d,int val)
{
dictEntry *entry;
dictEntry *entry0;
dictht *ht;
ht = &d->ht[0];
//现在没有段错误,但是redis 源码的
//entry = zmalloc(sizeof(*entry));
entry=malloc(sizeof(*entry));
entry->key=123;
ht->table[1]=entry;
entry0=malloc(sizeof(*entry));
entry0->key=456;
ht->table[0]=entry0;
printf("%d\n",ht->table[1]->key);
printf("%d\n",ht->table[0]->key);
return;
}
void add_to_ht(dict *d,int val){
add_ht(d,val);
}
int main(int argc, const char *argv[])
{
dict *d;
d=dictCreate();
//add
add_to_ht(d,22);
return 0;
}
ht->table=dict_entry;
这也不对啊,dict_entry
的类型是dict_Entry*
。ht->table
的类型是dict_Entry**
。
而且,你也没有为ht
分配内存,所以ht->table
也不对。
所以,你首先需要为ht
分配内存,dictht *ht = malloc(sizeof(dictht));
然后再ht->table = &dict_entry;
。
或者,直接*(ht->table) = malloc(sizeof(dict_entry)*数组大小)
Edit:
你在那里用sizeof(entry)
是不对的,可能你只是碰巧遇到sizeof(entry)
的大小和sizeof(*entry)
的大小相同。
因为sizeof(entry)
得到的是指针的大小,sizeof(*entry)
得到的才是dictEntry
的大小。用sizeof(*entry)
有一个好处就是当你修改entry的类型的时候,你不需要再去修改sizeof
里面的东西。
例如:
TypeA* ptr = malloc(sizeof(TypeA));
如果要修改ptr
为:TypeB* ptr
,那么就要连带修改sizeof(TypeA)
为sizeof(TypeB)
。如果用sizeof(*ptr)
,那么只需要修改把类型改为TypeB
。
还有,为什么sizeof(*entry)
是合法的?
Edit:
或者,直接
*(ht->table) = malloc(sizeof(dict_entry)*数组大小)
抱歉,之前这里漏了,要先为ht->table
分配内存先。