Skip to content

面试速答(先看这里)

**一句话结论:**Redis是一种KV的存储结构,他的key是字符串类型,值也支持字符串,所以字符串是redis中最常见的一个类型了。

60秒标准回答:

Redis是一种KV的存储结构,他的key是字符串类型,值也支持字符串,所以字符串是redis中最常见的一个类型了。 Redis自己本身是通过C语言实现的 ,但是他并没有直接使用C语言中的字符数组的方式来实现字符串,而是自己实现了一个SDS(Simple Dynamic Strings),即简单动态字符串,这是为什么呢?

首先,因为 字符串在Redis中使用实在是太广泛了 ,所以对他的基本要求就有两点, 第一就是要支持任意字符的存储,第二就是各种操作需要高效

接着我们看看C语言中字符串的实现方式有什么问题呢?很多人可能都忘了,我帮大家回忆一下,C语言中,字符串是通过字符数组实现的,底层呢是开辟了一块连续的空间,依次存放字符串中的每一个字符。为了表示字符串的结束,他会在字符数组的最后一个字符处记录 \0

**答题顺序:**结论 → 原理/机制 → 关键流程 → 场景与取舍 → 易错点

回答主线:

  • **要点1:**首先,因为 字符串在Redis中使用实在是太广泛了 ,所以对他的基本要求就有两点, 第一就是要支持任意字符的存储,第二就是各种操作需要高效。
  • **要点2:**接着我们看看C语言中字符串的实现方式有什么问题呢?
  • **要点3:**也就是说,在C语言中,当识别到字符数组中的 \0 字符的时候,就认为字符串结束了,那么这么做会带来哪些问题呢?
  • **要点4:**就是 这样实现的字符串中就不能保存任意内容了,至少 \0 就不行 ,因为遇到他的时候就直接截断了,这肯定是接受不了的。
  • **要点5:**还有就是因为 C中的字符串以 \0 作为识别字符串结束的方式,所以他的字符串长度判断、字符串追加等操作,都需要从头开始遍历,一直遍历到 \0 的时候再返回长度或者做追加。

**记忆锚点:**len → Redis → \0 → alloc → SDS → 中最常见的一个类

易错提醒:

  • 就是 这样实现的字符串中就不能保存任意内容了,至少 \0 就不行 ,因为遇到他的时候就直接截断了,这肯定是接受不了的。

加分表达:

  • 还有呢,就是在做追加操作的时候,只需要判断新追加的部分的 len 加上已有的 len 是否大于 alloc ,如果超过就重新再申请新空间,如果没超过,就直接进行追加就行了。

追问准备:

  • Redis自己本身是通过C语言实现的 ,但是他并没有直接使用C语言中的字符数组的方式来实现字符串,而是自己实现了一个SDS(Simple Dynamic Strings),即简单动态字符串,这是为什么呢?
  • 接着我们看看C语言中字符串的实现方式有什么问题呢?
  • 为了表示字符串的结束,他会在字符数组的最后一个字符处记录 \0 , 也就是说,在C语言中,当识别到字符数组中的 \0 字符的时候,就认为字符串结束了,那么这么做会带来哪些问题呢?
  • 那么,想要解决上面的两个问题要怎么办呢?

典型回答 ​

Redis是一种KV的存储结构,他的key是字符串类型,值也支持字符串,所以字符串是redis中最常见的一个类型了。Redis自己本身是通过C语言实现的,但是他并没有直接使用C语言中的字符数组的方式来实现字符串,而是自己实现了一个SDS(Simple Dynamic Strings),即简单动态字符串,这是为什么呢?

首先,因为字符串在Redis中使用实在是太广泛了 ,所以对他的基本要求就有两点,第一就是要支持任意字符的存储,第二就是各种操作需要高效。

接着我们看看C语言中字符串的实现方式有什么问题呢?很多人可能都忘了,我帮大家回忆一下,C语言中,字符串是通过字符数组实现的,底层呢是开辟了一块连续的空间,依次存放字符串中的每一个字符。为了表示字符串的结束,他会在字符数组的最后一个字符处记录\0,

也就是说,在C语言中,当识别到字符数组中的\0字符的时候,就认为字符串结束了,那么这么做会带来哪些问题呢?

就是这样实现的字符串中就不能保存任意内容了,至少**\0**就不行,因为遇到他的时候就直接截断了,这肯定是接受不了的。

还有就是因为C中的字符串以**\0**作为识别字符串结束的方式,所以他的字符串长度判断、字符串追加等操作,都需要从头开始遍历,一直遍历到**\0**的时候再返回长度或者做追加。这就使得字符串相关的操作效率都很低。

那么,想要解决上面的两个问题要怎么办呢?那就是在用字符数组表示字符串的同时,在这个字符串中增加一个表示分配给该字符数组的总长度的**alloc**字段,和一个表示字符串现有长度的**len**字段。这样在获取长度的时候就不依赖**\0**了,直接返回**len**的值就行了。

还有呢,就是在做追加操作的时候,只需要判断新追加的部分的len加上已有的len是否大于alloc,如果超过就重新再申请新空间,如果没超过,就直接进行追加就行了。

还有很多其他操作,比如复制、比较等都可以使用类似的思想高效的操作。