作者:守望,Linux应用开发者,目前在公众号【编程珠玑】 分享Linux/C/C++/数据结构与算法/工具等原创技术文章和学习资源。

不知道你有没有见过-1作为数组下标的,我算是见到了。当然这一点在Python之类的语言中毫不稀奇。

下标-1的代码

这里redis源码中的一部分:

sds sdsMakeRoomFor(sds s, size_t addlen) {    void *sh, *newsh;    size_t avail = sdsavail(s);    size_t len, newlen;    char type, oldtype = s[-1] & SDS_TYPE_MASK;    int hdrlen;    //摘取部分代码

其中sds定义如下:

typedef char* sds

我们忽略其中的逻辑,其实可以看到在sds中有很多使用-1作为下标的。那么这里到底有什么含义?又有什么好处呢?别急!

数组下标访问

我们都知道,数组下标可以以O(1)复杂度访问一个数组的元素:

int arr[] = {1,2,3,4,5};printf("%d\n",arr[2]);

上面的示例代码中,就是访问了数组的第三个元素,实际上,作用等价于;

printf("%d\n",*(arr+2));

这一点,我已经在《C语言入坑指南-数组之谜》中解释过了。arr相当于int*类型指针,+2,意味着指针向前移动了sizeof(int) * 2,即8字节的位置,最终指向数字3。关于指针的算术运算,也可以参考《void*是怎样的存在》。

再看下面:

int *pArr = arr + 2;printf("%d\n",pArr[-1]);//printf("%d\n",*(pArr-1))

这里也很好理解,无非就是pArr指向数字3,然后又使用下标-1,访问了前一个位置,最终自然指向了数字2,打印的也是2。

到目前为止,一切都还合情合理。

但是,我们别忘了,数组越界是一件很可怕事情。比如,你试试:

printf("%d\n",arr[16]);printf("%d\n",arr[-1]);

运气不好的时候,程序不会挂死,只是打印出一些莫名其妙的值,运气好的时候,程序挂死。(有人可能会问,为什么程序不会挂死,运气还算好呢?因为不挂死的时候,一些隐藏的问题更让人抓狂)。

到这里我们明白了,为了数组下标访问不越界,通常下标范围是0~size-1,其中size是数组元素个数。

那么问题来了,redis的源码中为什么要用-1作为下标呢?

巧妙的-1

实际上,sds其中的一个结构(8bit范围长度)定义是这样的:

struct __attribute__ ((__packed__)) sdshdr8 {    uint8_t len; /* used */    uint8_t alloc; /* excluding the header and null terminator */    unsigned char flags; /* 3 lsb of type, 5 unused bits */    char buf[];};

其中

__attribute__ ((__packed__))

是取消字节对齐,关于字节对齐,可以参考《理一理字节对齐的那些事》,本文不再赘述。

而在每一次创建新的sds结构的时候,返回的指针,都是指向buf这里从源码的sdsnewlen函数中很容易看出:
即:

1字节 1字节 1字节
len alloc flags buf

所以我们看到前面这样的代码也就不足为奇了:

oldtype = s[-1] & SDS_TYPE_MASK;

这里的-1相当于将指针指向了flags字段:

1字节 1字节 1字节
len alloc flags buf

相信到这里你应该能理解-1的作用了。

那么为什么要这么做呢?想象一下,使用strlen是不是直接可以计算sds字符串的长度了呢?

总结

一般来说-1这样的用法是不太建议的,或者说,在使用下标访问数组时,必须确保不越界。

预告

redis中为什么不用普通的char*存储字符串,而要使用所谓的简单动态字符串?背后究竟隐藏着怎样的秘密?请看下文详细分解。


●编号750,输入编号直达本文

●输入m获取文章目录

C语言与C++编程

分享C/C++技术文章

c++ string 无法通过下标访问_数组下标1你见过吗?相关推荐

  1. php判断数组下标,php检查数组下标是否存在

    PHP检查数组下标是否存在的方法 array_key_exists()函数 array_key_exists()函数判断某个数组中是否存在指定的 key,如果该 key 存在,则返回 true,否则返 ...

  2. python数组下标访问起始_为什么数组下标从0开始

    背景 有很多编程语言的数组都是从 0 开始编号,你是否下意识地想过,为什么数组要从 0 开始编号,而不是从 1 开始呢? 从 1 开始不是更符合人类的思维习惯吗?那先看下数组的定义. 数组(Array ...

  3. 增加数组下标_数组以及ArrayList源码解析

    点击上方"码之初"关注,···选择"设为星标" 与精品技术文章不期而遇 前言 前一篇我们对数据结构有了个整体的概念上的了解,没看过的小伙伴们可以看我的上篇文章: ...

  4. golang中string下标访问

    看一下golang中string的下标访问. package mainimport "fmt"func main() {x := "123"fmt.Printl ...

  5. c++排序数组下标_看动画学算法之:排序 - 基数排序

    简介 之前的文章我们讲了count排序,但是count排序有个限制,因为count数组是有限的,如果数组中的元素范围过大,使用count排序是不现实的,其时间复杂度会膨胀. 而解决大范围的元素排序的办 ...

  6. js 取得数组下标_数组的介绍及使用

    JavaScript 中的数组常用于在单个变量中存储多个值.数组就是一组数据的集合,在内存中表现为一段连续的内存地址(保存在堆内存).创建数组的目的就是为了保存更多的数据. 数组概念和语法 概念:数组 ...

  7. 通过数组下标获取值都有哪些方法_通过面试题,让我们来了解Collection

    前言 欢迎关注微信公众号:Coder编程 获取最新原创技术文章和相关免费学习资料,随时随地学习技术知识! 本章主要介绍Collection集合相关知识,结合面试中会提到的相关问题进行知识点的梳理.希望 ...

  8. js 取得数组下标_剖析JS和Redis的数据结构设计:数组

    语言的数据结构相通性 最近读了Redis的原理实现,感受到程序语言的相通性,只要你掌握了语言的共性,触类旁通其他语言的开发就变得非常简单了. 总体来说,各种程序语言底层的设计思想是非常相通的,首先针对 ...

  9. matlab 连续下标表示,MATLAB通过下标访问多个数组元素

    在<MATLAB通过下标访问数组元素>中我们讲解了如何通过下标来访问数组中的某一个元素,除此之外,MATLAB 还允许通过下标一次性访问多个元素. 使用冒号指明下标范围 MATLAB 允许 ...

最新文章

  1. 漫画|小白到大神程序员的进阶,都是什么生活状态?
  2. 算法之最近最少使用LRU
  3. Redis常用命令之操作List类型
  4. OVS+Docker
  5. VMware虚拟机VMware Authorization Service不能启动问题
  6. 拼装机器人感想_学习制作机器人的感想作文500字15篇
  7. rabbitmq java文档_RabbitMQ文档翻译——Hello World!(上)
  8. 从C语言中的指针看C#中委托
  9. python---(4) win10 环境下访问MYSQL 数据库
  10. python高手养成_Python用PyQt5制作颜色对话框,PyQt图形界面编程之QColorDialog
  11. JS操作Cookie写入和读取实例代码
  12. F5入口IP依据不同的端口实现转发到不同的POOL
  13. 计算矩阵A与矩阵B的欧式距离
  14. 【IoT】产品设计之商业模式分析:一篇文章九个维度,带你认知小米的商业模式
  15. activiti选择上一步下一步处理人
  16. Android 动画基础知识学习(下)
  17. DataStream API【1】
  18. 各种机械键盘轴线之间的差,究竟好轴
  19. Pytorch:基于转置卷积解码的卷积自编码网络
  20. Redis与传统sql数据库的区别

热门文章

  1. DPDK跟踪库:trace library
  2. 利用scp在windows和linux之间进行文件和文件夹的数据拷贝
  3. Java与C语言混合编程
  4. android studio下生成aar文件,本地调用
  5. 大班线描机器人_大班美术教案机器人
  6. android缩放动画后,Android ObjectAnimator:缩放后动画填充
  7. 神经网络模型中有什么样的算子_浅析图卷积神经网络
  8. python实现绘制信号序列语谱图
  9. 如何使用AOP改进.NET应用程序
  10. 谁能制约云厂商滥用开源,谁来帮助开源软件作者?