SDS(simple dynamic string 简单动态字符串)
struct sdshdr{
//记录buf数组中已使用字节的数量
//等于sds所保存字符串的长度
int len;
//记录buf数组中未使用字节的数量
int free;
//字节数组,用于保存字符串
char buf[];
}
SDS与C字符串的区别:
SDS | C字符串 | |
获取字符串长度 | 复杂度O(1) 直接读取len |
复杂度O(N) 遍历整个字符串 |
缓冲区溢出 | API是安全的,不会造成缓冲区溢出。 具体: 当SDS API需要对SDS进行修改时,API会先检查SDS的空间是否满足修改所需的要求,如果不满足的话,API会自动将SDS的空间扩展至执行修改所需的大小,然后才执行实际的修改操作。 |
API是不安全的,可能会造成缓存区溢出。 具体: 因为C字符串不记录自身的长度,所以strcat假定用户在执行这个函数时,已经为要拼接的字符串分配了足够的内存。 例:s1字符串分配内存不够,拼接s2字符串会造内存溢出。所以需要注意s1的内存是否分配的足够多。 |
内存重分配次数 | 修改字符串N次最多需要执行N次内存重分配。 具体: 减少修改字符串时带来的内存重分配次数 1、空间预分配 对SDS修改后,SDS的长度(即len属性的值) (1)将小于1MB,那么程序分配和len属性同样大小的未使用空间,即len=free。例: sds修改后长度变为13byte,那么len=free=13,该buf数组的实际长度为13+13+1=27。1为结束字符。 (2)将大于等于1MB,那么程序会分配1MB的未使用空间。例:sds修改后长度变为30MB,该buf数组的实际长度为30MB+1MB+1byte。 2、惰性空间释放 惰性空间释放用于优化SDS的字符串缩短操作:当SDS的API需要缩短SDS保存的字符串时,程序并不立即使用内存重分配来回收缩短后多出来的字节,而是使用free属性将这些字节的数量记录起来,并等待使用。 |
修改字符串N次必然执行N次内存重分配。 |
二进制安全 | 可以保存文本或者二进制数据。 SDS API都会以处理二进制的方式来处理。SDS存放在buf数组里的数据,程序不会对其中的数据做任何限制、过滤、假设,数据在写入时时什么样的,他被读取时就是什么样。所以称buf数组为字节数组,不是用来保存字符,而是用它来保存一系列二进制数据。 |
只能保存文本数据。 C字符串中的字符必须符合某种编码(比如ASCII),并且除了字符串的末尾之外,字符串里面不能包含空字符,否则最先被程序读入的空字符被误认为是字符串结尾,这些限制使得C字符串只能保存文本数据,不能保存像图片、音频、视频、压缩文件这样的二进制数据。 |
C字符串函数 | 可以使用一部分 兼容部分C字符串函数。 SDS遵循C字符串以空字符串结尾的惯例,以便可以重用一部分 |
可以使用所有 |
总结,与C字符串相比,SDS具有以下优点:
1、常数复杂度获取字符串长度。 O(1)
2、杜绝缓冲区溢出。 自动扩展
3、减少修改字符串长度时所需的内存重分配次数。 (1)空间预分配(2)惰性空间释放
4、二进制安全。 buf数组保存二进制数据,而不是字符
5、兼容部分C字符串函数。 可以使用一部分