c++判断一个字符串里面有特殊符号_简单动态字符串(SDS)
一,何谓 SDS
SDS(Simple Dynamic String)在 Redis 中被定义为一个结构
structsdshdr{intlen;// 记录 buf 数组中已使用字节的数量,等于 SDS 所保存字符串的长度intfree;// 记录 buf 数组中未使用字节的数量charbuf[];// 字节数组,用于保存字符串}
SDS 示例
free 属性值为0,表示这个 SDS 没有分配任何未使用的空间;
len 属性值为5,表示这个 SDS 保存了一个五字节长的字符串;
buf 数值是一个 char 类型的数组,数组前五个字节分别保存了 'R','e','d','i','s' 五个字符,而最后一个字节则保存了一个空字符;
二,SDS 与 C 字符串的区别
根据传统,C 语言使用长度为 N +1 的字符数组来表示长度为 N 的字符串,并且字符数组的最后一个元素总是空字符 '\0';
2.1 获取字符串的长度
C 语言中获取字符串的长度,需要程序遍历整个字符串,直到遇到代表字符串结尾的空字符为止,这个操作的复杂度为O(N);比如,如果想获取字符串 "Redis" 的长度,在 C 中是按照如下过程操作的。
与 C 语言不同的是,SDS 中有一个属性 len,专门用于记录字符串的属性,并且该属性值是由 SDS API 自动计算完成的,我们在使用时只需去读取该值即可。这样复杂度就变为 O(1);比如获取字符串 "hello,world" 的长度只需读取 len 属性即可。
小结:就获取字符串的长度而言, SDS 显然比 C 更具优势。
2.2 杜绝缓冲区溢出
举例,char *strcat(char *dest, const char *src) 是 C 语言中的函数,用于将 src 字符串拼接到 dest 字符串的末尾,因为 C 字符串不记录自身的 长度,所以 strcat 假定用户在执行这个函数时,已经为 dest 分配了足够多的内存,可以容纳 src 字符串中的所有内容,而一旦这个假设不成立时就会产生缓存溢出。假设有两个在内存中紧邻的C字符串 s1 和 s2,其中 s1 保存了字符串 "Redis",而 s2 保存了字符串 "MongoDB",如图所示:
如果用户在未提前分配内存的情况下执行 strcat(s1, " Cluster") ,那么将会导致 s1 的数据溢出到 s2 所在的内存空间中,导致 s2 的数据被修改;
针对上面可能造成的问题,SDS 做了如下修改:当 SDS API 需要对 SDS 进行修改时,API 会先检查 SDS 的空间会否满足所需,不满足情况下 API 会自动将 SDS 的空间扩展至执行修改所需的大小,然后才执行实际的修改操作。这样在不需要用户自己操作的情况下避免了内存溢出的发生。
2.3 操作字符串时的内存分配策略
C 语言中对字符串的增减都需要对这个字符串数组进行内存重新分配。如果是增长字符串的操作,那么在操作之前,需要先通过内存重分配来扩展底层数组的大小,否则就会产生缓冲区溢出。如果是缩短字符串的操作,那么在操作之前,需要先通过内存重新分配来释放不再使用的那部分空间,否则就会产生内存泄漏。因为内存的重新分配涉及复杂的算法,并且可能需要执行系统调用,所以它通常是一个比较耗时的操作。在一般程序中,如果修改字符串的长度的情况不太常见,那么每次修改就执行一次内存重分配是可以接受的。但是 Redis 作为数据库,数据被频繁修改是很常见的,此时如果每次都执行内存重新分配的话,将会对性能造成不小的影响。为了避免 C 中的上述缺陷,SDS 定义了未使用空间属性。在 SDS 中,buf 数组的长度不一定就是字符数量 + 1,数组里面可以包含未使用的字节,而这些未使用的字节数量就由 SDS 的 free 属性记录。基于该属性 SDS 实现了空间预分配和惰性分配空间释放两种优化策略。
2.3.1. 空间预分配
当 SDS 字符串增长时,SDS 的 API 不仅会为 SDS 分配修改所必须要的空间,还会为 SDS 分配额外的未使用空间。如果对 SDS 进行修改后,SDS 的 len 小于 1MB,那么程序将会分配和 len 属性同样大小的未使用空间即 free = len,buf 的实际长度将是 len + free + 1;如果对 SDS 修改之后的长度大于等于 1MB,那么程序将会分配 1MB 的未使用空间。此时 buf 的实际长度是 len + 1MB + 1byte。通过这种分配策略,SDS 将连续增长 N 次字符串所需要的内存重分配次数从必定 N 次降为 最多 N 次。
2.3.2 惰性空间释放
当 SDS 字符串缩短时,SDS 的 API 不会立即使用内存重分配来回收缩短后多出来的字节,而是使用 free 属性将这些字节的数量记录下来,并等待将来使用。举例,将长度为 11 个字符的字符串 "XYXaYYbcXYY" 中的 "X" 和 "Y" 字符全部去掉;
执行完缩短操作之后的结果如图所示:
可知,SDS 并没有释放因为去掉 "X" 和 "Y" 所多出来的 8 字节空间,而是将这 8 字节空间作为未使用空间保留在了 SDS 里面,如果将来对 SDS 进行增长操作的话,可以直接使用这些未使用空间。为了避免惰性空间释放策略造成的内存浪费,SDS 提供了相应的 API,让我们在需要时通过这些 API 释放未使用的空间。
2.4 二进制安全
C 中字符编码必须符合某种编码(比如ASCII),并且除了字符串的末尾之外,字符串里面不能包含空字符,因为 C 语言中默认以 \0 作为字符串的结尾。这使得 C 字符串只能用来保存文本数据,而像图片,音频,视频,压缩文件等这样的二进制数据则不能被保存。而 SDS 中判断字符串是否结束的标志是 len 属性而不是 \0,这使得 Redis 可以存储任何二进制数据。
2.5 总结
C 字符串 | SDS |
获取字符串长度的复杂度为 O(N) | 获取字符串长度的复杂度为 O(1) |
API 不安全,可能造成缓存区溢出 | API 是安全的,不会造成缓存区溢出 |
修改 N 次字符串必然需要 N 次内存重新分配 | 修改 N 次字符串最对需要 N 次内存重新分配 |
只能保存文本数据 | 可以保存文本数据或二进制数据 |
可以使用中的所有函数 | 可以使用中的部分函数 |
2020年10月28日于将台
c++判断一个字符串里面有特殊符号_简单动态字符串(SDS)相关推荐
- c语言追加字符串_Redis源码解析二--简单动态字符串
Redis 简单动态字符串 1.介绍 Redis兼容传统的C语言字符串类型,但没有直接使用C语言的传统的字符串(以'0'结尾的字符数组)表示,而是自己构建了一种名为简单动态字符串(simple dyn ...
- redis笔记_源码_简单动态字符串SDS
参照:https://zcheng.ren/sourcecodeanalysis/theannotatedredissourcesds/#sds%E5%B0%8F%E7%BB%93 这里用char b ...
- 【Redis系列2】Redis字符串对象之SDS(简单动态字符串)实现原理分析
Redis字符串对象之SDS实现原理分析 前言 字符串对象 为什么Redis的字符串对象是二进制安全的 SDS空间分配策略 空间预分配 惰性空间释放 SDS和C语言字符串区别 SDS的底层存储对象 d ...
- Redis源码初探(1)简单动态字符串SDS
前言 现在面试可太卷了,Redis基本是必问的知识点,为了在秋招中卷过其他人(虽然我未必参加秋招),本菜鸡决定从源码层面再次学习Redis,不过鉴于本菜鸡水平有限,且没有c语言基础,本文不会对源码过于 ...
- Redis内部数据结构详解之简单动态字符串(sds)
本文所引用的源码全部来自Redis2.8.2版本. Redis中简单动态字符串sds数据结构与API相关文件是:sds.h, sds.c. 转载请注明,本文出自:http://blog.csdn.ne ...
- Redis之简单动态字符串sds
转载:https://segmentfault.com/a/1190000012262739 redis在处理字符串的时候没有直接使用以'\0'结尾的C语言字符串,而是封装了一下C语言字符串并命名为s ...
- redis学习 -- 简单动态字符串
Redis没有使用C语言字符串的形式,通过'\0'作为结尾,而是使用了简单动态字符串(simple dynamic string). 当Redis使用的字符串不需要修改字符串的内容的时候,可以使用C语 ...
- 《Redis设计与实现》阅读笔记(二)--简单动态字符串
简单动态字符串 Redis只在一些无需对字符串进行修改的地方使用C字符串,大部分时候使用简单动态字符串(simple dynamic string, SDS),字符串的抽象类型.二进制安全,可以存放任 ...
- Redis简单动态字符串
简单动态字符串 Simple Dynamic String是Redis内部自己定义的一种数据类型 在Redis内部, 任何包含字符串的键值对都是由SDS实现的 SDS还被用于缓冲区, 比如AOF缓冲区 ...
最新文章
- 文件处理命令:sed
- DllMain使用的注意事项
- pandas使用bdate_range函数获取起始时间(start)和结束时间(end)范围内的所有工作日日期(business day)
- 0.0 环境搭建 - PyTorch学习笔记
- HttpWatch是强大的网页数据分析工具
- 经典FOXMAIL报错 winsock error 11004
- 关于颜色值透明度的设置
- Microsoft Windows SDK for Windows 7 and .NET Framework 3.5 SP1 (ISO)
- 深度学习第一次课-数学
- 2018全球智能手机市场的主要趋势
- 计算机组成原理白中英课后习题题答案
- 十款好用的PDF编辑软件推荐
- 组策略设置计算机计划任务,组策略 运行计划任务 Powershell
- 东芝打印机共享怎么设置_东芝2051C打印机怎么连接并扫描文件到电脑?
- 我的第一次CTF比赛(SDPC)
- C语言 数字实现字母表 链表实现字母表
- tracert路由跟踪(ICMP)
- 大家都在学C语言吧,作为程序员这有一个问题,秃顶算工伤吗?
- 我是没有口袋的哆啦a梦
- linux io栈(读写流程)