1、C语言中的字符串

C语言中,字符串的使用对于初学者来说是个很容易混淆、很容易出错。C语言字符串是以‘\0′结尾。因此,我们使用字符串时,始终要记得留一个字节用于存放结尾符。

请看下面一段代码,哪个地方会在运行时出错?

1

2

3

4

5

6

char str1[]="hello,world";

char str2[100]="hello,world";

char *str3 = "hello,world";

str1[0]='H';

str3[0]='H';  

printf(" %s   %s  %s",str1,str2,str3);

上面的代码会在如下地方出错。

1

str3[0]='H';

从概念上讲,之所以出错是因为str3是个常量字符串,而常量是不允许被改变的。

 

在一些开源项目中,我们能看到C语言字符串的一些引申版本,他们对c语言原生字符串进行封装以获得额外的优点。例如:

2、Nginx中的字符串

nginx中字符串类型被定义为一个结构体,如下:

1

2

3

4

typedef struct {

    size_t len;

    u_char *data;

} ngx_str_t;

这样定义有什么好处呢?

nginx针对web服务器特定的场景对字符串进行的一个简单封装。这样封装的好处是可以有效的降低内存使用量。

例如:假设如下一个http请求存放在起始地址为0×12345678的内存处。

GET  /about.html  http/1.1

我们要取出http请求的请求方法,只需要如下赋值即可获得,而不需要额外开辟内存空间来存储。这样就节省了内存。

1

2

len=3;

data = 0x12345678


3、Redis中的字符串

在redis中,字符串同样也被封装成了一个结构体,具体如下:

1

2

3

4

5

struct sdsdr{

    int len;  //存放字符串长度

    int free; //记录buf中还有多少字节未使用

    char buf[];

};

redis总将字符串封装成如上结构,你能看出它相比于原生字符串,有什么好处么??

至少有如下几个好处:

1)能够在O(1)时间内获取到字符串的长度。而原生字符串要获取器长度择需要通过检测字符串结尾符才能得到字符串长度,时间复杂度为O(n)

2)能够有效杜绝缓冲区溢出。这个很好理解,比如c语言字符串复制操作,如果如果事先没有分配足够的内存,便会出现缓存区溢出。而有了len这个字段后,我们可以利用它来防止缓存区溢出。

3)二进制安全。这个有点不容易注意到。C语言中的字符中,除了字符串末尾之外,字符串里不能包含空字符,否则最先读入的空字符就会被误认为是字符串结尾,因此字符串就被无故截断了,这种限制使得C语言原生字符串只能保持文本数据,而不能保持诸如图片、音频、视频等二进制数据。但是,通过上面的结构体封装后,有了len字段记录字符串的真实长度,我们就不会再有限制,我们只管通过len来取数据就行了,不用担心buf里面存放的是不是空字符。