Linux/Centos: 开源库uthash第五弹utarray.h

文章目录

 

一、简介

1.1 介绍

utarray.h中包含了一组用于C结构体的通用array宏。使用起来非常简单,只需要将utarray.h拷贝到你的项目,并包含进你的源码即可:

#include "utarray.h"

动态array支持基本的array操作:push、pop和erase。array的元素可以是任何基本类型或者符合的结构体类型。

动态array内部通过一个连续的内存区域来实现,这个内存区域将会根据push的数据内容,通过realloc方法增长。

1.2 源码获取

utarray.h的源码可以在GitHub上直接获取(src/utarray.h):

https://github.com/troydhanson/uthash

二、使用方法

2.1 声明

不管元素的数据类型怎样,utarray.h本身使用的数据类型是UT_array:

UT_array *nums;

2.2 new and free

接下来是创建array,当我们使用完之后,还需要释放:

utarray_new
utarray_free

utarray_free将会释放包括内部的所有元素。

2.3 push and pop

utarray.h核心的功能是提供了内部元素的:push、pop和iterate操作。

三、元素

使用整数或字符串类型作为元素,是动态array最简单的例子。

3.1 整数

下面的例子使用整数push了0 ~ 9到array,然后打印,最后free。

#include <stdio.h>
#include "utarray.h"

int main() {
  UT_array *nums;
  int i, *p;

  utarray_new(nums,&ut_int_icd);
  for(i=0; i < 10; i++) utarray_push_back(nums,&i);

  for(p=(int*)utarray_front(nums);
      p!=NULL;
      p=(int*)utarray_next(nums,p)) {
    printf("%d\n",*p);
  }

  utarray_free(nums);

  return 0;
}

utarray_push_back的第二个参数必须是指向元素类型的指针。

3.2 字符串

下面实例创建了一个字符串array,然后push两个字符串,然后打印,最后free。

#include <stdio.h>
#include "utarray.h"

int main() {
  UT_array *strs;
  char *s, **p;

  utarray_new(strs,&ut_str_icd);

  s = "hello"; utarray_push_back(strs, &s);
  s = "world"; utarray_push_back(strs, &s);
  p = NULL;
  while ( (p=(char**)utarray_next(strs,p))) {
    printf("%s\n",*p);
  }

  utarray_free(strs);

  return 0;
}

在本例中,由于元素类型是char *,因此我们传入的参数为char **。

注意:push操作会导致源字符串到array的拷贝动作。

3.3 关于UT_icd

utarray.h不仅仅支持整数和字符串,还支持其他任何类型的元素。除了整形和字符串类型外,你需要定义一个UT_icd帮助结构体,它包含utarray用到的初始化、拷贝和释放等操作。

typedef struct {
    size_t sz;
    init_f *init;
    ctor_f *copy;
    dtor_f *dtor;
}

其中init、copy和dtor函数指针的原型如下:

typedef void (ctor_f)(void *dst, const void *src);
typedef void (dtor_f)(void *elt);
typedef void (init_f)(void *elt);
  • sz:是需要保存到array的元素的大小;
  • init:函数指针,该函数将会在utarray需要初始化一个空元素时被调用。这是utarray_resize或utarray_extend_back操作的副产品;如果init为NULL,那么元素的所有值将会默认用memset设置为0;
  • copy:函数指针,该函数用于元素被push进array时被调用,比如utarray_push_back、utarray_insert、utarray_inserta和utarray_concat;如果copy为NULL,将会默认默认用memcpy按位进行拷贝;
  • dtor:函数指针,该函数用于元素从array中移除时被调用,比如utarray_resize、utarray_pop_back、utarray_erase、utarray_clear、utarray_done和utarray_free;如果元素不需要释放资源,则dtor可以设为NULL。

3.3.1 标准数据类型

下面的例子,使用UT_icd的默认方法,来使用C语言的其他标准类型,比如这里是long。

/* long elements */
#include <stdio.h>
#include "utarray.h"

UT_icd long_icd = {sizeof(long), NULL, NULL, NULL };

int main() {
  UT_array *nums;
  long l, *p;
  utarray_new(nums, &long_icd);

  l=1; utarray_push_back(nums, &l);
  l=2; utarray_push_back(nums, &l);

  p=NULL;
  while( (p=(long*)utarray_next(nums,p))) printf("%ld\n", *p);

  utarray_free(nums);
  return 0;
}

3.3.2 自定义结构体

用户自定义的结构体也可以作为utarray的元素。如果自定义数据结构不需要特别的初始化、拷贝和释放处理,我们可以使用UT_icd的默认方法;但如果有自己的特殊操作,则需要自行定义对应的方法。

/* structure type */
#include <stdio.h>
#include "utarray.h"

typedef struct {
    int a;
    int b;
} intpair_t;

UT_icd intpair_icd = {sizeof(intpair_t), NULL, NULL, NULL};

int main() {

  UT_array *pairs;
  intpair_t ip, *p;
  utarray_new(pairs,&intpair_icd);

  ip.a=1;  ip.b=2;  utarray_push_back(pairs, &ip);
  ip.a=10; ip.b=20; utarray_push_back(pairs, &ip);

  for(p=(intpair_t*)utarray_front(pairs);
      p!=NULL;
      p=(intpair_t*)utarray_next(pairs,p)) {
    printf("%d %d\n", p->a, p->b);
  }

  utarray_free(pairs);
  return 0;
}

在实际的使用中,我们的结构体是需要有特殊的初始化、拷贝和释放函数的。比如,当我们的结构体包含一个指针指向另外一块区域的时候,我们就需要自定义UT_icd中对应的init、copy和dtor方法了。

这里用到了两个概念:

  • 浅拷贝:只是拷贝结构体中的内容;
  • 深拷贝:将结构体与结构体指针成员指向的所有内存全部拷贝。

下面是一个实现深拷贝的实例:定义了一个整形和字符串数据,初始化时分配字符串内容,拷贝的时候拷贝字符串内容,释放的时候也要释放字符串的内容。

#include <stdio.h>
#include <stdlib.h>
#include "utarray.h"

typedef struct {
    int a;
    char *s;
} intchar_t;

void intchar_copy(void *_dst, const void *_src) {
  intchar_t *dst = (intchar_t*)_dst, *src = (intchar_t*)_src;
  dst->a = src->a;
  dst->s = src->s ? strdup(src->s) : NULL;
}

void intchar_dtor(void *_elt) {
  intchar_t *elt = (intchar_t*)_elt;
  if (elt->s) free(elt->s);
}

UT_icd intchar_icd = {sizeof(intchar_t), NULL, intchar_copy, intchar_dtor};

int main() {
  UT_array *intchars;
  intchar_t ic, *p;
  utarray_new(intchars, &intchar_icd);

  ic.a=1; ic.s="hello"; utarray_push_back(intchars, &ic);
  ic.a=2; ic.s="world"; utarray_push_back(intchars, &ic);

  p=NULL;
  while( (p=(intchar_t*)utarray_next(intchars,p))) {
    printf("%d %s\n", p->a, (p->s ? p->s : "null"));
  }

  utarray_free(intchars);
  return 0;
}

四、引用

下表列出了utarray常用的操作宏,所有方法类似于C++的vector类。

Operationsdescription
utarray_new(UT_array *a, UT_icd *icd)allocate a new array
utarray_free(UT_array *a)free an allocated array
utarray_init(UT_array *a,UT_icd *icd)init an array (non-alloc)
utarray_done(UT_array *a)dispose of an array (non-allocd)
utarray_reserve(UT_array *a,int n)ensure space available for n more elements
utarray_push_back(UT_array *a,void *p)push element p onto a
utarray_pop_back(UT_array *a)pop last element from a
utarray_extend_back(UT_array *a)push empty element onto a
utarray_len(UT_array *a)get length of a
utarray_eltptr(UT_array *a,int j)get pointer of element from index
utarray_eltidx(UT_array *a,void *e)get index of element from pointer
utarray_insert(UT_array *a,void *p, int j)insert element p to index j
utarray_inserta(UT_array *a,UT_array *w, int j)insert array w into array a at index j
utarray_resize(UT_array *dst,int num)extend or shrink array to num elements
utarray_concat(UT_array *dst,UT_array *src)copy src to end of dst array
utarray_erase(UT_array *a,int pos,int len)remove len elements from a[pos]…a[pos+len-1]
utarray_clear(UT_array *a)clear all elements from a, setting its length to zero
utarray_sort(UT_array *a,cmpfcn *cmp)sort elements of a using comparison function
utarray_find(UT_array *a,void *v, cmpfcn *cmp)find element v in utarray (must be sorted)
utarray_front(UT_array *a)get first element of a
utarray_next(UT_array *a,void *e)get element of a following e (front if e is NULL)
utarray_prev(UT_array *a,void *e)get element of a before e (back if e is NULL)
utarray_back(UT_array *a)get last element of a

五、注意

  1. utarray_new和utarray_free用于分配和释放一个array;然而utarray_init和utarray_down是在UT_array已经分配之后,用于初始化和释放内部结构的资源;
  2. utarray_reserve takes the “delta” of elements to reserve(not the total desired capacity of the array-- this differs from the C++ STL “reserve” notion);
  3. utarray_sort expects a comparison function having the usual strcmp -like convention where it accepts two elements (a and b) and returns a negative value if a precedes b, 0 if a and b sort equally, and positive if b precedes a. This is an example of a comparison function:
int intsort(const void *a, const void *b) {
    int _a = *(const int *)a;
    int _b = *(const int *)b;
    return (_a < _b) ? -1 : (_a > _b);
}
  1. utarray_find uses a binary search to locate an element having a certain value according to the given comparison function. The utarray must be first sorted using the same comparison function. An example of using utarray_find with a utarray of strings is included in tests/test61.c.

  2. A pointer to a particular element (obtained using utarray_eltptr or utarray_front, utarray_next, utarray_prev, utarray_back) becomes invalid whenever another element is inserted into the utarray. This is because the internal memory management may need to realloc the element storage to a new address. For this reason, it’s usually better to refer to an element by its integer index in code whose duration may include element insertion.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值