C 语言泛型Array数组封装

    以前,写过一个C 语言泛型数组实现,但在实际的使用过程中,发现了更加易用的模式,进行了改进。这个数组封装作为一个最基础的结构,在此之上实现了动态数组,队列,数组映射等。还利用这些数据结构实现了一个简单的json解析器,已经成为C工具箱的最基础工具,可以验证这些结构的可用性和稳定性,以后将逐步介绍。

   

    这个泛型数组分为代码实现和宏定义两部分,主要完成以下功能。

  • 可存储任意数据类型数据
  • 带有数据长度
  • 一套便捷使用的宏定义接口
  • 可以在堆上,也可以在栈上使用


    首先看代码实现部分,非常的简单。

typedef struct
{
	/** Elements memory data */
	void* data;
	/** Elements count */
	int   length;
}
Array;


typedef struct
{
	/**
	 * Array space and data space in one malloc
	 * Array data hold the offset of malloc return address
	 */
	Array* (*Create)(int typeSize, int length);
}
_AArray_;

extern _AArray_ AArray[1];

static Array* Create(int typeSize, int length)
{
	Array* array  = (Array*) malloc(sizeof(Array) + typeSize * length);
	array->data   = (char*) array + sizeof(Array);
	array->length = length;

	return array;
}

_AArray_ AArray[1] =
{
	Create,
};

   Create是在堆上分配空间,这里我们采用了折叠空间的方法,是的Array本身的空间和元素的空间一次性分配,用过data指针持有元素空间的偏移地址。这样的好处就是分配和释放只需要一次。


    然后,是一组宏定义的访问接口。
    
/** The type is the array element type */
#define Array(type) Array

/**
 * The type is element type
 */
#define AArray_GetData(array, type) \
	(type*) ((array)->data)

/**
 * return element
 */
#define AArray_Get(array, index, type) \
	(AArray_GetData(array, type))[index]

/**
 * return element ptr
 */
#define AArray_GetPtr(array, index, type) \
	(AArray_GetData(array, type) + index)

/**
 * set element
 */
#define AArray_Set(array, index, element, type) \
	AArray_Get(array, index, type) = element

    
    标示性宏定义  #define Array(type) Array 的意义就是在定义的时候,可以明确Array元素的类型,虽然编译器没有像泛型那样的类型检查,但C中可以增加可读性。然后就是一组对元素的get,set访问方法。那么,Get和GetPtr的区别就在于。元素是指针的时候Get返回指针,元素是结构对象的时候Get回返回对象,这样会产生栈上的结构对象复制。而这个时候使用GetPtr能获得元素对象的指针,不会复制元素对象的结构内容。


   特别介绍两个宏定义。
   
/**
 * Create Array composite literal
 */
#define AArray_Create(type, length, ...) \
	(Array[1])                           \
	{                                    \
		(type[length]) { __VA_ARGS__ },  \
		length,                          \
	}

/**
 * Init constant Array
 */
#define AArray_Init(type, length, ...)  \
	{                                   \
		(type[length]) { __VA_ARGS__ }, \
		length,                         \
	}

     这两个宏定义,都是在栈上分配数组空间并初始化。使用了C99变参宏替换,这样数组元素可以传入变参数据。另外,第一个使用了C99的 复合字面量。这两个定义的使用区别在于,第一个可以赋值给变量,第二个是在结构对象定义中嵌入字面量。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第1章向读者介绍数据结构作为数据集合的概念。介绍线性和非线性集合的概念。示范说明了Collection类。本章还介绍泛型编程的概念。泛型编程允许程序员编写一个类或一种方法,并且把它用于众多数据类型。泛型编程是C#语言一种重要的新特性(在C#2.0以及更高版本中可用)。这种特性是如此重要以至于在System.Collections.Generic命名空间中存在一个专门的泛型数据结构库。当数据结构具有在此库中能找到的泛型实现时,就会讨论它的用途。本章结尾处介绍了衡量书中讨论的数据结构与算法性能的方法。 第2章提供了数组构造方法的回顾,并连同示例说明了Array类的特征。Array类把许多与数组相关的函数(UBound函数、LBound函数等等)封装到单独一个包中。ArrayLists是数组的一种特殊类型,它支持动态地调整容量。 第3章是对基础排序算法的介绍,例如冒泡排序和插入排序。而第4章则研究了用于内存查找的最基本算法,顺序查找和二叉查找。 第5章探讨了两种经典的数据结构:堆栈和队列。本章节强调的重点是这些数据结构在解决日常数据处理问题中的实际应用。第6章讲述了BitArray类。这种类可以用于有效地表示大量整数值,比如测试成绩。 数据结构的书中通常不包含字符串,但是第7章介绍了字符串、String类和StringBuilder类。这是因为在C#语言中许多的数据处理是在字符串上执行的,读者应该接触基于这两种类的特殊方法。第8章分析了用于文本处理和模式匹配的正则表达式的使用。与较传统的字符串函数和方法相比,正则表达式常常会提供更强大更有效的处理。 第9章向读者介绍作为数据结构的字典的使用。字典和基于字典的不同数据结构把数据作为键/值对来存储。本章向读者说明了如何创建基于DictionaryBase类的他或她自己的类。DictionaryBase类是一个抽象类。第10章包括散列表和HashTable类。HashTable类是字典的一种特殊类型,它用散列算法对内部数据进行存储。 链表作为另外一种经典的数据结构是在第11章介绍。链表在C#语言中不像在C++这样基于指针的语言中那样重要,但是它始终在C#编程中发挥作用。第12章为读者介绍另一种经典数据结构——二叉树。二叉查找树作为二叉树的特殊类型将是本章的主要内容。其他二叉树类型在第15章进行介绍。 第13章向读者说明在集合中存储数据的方法。这种方法在数据结构只存储唯一数据值的情况下是很实用的。第14章涵盖了高级排序算法,包括流行且高效的快速排序算法。此算法是大多数在.NET框架库中实现的排序程序的基础。第15章会看到三种数据结构。在无法使用二叉查找树的时候,这三种数据结构证明对查找是很有用的。他们是:AVL树、红黑树和跳跃表。 第16章讨论了图以及图的算法。图在表示许多不同的数据类型时非常有用,特别是网络的情况。最后,第17章向读者介绍真正的算法设计技巧是什么:动态算法和贪心算法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值