设为首页 加入收藏

TOP

C语言编程笔记丨SDS:一个简易动态字符串库(四)
2019-04-01 22:08:12 】 浏览:414
Tags:语言编程 笔记 SDS 一个 简易 动态 字符串
*s, int len, const char *sep, int seplen, int *count);void sdsfreesplitres(sds *tokens, int count);

和往常一样,这个函数可以处理SDS字符串和普通的C字符串。头两个参数slen指定了要单元化的字符串,另两个字符串sepseplen是在单元化过程中用到的分割符。最后的参数count是一个整数指针,会被设为返回的单元(子字符串)的数目。

返回值是一个在堆上分配的SDS字符串数组。

sds *tokens;int count, j;

sds line = sdsnew("Hello World!");tokens = sdssplitlen(line,sdslen(line)," ",1,&count);

for (j = 0; j < count; j++)

    printf("%s\n", tokens[j]);sdsfreesplitres(tokens,count);

output> Hellooutput> World!

返回的数组是在堆上分配的,并且数组的单个元素是普通的SDS字符串。在例子中,你可以通过调用sdsfreesplitres()释放所有资源。你也可以选择用free函数自行释放数组,或者像通常那样释放单独的SDS字符串。

合理的方法是用某种方式将你会重用的数组元素设置为NULL,并且用sdsfreesplitres()来释放其余所有的数组。

面向命令行的单元化

用分割符分割字符串是很有用的操作,但是对于执行最常见的涉及到重要的字符串操作,即为程序实现命令行接口来说,通常还是不够的。

这是为什么SDS也提供一个额外的函数,允许你将用户由键盘交互式输入,或者通过一个文件、网络或者其他任何方式的参数,分割成单元。

sds *sdssplitargs(const char *line, int *argc);

sdssplitargs函数返回一个SDS字符串数组,就像sdssplitlen()一样。释放结构的函数sdsfreesplitres(),也是一样的。不同在于执行单元化的方式。

例如,如果输入下面一行:

call "Sabrina"    and "Mark Smith\n"

函数会返回下面的标记(token):

“call”

“Sabrina”

“and”

“Mark Smith\n”

基本上,不同的标记要被一个或多个空格分割,每一个标记也可以是一个sdscatrepr()可以发出的相同格式的引用字符串。

字符串结合(Joining)

有两个函数做与单元化相反的工作,将字符串结合成一个。

sds sdsjoin(char **argv, int argc, char *sep, size_t seplen);sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen);

这两个函数取一个长度为argc的字符串数组,一个分割符及其长度作为输入,产生一个由所有被输入分割符分割的输入字符串所组成的SDS字符串。

sdsjoin()sdsjoinsds()不同点在于前者接收C空字符终结的字符串作为输入,而后者要求所有数组里的字符串须为SDS字符串。但是也因为这个原因,只有sdsjoinsds()能够处理二进制数据

char *tokens[3] = {"foo","bar","zap"};sds s = sdsjoin(tokens,3,"|",1);printf("%s\n", s);

output> foo|bar|zap

错误处理

所有返回SDS指针的SDS函数,在内存不足的情况下,也有可能返回NULL,基本上这是唯一需要你进行检查的地方。

但是许多现代的C程序处理内存不足时,只会简单地中止程序,所以可能你也会需要通过包装malloc,直接调用其他相关的内存分配函数来处理这种情况。

SDS本质和进阶用法

在本篇开始时,解释了SDS字符串是如何被分配的,但是只涉及到保存在返回用户的指针之前的前缀,被当作一个字符串头(header)而已,没有更深入的细节。为了了解进阶的用法,最好挖掘更多SDS的本质,看看实现它所用到的结构体:

struct sdshdr {

    int len;

    int free;

    char buf[];};

如你所见,这个结构体可能与某个传统的字符串库类似,但是结构体的buf域是不同的,因为它不是一个指针,而是一个没有声明任何长度的数组,所以buf实际上指向了紧跟叫free的整数后的第一个字节。所以为了创建一个SDS字符串,我们只要分配一片内存,其大小为sdshdr结构体加上我们的字符串长度,外加一个额外的字节,这是为了所有SDS字符串硬性需要的空字符。

结构体的len域显而易见,就是当前的SDS字符串的长度,每当字符串被通过SDS函数调用修改时,总是会被重新计算。而free域表示了在当前分配空间中的空闲内存的数量,可以被用来存储更多的字符。

所以实际的SDS内存分布是这个:

+------------+------------------------+-----------+---------------\

| Len | Free | H E L L O W O R L D \n | Null term |  Free space   \

+------------+------------------------+-----------+---------------\

             |

             Pointer returned to the user.

你可能要问,为什么在字符串末尾会有一些空闲空间,这看上去是浪费。实际上,在一个新的SDS字符串创建后,之后是没有任何空闲空间的:分配空间小到只需要保存字符串头、字符串和空终结符。然而,其他的访问模式会在末尾创建一些额外的空闲空间,如下面的程序:

s = sdsempty();s = sdscat(s,"foo");s = sdscat(s,"bar");s = sdscat(s,"123");

因为SDS致力于高效,它负担不起在每次添加新数据时,重新分配字符串,因为这会非常的低效,所以会使用每次你扩大字符串时,预分配一些空闲空间。

所使用的预分配算法如下:每次字符串为了保存更多的字节而被重新分配时,实际进行分配的大小是最小需求的两倍。例如,如果字符串现在保存了30个字节,我们多连接2个字节,SDS总共会分配64个字节,而非32个。

然而,可进行分配的空间有一个硬性限制,被定义为SDS_MAX_PREALLOC。SDS绝不会分配超过1MB的额外空间(默认的,你可以修改这个默认值)。

缩减字符串

sds sdsRemoveFreeSpace(sds s);size_t sdsAllocSize(sds s);

有时,有一类程序要求使用非常少的内存。字符串连接、裁剪、取

首页 上一页 1 2 3 4 5 下一页 尾页 4/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇C++编程丨C++11的指针 下一篇第一章:UNIX基础知识

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目