spool利用pool来方便处理动态增长的字符串,spool维护一个单向链表,每追加一个字符串对应链表一个节点,这样的好处是可以很快速的追加新的字符串,而不需要使用realloc来动态扩展内存空间。只有当需要使用完整的字符串的时候,才动态分配一个大的内存空间,来合并链表中的所有节点。
传统的动态增长字符串的处理中一般都是预先分配比较大的内存空间,每次追加新字符串的时候,判断剩余内存是否够用,如果不够,需要使用realloc重新分配或者扩展内存大小。realloc如果是需要重新分配新的内存地址的时候,这时需要将”旧内存地址“里的数据拷贝到”新内存地址“。虽然使用预先分配比较大内存的做法可以减少reallloc的次数,但也会浪费一些内存空间。 spool每次追加新字符串的时候并不是真正插入到原字符串中,而是使用一个链表将每次追加的数据以链表一个节点形式插入,这样可以避免使用realloc来扩展内存空间。仅仅在使用该字符串的时候才将链表中的所有节点合并成一个大的字符串。可以看到spool这个特性,在需要频繁的追加新字符串的场合比传统需要realloc扩展空间的方法要高效的多。 下面我们来分析一下spool的数据结构和API:/* --------------------------------------------------------- *//* *//* String pools (spool) functions *//* *//* --------------------------------------------------------- */
//链表中的节点数据结构struct spool_node{
//用来保存追加的字符串指针
char *c;
//指向下一个节点的指针 struct spool_node *next;};
typedef struct spool_struct{
//spool_new传进来的参数,spool维护的内存都是从这里分配的 pool_t p;
//所有字符串的总长度 int len;
//链表最后一个节点指针,新节点都是插入到尾部 struct spool_node *last;
//链表中第一个节点指针 struct spool_node *first;} *spool;
API:spool spool_new(pool_t p)
从现有的pool_t中分配一个新的spool空结构体void spool_add(spool s, char *str)
创建一个spool_node将spool_node->c指向str, 将spool_node插入到spool的末尾。void spool_escape(spool s, char *raw, int len)
和spool_add类似,当spool_escape将raw中特殊字符转义后插入到spool中。 转义字符为:& ' " < > 5个字符,被转义成:& ' " < >char *spool_print(spool s)
将spool链表中保存的字符串,转换成一个字符串。返回的字符串的内存时从pool中分配的,不需要单独释放内存,可以由pool_free统一释放内存。void spooler(spool s, ...)
变长参数,将每个char*参数按照顺序添加到spool中。char *spools(pool_t p, ...)
每个char*参数合并起来生成一个大的字符串。