-
-
-
* [@ 3减少修改字符串时带来的内存重分配次数](about:blank#___3_81) * [@4 二进制安全](about:blank#4_______94) * [@5 兼容部分C字符串函数](about:blank#5____C_98)
-
-
[](
)before
-
C语言基础
-
Redis基础
[](
)导入
redis的命令如下:
set x "hello";
get x;
hello
Redis作为一种存储字符串的缓存结构,其具体实现是由C语言完成,在C语言中,字符串是通过字符数组实现的,即char[],那么Redis对于字符串的实现是不是也是基于字符数组吗?不是的,Redis对字符串的处理是通过SDS(Simple Dynamic String)实现的。
[](
)SDS介绍
SDS(Simple Dynamic String)简单动态字符串,它是由C语言完成,如下是其具体实现
struct sdshdr{
//记录buf数组已使用字节的数量
//等于SDS所保存字符串的长度
int length;
//记录buf数组未使用字节的数量
int free;
//buf数组
char[] buf;
};
看看redis的示例:
sdshdr
free 0
length 5
buf -->|‘R‘|‘e‘|‘d‘|‘i‘|‘s‘|‘\0‘|
解释:
- free为0,表示这个SDS没有分配任何未使用的空间
- length为5,表示这个SDS保存了一个长度为5的字符串
- buf数组中保存着“Redis”字符串
SDS遵循C字符串以空字符串结尾的惯例,保存空字符串的1字节空间不计算在SDS的len属性之中。
再看看SDS的free不为0的情况:
sdshdr
free 3
length 5
buf -->|‘R‘|‘e‘|‘d‘|‘i‘|‘s‘| | | |
free的值为3,表示这个SDS分配了三个空闲的空间
[](
)SDS与字符串的区别
C语言使用简单的字符串表示方式,并不能满足Redis对字符串在安全性,效率,以及功能方面的要求,SDS更使用Redis。
@1 常数复杂度获取字符串长度
C字符串:
因为C语言并不记录自身的长度信息,所以获取一个C字符串的长度,程序必须遍历整个字符串,对遇到的,每个字符进行计数,直到遇到代表字符串结尾的空字符串为止,这个操作的复杂度为O(n)。
SDS:
与C语言不同的是,SDS结构中的属性length记录了SDS本身的长度,所以获取一个SDS长度的复杂度为O(1)。有人疑问那么SDS的length值是哪来的?这里的length值是SDS API在设置和更新SDS时自动完成的。
总结1
:通过使用SDS而不是C字符串,Redis获取字符串长度的复杂度由O(N)降为O(1),这确保了字符串长度的获取的工作不会成为Redis的性能瓶颈。
[](
)@ 2杜绝缓冲区溢出
C字符串:
由于C自身不记录字符串的长度带来一个问题是容易造成缓冲区溢出(buffer overflow)。在<string.h>/strcat
函数中,可以将一个字符串拼接到另外一个字符串的末尾。
char *strcat(char *dest,const char *src)
理想状态下,用户在使用这个函数时,假定C为dest分配了足够多的内存,可以容纳src字符串中的所有内容,而一旦这个假定不成立,就会产生缓冲区溢出。举个例子,假定内存中有相邻的两个字符串s1,s2,如图:
总结
这个月马上就又要过去了,还在找工作的小伙伴要做好准备了,小编整理了大厂java程序员面试涉及到的绝大部分面试题及答案,希望能帮助到大家