wangpengcheng 发表于 2014-8-31 23:30:05

原创:在C语言中大概实现VC++中的CArray部分功能的两种方法

本帖最后由 wangpengcheng 于 2014-9-1 11:16 编辑

经takashiki 同学提醒,我查阅了以前的工程,发现其实我说的动态数组在VC中用的是CArray 类!特此说明,不会误导大家!
同样都是RTT平台上验证过的,呵呵!
ARRAYLIST:动态数组,相当于一个大小可变的结构体数组,比如你有一群结构体需要存储,但是你不知道会有多少,也不知道每个结构体的大小,你就可以用这个类,添加到里面,然后用的时候可以用Index在里查找,相当于一个数组,但可以变长!

方法1:此种方法是在添加或删除数组中的元素时,重新申请大1或者小1的一块内存,然后将原数组拷到新申请的内存中,然后将原来的数组指针替换掉!
#ifndef __LISTARRAY_H__
#define __LISTARRAY_H__
#include "rtthread.h"
#include "finsh.h"
//LIST数组
typedef struct _ListArray ListArray;
struct _ListArray
{
    void **pListPointArray;                         //LIST数组指针
    int Total;                                    //元素个数
    void (*Add)(ListArray *pList, void *pListPoint);   //添加
    void (*Remove)(ListArray *pList, void *pListPoint);//移除
    void (*Delete)(void *pList);                  //析构
};
//List类的析构函数
static void ListDelete(void *pList)
{
    if(((ListArray *)pList)->pListPointArray != RT_NULL)   //先释放指针数组
    {
      rt_free(((ListArray *)pList)->pListPointArray);
    }
    rt_free(pList);                                     //再释放整个List类
}
//元素增加函数
static void ListAdd(ListArray *pList, void *pListPoint)
{
    void **tListPointArray = rt_malloc(sizeof(int *) * (pList->Total + 1));   //申请比原来大一个存储单元的内存
    int pListIndex;
    for(pListIndex = 0; pListIndex < pList->Total; pListIndex++)      //拷贝
    {
      if(pList->pListPointArray == pListPoint)               //判断,如果有相同的元素存在
      {   
            rt_free(tListPointArray);                                        //释放现申请的内存
            return;                                                   //返回
      }
      tListPointArray = pList->pListPointArray;         //拷贝
    }
    tListPointArray = pListPoint;                              //将添加的元素放到最后一个存储单元中
    pList->Total += 1;                                                //总数加1
    if(pList->pListPointArray != RT_NULL) rt_free(pList->pListPointArray);                      //释放原来的内存
    pList->pListPointArray = tListPointArray;                                          //将新的句柄替换原句柄
}
//元素移除函数
static void ListRemove(ListArray *pList, void *pListPoint)
{
    int pListIndex, tListIndex;
    void **tListPointArray;
    void **FreePointArray;
    void **SavePointArray;
    if(pList->Total == 0) return;                                       //总数为0时退出
    tListPointArray = rt_malloc(sizeof(int) * (pList->Total - 1));    //申请比原来小一个存储单元的内存
    FreePointArray = tListPointArray;                                  //将刚申请的内存空间作为默认的释放空间
    SavePointArray = pList->pListPointArray;                           //将已有的内存空间作为默认的存储空间
    for(pListIndex = 0, tListIndex= 0; pListIndex < pList->Total; pListIndex++) //查找移除点
    {
      if(pList->pListPointArray == pListPoint)         //当前点是移除点
      {
            FreePointArray = pList->pListPointArray;            //改变释放内存指针
            SavePointArray = tListPointArray;                   //改变保留内存指针
            continue;                                           //结束本次循环
      }
      if(tListIndex < (pList->Total -1))                      //如果当前点不是移除点,拷贝序号小于总量减1
      {
            tListPointArray = pList->pListPointArray;   //拷贝
            tListIndex++;                                             //拷贝序号加1
      }
    }
    pList->Total = (SavePointArray == tListPointArray) ? pList->Total - 1 : pList->Total;   //根据保留的内存块改变总数的值
    if(FreePointArray != RT_NULL) rt_free(FreePointArray);      //释放该释放的不用的内存块
    pList->pListPointArray = SavePointArray; //保留该保留的
}
//List构造函数
static ListArray *ListCreate(void)
{
    ListArray *pList = (ListArray *)rt_malloc(sizeof(ListArray));
    pList->Total = 0;
    pList->pListPointArray = RT_NULL;
    pList->Add = ListAdd;
    pList->Remove = ListRemove;
    pList->Delete = ListDelete;
    return pList;
}
#endif


方法2:此方法是由方法1发展而来,在方法1中添加了两个参数,一个是SIZE参数,一个是CHANGESIZE参数,SIZE参数是初始化时的数组容量,CHANGESIZE是在数据刚好达到SIZE时将数组容量改变的数组添加或减少的容量。比如初始大小为SIZE,然后当数组增加到SIZE的时候要存储第SIZE + 1个数据的时候就重新申请一块比SIZE大CHANGESIZE的内存,然后再将数据转移进去,将原内存释放,将新内存的指针保存。减少是一个道理的,当减到SIZE的时候,将原尺寸减个CHANGESIZE,然后申请内存,转移数据,释放老内存,保存新指针。

此方法的好处是不用每次都申请、释放内存、转移数据,操作LIST比较频繁的时候,用此方法比用第1种方法在速度上有优势!
#ifndef __LISTARRAY_H__
#define __LISTARRAY_H__
#include "rtthread.h"
#include "finsh.h"

#define LISTDEFAULTSIZE   20
#define LISTCHANGESIZE      10

//LIST数组
typedef struct _List List;
struct _List
{
    void **pListPointArray;                         //LIST数组指针
    int Total;                                    //元素个数
    int ChangeSize;                                 //每次改变容量的时候容量的大小
    int Size;                                       //当前容量
    void (*Add)(List *pList, void *pListPoint);   //添加
    void (*Remove)(List *pList, void *pListPoint);//移除
    void (*Delete)(void *pList);                  //析构
};
//List类的析构函数
static void ListDelete(void *pList)
{
    rt_free(((List *)pList)->pListPointArray);
    rt_free(pList);                                     //再释放整个List类
}
//元素增加函数
static void ListAdd(List *pList, void *pListPoint)
{
    void **tListPointArray;
    if(pList->Size == pList->Total)                     //如果空间已满
    {
      pList->Size = pList->Size + pList->ChangeSize;//改变空间的尺寸
      tListPointArray = rt_malloc(sizeof(int *) * pList->Size);   //重新申请内存
      memcpy(tListPointArray, pList->pListPointArray, sizeof(int *) * pList->Total); //将原内存的数据拷到新内存
      rt_free(pList->pListPointArray);                //释放原空间
      pList->pListPointArray = tListPointArray;       //将新空间指针代替原空间指针
    }
    pList->pListPointArray = pListPoint;         //将添加的元素放到最后一个存储单元中
    pList->Total++;                                     //个数加1
}
//元素移除函数
static void ListRemove(List *pList, void *pListPoint)
{
    int pListIndex, tListIndex;
    void **tListPointArray;
    if(pList->Total == 0) return;                                       //总数为0时退出
    for(pListIndex = 0, tListIndex= 0; pListIndex < pList->Total; pListIndex++) //查找移除点
    {
      if(pList->pListPointArray != pListPoint)         //当前点不是移除点
      {
            pList->pListPointArray = pList->pListPointArray;   //拷贝
            tListIndex++;                                             //拷贝序号加1
      }
    }
    pList->Total = tListIndex;
   
    if(pList->Total <= (pList->Size - pList->ChangeSize))
    {
      pList->Size = pList->Size - pList->ChangeSize;            //改变内存尺寸
      tListPointArray = rt_malloc(sizeof(int *) * pList->Size);    //申请新内存
      memcpy(tListPointArray, pList->pListPointArray, sizeof(int *) * pList->Total);//拷贝数据
      rt_free(pList->pListPointArray);                //释放原空间
      pList->pListPointArray = tListPointArray;       //将新空间指针代替原空间指针
    }
}
//List构造函数
static List *ListCreate(void)
{
    List *pList = (List *)rt_malloc(sizeof(List));
    pList->Total = 0;
    pList->Size = LISTDEFAULTSIZE;
    pList->ChangeSize = LISTCHANGESIZE;
    pList->pListPointArray = rt_malloc(LISTDEFAULTSIZE);
    pList->Add = ListAdd;
    pList->Remove = ListRemove;
    pList->Delete = ListDelete;
    return pList;
}
#endif

cn_x 发表于 2014-9-1 07:06:50

学习一下,现在貌似用不上,楼主一直用rt-thread?

fengyunyu 发表于 2014-9-1 09:06:02

LZ原创帖子技术含量很高!

浪里白条 发表于 2014-9-1 09:13:19

不明觉厉,露珠能简单介绍下LISTARRAY功能是什么意思吗

takashiki 发表于 2014-9-1 09:31:20

被标题吸引来了,我没有见过C++有什么LISTARRAY啊,楼主请简单介绍下,至少说明在那个头文件中,我去看看。
STL标准模板库中,只发现了list和array,和这个完全不同啊。

sunnyqd 发表于 2014-9-1 09:36:11

楼主给力

wangpengcheng 发表于 2014-9-1 09:49:36

cn_x 发表于 2014-9-1 07:06
学习一下,现在貌似用不上,楼主一直用rt-thread?

以前用它做产品,后来换工作了{:titter:}

wangpengcheng 发表于 2014-9-1 09:50:02

fengyunyu 发表于 2014-9-1 09:06
LZ原创帖子技术含量很高!

还行,呵呵!

wangpengcheng 发表于 2014-9-1 09:51:12

浪里白条 发表于 2014-9-1 09:13
不明觉厉,露珠能简单介绍下LISTARRAY功能是什么意思吗

相当于一个大小可变的元素数组!

takashiki 发表于 2014-9-1 10:00:10

wangpengcheng 发表于 2014-9-1 09:51
相当于一个大小可变的元素数组!

不是吧,就这样?
我认为您这个要求alloc、realloc、free函数就足够了,一定还有其他功能,比如神马前插入后插入中间插入删除交换排序等等之类杂七杂八功能的

wangpengcheng 发表于 2014-9-1 10:00:39

takashiki 发表于 2014-9-1 09:31
被标题吸引来了,我没有见过C++有什么LISTARRAY啊,楼主请简单介绍下,至少说明在那个头文件中,我去看看。 ...

呵呵,应该是ARRAYLIST!

wangpengcheng 发表于 2014-9-1 10:04:23

本帖最后由 wangpengcheng 于 2014-9-1 10:20 编辑

takashiki 发表于 2014-9-1 10:00
不是吧,就这样?
我认为您这个要求alloc、realloc、free函数就足够了,一定还有其他功能,比如神马前插 ...

这个是动态数组,呵呵,不是链表!不过相对来说,链表还简单点,发这个也只是让大家了解一下面向对像的编程方式!

sdlibin007 发表于 2014-9-1 10:19:08

先把资料收藏了,用到的时候再来取,谢谢楼主!!

浪里白条 发表于 2014-9-1 10:25:18

wangpengcheng 发表于 2014-9-1 09:51
相当于一个大小可变的元素数组!

感谢讲解,这种东西的用途一般是什么呢?

wangpengcheng 发表于 2014-9-1 10:28:32

浪里白条 发表于 2014-9-1 10:25
感谢讲解,这种东西的用途一般是什么呢?

我当初写的时候是因为项目中有很多相同的临时变量要存起来,到最后做个比较,但我又不知道这些变量会有多少,内存预留的时候有困难,后来就想到VC里面有个ARRAYLIST,就用C模拟了一下,呵呵!

浪里白条 发表于 2014-9-1 10:36:15

wangpengcheng 发表于 2014-9-1 10:28
我当初写的时候是因为项目中有很多相同的临时变量要存起来,到最后做个比较,但我又不知道这些变量会有多 ...

原来如此 ,感谢讲解。

takashiki 发表于 2014-9-1 10:36:52

wangpengcheng 发表于 2014-9-1 10:04
这个是动态数组,呵呵,不是链表!

VC中既也没有ArrayList,也没有ListArray……

好吧,建议楼主看看std::vector的源码,#include <vector>就行,你就知道我说的那些功能不仅仅链表list有,队列queue、deque也是有的,动态数组vector也是有的,但是你的没有。

wangpengcheng 发表于 2014-9-1 10:45:03

takashiki 发表于 2014-9-1 10:36
VC中既也没有ArrayList,也没有ListArray……

好吧,建议楼主看看std::vector的源码,#include 就行,你 ...

VC中肯定是有的,我用过的,看看这个博:
http://www.cnblogs.com/rickie/articles/67978.html

至于我少的一些东西,因为我在做项目的时候没有用到,所以没做到,我也没有真正去研究过他都有多少种FUNCTION,呵呵,要是你有兴趣,可以进行添加,欢迎补充哦!

takashiki 发表于 2014-9-1 10:48:51

wangpengcheng 发表于 2014-9-1 10:45
VC中肯定是有的,我用过的,看看这个博:
http://www.cnblogs.com/rickie/articles/67978.html



不好意思,我不会添加的,因为STL足够用了,而且好用,效率高,占用资源少,在支持C++的编译器中,我优选C++。
另外,他这个是C#的,你移花接木说是VC++是几个意思?

wangpengcheng 发表于 2014-9-1 11:13:47

takashiki 发表于 2014-9-1 10:48
不好意思,我不会添加的,因为STL足够用了,而且好用,效率高,占用资源少,在支持C++的编译器中,我优选 ...

sorry,我刚才查了一下我的工程,我用的是一个CArray的class,没描述清楚,见谅!

didadida 发表于 2014-9-1 11:38:44

有个问题,内部实现做成链表的话,不就省去了重复申请、释放大段儿内存吗?只需要申请、释放一个元素的就行了。而且做成链表的话,也可以用数组下标的形式访问元素啊,因为你有一个指针数组了{:smile:}

wangpengcheng 发表于 2014-9-1 13:06:32

didadida 发表于 2014-9-1 11:38
有个问题,内部实现做成链表的话,不就省去了重复申请、释放大段儿内存吗?只需要申请、释放一个元素的就行 ...

正确,呵呵,那时候不是对链表还没什么研究嘛!

tomhe666 发表于 2014-9-1 13:07:03

didadida 发表于 2014-9-1 11:38
有个问题,内部实现做成链表的话,不就省去了重复申请、释放大段儿内存吗?只需要申请、释放一个元素的就行 ...

嵌入式编程一般都是list, array用的很少,   PC上一般指定个增量SIZE就能解决一半的效率问题,嵌入式的不行, 它的CPU和内存都是很有限的, 不停的move, delete开销巨大

wangpengcheng 发表于 2014-9-1 13:15:28

tomhe666 发表于 2014-9-1 13:07
嵌入式编程一般都是list, array用的很少,   PC上一般指定个增量SIZE就能解决一半的效率问题,嵌入式的不 ...

说的正确,呵呵,当年用的时候是感觉有点慢,但因为机器要求时间不是那么严格,所以就那样了!

didadida 发表于 2014-9-1 14:17:05

tomhe666 发表于 2014-9-1 13:07
嵌入式编程一般都是list, array用的很少,   PC上一般指定个增量SIZE就能解决一半的效率问题,嵌入式的不 ...

呵呵,恩,uC/OS都是用的静态的数组

jiangkexiaozhen 发表于 2014-9-1 21:13:21

C的很多技巧都是用不上的

cn_x 发表于 2014-9-1 21:21:50

认真看一遍先,RTOS 总归要用的

wangpengcheng 发表于 2014-9-1 21:24:21

cn_x 发表于 2014-9-1 21:21
认真看一遍先,RTOS 总归要用的

这个是RT_Thread系统,不是RTOS,呵呵,上海几个大牛开发的!

rockyyangyang 发表于 2014-9-4 14:57:22

mark   代码风格很好。最近发现自己的C水平很不足,想恶补一下C,提高一下水平。

wangpengcheng 发表于 2014-9-4 15:18:02

rockyyangyang 发表于 2014-9-4 14:57
mark   代码风格很好。最近发现自己的C水平很不足,想恶补一下C,提高一下水平。 ...

多看看别人写的代码,跑跑系统,会了解到更多!

rockyyangyang 发表于 2014-9-4 15:47:35

wangpengcheng 发表于 2014-9-4 15:18
多看看别人写的代码,跑跑系统,会了解到更多!

现在的水平智能叫熟悉。看别人的代码,我最近也是正在看!系统自己还是差得远,暂时没考虑,先把语言学好在说。
关于系统,我想从LINUX的应用开始做起,你觉得OK 吗?

dongyanbo 发表于 2014-9-4 15:53:09

技术贴,mark学习

wangpengcheng 发表于 2014-9-4 16:07:46

rockyyangyang 发表于 2014-9-4 15:47
现在的水平智能叫熟悉。看别人的代码,我最近也是正在看!系统自己还是差得远,暂时没考虑,先把语言学好 ...

哪个系统都无所谓,主要是先能用起来,跑起来,自己做几个任务试试,了解它的机制!后面再深入看他内部的一些概念!

rockyyangyang 发表于 2014-9-4 16:14:13

wangpengcheng 发表于 2014-9-4 16:07
哪个系统都无所谓,主要是先能用起来,跑起来,自己做几个任务试试,了解它的机制!后面再深入看他内部的 ...

恩恩,谢谢你的指导。
页: [1]
查看完整版本: 原创:在C语言中大概实现VC++中的CArray部分功能的两种方法