系统程序员成长计划007第三章动态数组 --create和destroy(二级指针理解)

一、首先说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*指向的。。。

 

 【感觉自己好菜币,还整天浮躁】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值