一、首先说delet函数内容中(见上一节)出现的data_destroy函数。
我的思考:数据销毁,管理块销毁,是两码事。
二、创建的函数原型是 DArray* darray_create(DataDestroyFunc data_destroy, void* ctx)
我的思考:传入销毁数据的函数,动态的销毁上次使用的darray的数据,
再销毁动态数组的管理块structure DArray,
最后重新生成动态数组。
要销毁的数据,可能被考虑是多种类型的,所以销毁的时候,需要传入特定的销毁数据函数来操作。
但是数据都是void*类型的啊??没有类型的分别,传进来data_destroy干嘛?
三、经过上边的思考,发现销毁函数的动作,应该是两步走,先把数据销毁,再销毁动态数组的管理块。
写了两个函数,create和destroy,先把darray.h和main.c贴上来。
#ifndef __DARRAY_H__
#define __DARRAY_H__
#include <stdio.h>
#include <stdlib.h>
#define return_if_fail(p) if(!(p)) \
{printf("%s:%d Warning: "#p" failed.\n", \
__FUNCTION__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
{printf("%s:%d Warning: "#p" failed.\n",\
__FUNCTION__, __LINE__); return (ret);}
struct _DArray;
typedef struct _DArray DArray;
typedef enum _Ret{
RET_INVALID_PARAMS=0,
RET_OK,
RET_FAIL,
RET_OOM
}Ret;
typedef void (*DataDestroyFunc)(DArray*);
typedef void (*DataCompareFunc)(void);
typedef void (*DataVisitFunc)(void);
DArray* darray_create(DataDestroyFunc data_destroy, void* ctx);
Ret darray_insert(DArray* thiz, size_t index, void* data);
Ret darray_prepend(DArray* thiz, void* data); //数组最前面添加元素
Ret darray_append(DArray* thiz, void* data); //最后面添加
Ret darray_delete(DArray* thiz, size_t index);
Ret darray_get_by_index(DArray* thiz, size_t index, void** data);
Ret darray_set_by_index(DArray* thiz, size_t index, void* data);
size_t darray_length(DArray* thiz);
int darray_find(DArray* thiz, DataCompareFunc cmp, void* ctx);
Ret darray_foreach(DArray* thiz, DataVisitFunc visit, void* ctx);
void darray_destroy(DArray* thiz);
#endif
darray.h
#include "darray.h"
void main()
{
DArray* p = darray_create(NULL, NULL);
darray_destroy(p);
}
// main.c用于测试create和destroy函数
=====================================================================
只有create和destroy。
在写darray.c代码的时候,碰到了点问题。两种理解。先贴不可行的理解方式。
把DArray.data指针,理解成了由一个二级指针,指向一个一级指针,再指向10个sizeof(void*)。所以这么写的:
void* p = malloc(10 * (sizeof(void*));
void** q = &p;
DArray->data = q;
#include "darray.h"
typedef struct _DArray{
void** data;
size_t alloc_size;
size_t size;
}DArray;
#define MIN_PRE_ALLOCATE_NR 10
void darray_destroy(DArray* thiz)
{
void* z;
return_if_fail(thiz != NULL);
/*
销毁函数动作两步走:
销毁数组各成员(数据)
销毁管理项
*/
/*
想用二级指针thiz->data指向的,一级指针,来销毁10次sizeof(void*)。
严重理解错误!
使用malloc的时候,不论分配的是一个一级指针,还是一个二级指针。
分配的这块空间都是一个整体,怎么能够销毁10次呢??
脑子秀逗了吧!
while((thiz->size)--)
{
free(thiz->data[thiz->size]);
}
*//*
free(*(thiz->data));这个销毁数据的步骤,还分了两步写...:
z = *(thiz->data);
printf("%p\r\n", z);
free(z);
弊端2:
这样出错是因为,原来在create函数中赋值的时候,p变量指向哪儿,已经丢失!!!
thiz->data只记录了&p,
thiz->data指向p的地址,但是p指向哪儿,就不知道了。
*/
free(thiz);
}
DArray* darray_create(DataDestroyFunc data_destroy, void* ctx)
{
/*传入销毁函数,动态的销毁上次使用的darray,重新生成。*/
if(NULL != ctx)
{
darray_destroy((DArray*)ctx);
}
/*
弊端1
简单地说, void 是一个类型, void * 就是指向这个类型的指针, 因此一个指向 void 类型的指针是没法 ++ 操作的, 因为 void 不是一个有长度的类型.
而 void ** 是指向指针的指针, 它指向一个指针, 任何指针在 32 位下都是 4 bytes(或用unsigned long表示), 因此它是有长度的, 就可以进行 ++ 运算.
void* p = malloc(sizeof(void*));
printf("p+1 Addr: %p\r\n", p+1); //error:c2036
void** q = (void**)malloc(sizeof(void**));
printf("q+1 Addr: %p\r\n", q+1);
*/
void* p = malloc(MIN_PRE_ALLOCATE_NR * sizeof(void*));
printf("%p\r\n", p);
if(NULL != p){
DArray* pDArray = (DArray*)malloc(sizeof(DArray));
void** q = &p;
if(NULL != pDArray){
pDArray->data = q;
pDArray->alloc_size = 0;
pDArray->size = MIN_PRE_ALLOCATE_NR;
printf("%p\r\n", *(pDArray->data)); //打印p的地址
for(i=0; i<10; i++)
{
//printf("p[%d] Addr: %p\r\n", i, p+i); //和下边等效的, void*不能运算!
//printf("(*(Darray.data))[%d] Addr: %p\r\n", i, &((*(pDArray->data))[i]));
//printf("Darray.data[%d] Addr: %p\r\n", i, pDArray->data[i]);//这个对的,void**的pDArray->data可以做运算
}
return pDArray;
}
}
return NULL;
}
以上代码,在运行destroy的时候出错的。下面看第二种理解。
=====================================================================
把DArray.data指针,理解成了由一个二级指针,直接指向10个sizeof(void*)。所以这么写的:
void** p = malloc(10 * (sizeof(void*));
DArray->data = p;
#define MIN_PRE_ALLOCATE_NR 10
void darray_destroy(DArray* thiz)
{
return_if_fail(thiz != NULL);
/*
销毁数组各成员
销毁管理项
*/
free(thiz->data);
free(thiz);
}
DArray* darray_create(DataDestroyFunc data_destroy, void* ctx)
{
/*传入销毁函数,动态的销毁上次使用的darray,重新生成。*/
void** p = NULL;
int i;
if(NULL != ctx)
{
darray_destroy((DArray*)ctx);
}
/*
从delete函数中看到如此操作:pDArray->data[i]
所以这里分配的是10个二级指针,
不是一个二级指针,指向的10个一级指针!【 理解还是错误的,解释见后 】
故而,free的时候,只free这10个二级指针的首地址,就可以了。
而且,不管你是上边的哪种理解也好,free是必须只做一次的!
*/
p = (void**)malloc(MIN_PRE_ALLOCATE_NR * sizeof(void*));
if(NULL != p){
DArray* pDArray = (DArray*)malloc(sizeof(DArray));
if(NULL != pDArray){
pDArray->data = p;
pDArray->alloc_size = 0;
pDArray->size = MIN_PRE_ALLOCATE_NR;
printf("Darray Addr: %p\r\n", pDArray);
printf("&(Darray.data) Addr: %p\r\n", &(pDArray->data));
printf("Darray.data Addr: %p\r\n", pDArray->data);
for(i=0; i<10; i++)
{
printf("p + %d Addr: %p\r\n", i, p + i);
printf("Darray.data + %d Addr: %p\r\n", i, pDArray->data + i);
}
return pDArray;
}
}
return NULL;
}
=====================================================================
刚开始我还理解malloc是分配了十个一级指针,
还有理解成分配了十个二级指针,
都是错的。。。
但,分配的都是十个sizeof(void*)类型空间,你用什么指针指向它,都是可以的。这句是对的。
真正的理解应该是,分配的十个void*空间,每一个空间就都会是void*类型的指针,
当然,分配之后,需要用一个二级指针来指向void*类型一级指针的位置。
错误的理解,主要是被malloc( 10 * sizeof(void*))给迷惑了,
以为是分配了十个一级指针,再由一个二级指针来指向他们;或者是分配了十个二级指针。
强调一下:
分配的空间,如果是存放一级指针的,那么malloc的结果,要二级指针来盯住!
by the way, 我是没见过分配完用二级指针盯住的(指向),一般都是用一级void*指向的。。。
【感觉自己好菜币,还整天浮躁】