C语言字符串缺陷

目录

 

补缺:

正题开始:

思考:

解决方案:

1.string类

2.redis库

简介:

对于处理字符串的好处:

下期预告:内容待定


 

补缺:

在上期内容的结尾我留下了一个问题,这个问题是让大家思考八位二进制的最大值和最小值以及它们之间的关系。相信大家都有了自己的一个思考,现在解析开始。算是补码的一个小奇葩。

首先这个问题我们要先想到在八位二进制中最大值是多少(补码中),最大值是127(0111 1111)。第二个要想一想在补码中的规则(在补码中首位是符号位,不参与计算),所以最大值的表达就是剩下的七位是1,首位是0代表最大的有符号数。然后我们再思考,在补码中负数是由正数的二进制取反加一来表达的,所以我们只要找到正数最大数然后取反就可以了?由于补码中八位二进制的最大数127,那么我们应该取反加一就行了吗?不不不,在这里C语言中用到了一个巧妙地方法(与之前的方法不同)。C语言在八位二进制数的最大值127(0111 1111)后面直接加一从而得到(1000 0000)也就是-128。这里的方法和补码的规则不太一样,这种方法只是在补码中对于由最大的二进制数转换到最小的二进制数的过程,其他的转换还是补码的规则(保留首位,取反加一)。我们加上一之后满足二进制的规则(逢二进一),我们就会得到(1000 0000)这个数,而这恰恰满足补码中对于有符号数的表达(首位的1恰好看作是符号位),所以这就是补码中关于最大数转换成为最小数的过程(循环)中的一个方法,整数溢出导致的二进制数循环的最特殊的一步。

总结:补码中对于最大数到最小数的转换的规则就是找到最大数的二进制表达方式,然后加一得到的二进制数就是最小数的表达。至于为什么说这是循环可以看看我上一篇的内容C语言整数溢出的问题              提升补充内容——补码


正题开始:

首先我们要清楚字符串其实就是字符数组,所以字符数组的结尾也是有\0存在的。而且在C语言中通过字符数组的指针(首地址)和字符数组的结束符来控制字符数组。

#include<iostream>
using namespace std;
int main()
{
char z1[]="hello"
cout<<strlen(z1)<<endl;//5
cout<<sizeof(z1)/sizeof(z1[0]);//6

char z2[]="hel\0lo"
cout<<strlen(z2)<<endl;//3
cout<<sizeof(z2)/sizeof(z2[0]);//4

char z3[30]="hello2";
strcat(z3[],z2[]);
cout<<z3<<endl;//hellohel
cout<<strlen(z3)<<endl;//8
cout<<sizeof(z3)/sizeof(z3[0]);//9
}

上面的代码我们定义了三个个字符数组.我们都知道\0就是字符串的结束符,所以我们第一个数组输出的结果就是5和6。(这里的strlen就是数组的内容长度;sizeof算的是数组的存储长度,是包括\0的)。那么看z2这里由于hello中插入了一个\0所以hello的长度就被提前结束了所以内容长度只有3,但是它的存储长度却是因为多了一个\0,所以变成了8。接下来看z3,这个数组我们利用strcat来将两个数组进行拼接,结果是:内容长度是8,存储长度是9。(拼接的时候第一个数组的结束符会被删除,只保留第二个数组的结束符,相当于拼接后的字符数组只有一个结束符)。


思考:

那么你发现了什么。所有的字符数组都是和\0有直接的关系的,不论是内容长度还是存储的空间长度都是相关的。所以这就导致我们存储的内容是不能包含\0的而且这种检测存储长度的方法(sizeof)也会变得很慢,效率不高。


解决方案:

有两种:1 string类    2  redis库

1.string类

#include<iostream>
using namespace std;
#include<string>
int main()
{
char z1[]="hello"
cout<<strlen(z1)<<endl;//5
cout<<sizeof(z1)/sizeof(z1[0]);//6

char z2[]="hel\0lo"
cout<<strlen(z2)<<endl;//3
cout<<sizeof(z2)/sizeof(z2[0]);//4

char z3[30]="hello2";
strcat(z3[],z2[]);
cout<<z3<<endl;//hellohel
cout<<strlen(z3)<<endl;//8
cout<<sizeof(z3)/sizeof(z3[0]);//9

//C++的改进方案:

string zz1="hello";
cout<<zz1.length()<<endl;//5
cout<<zz1.capacity()<<endl;//15
cout<<sizeof(zz1)<<endl;//28

string zz2="hel\0lo";
cout<<zz2.length()<<endl;//3
cout<<zz2.capacity()<<endl;//15
cout<<sizeof(zz2)<<endl;//28

zz1+=zz2;
cout<<zz1.length()<<endl;//8
cout<<zz1.capacity()<<endl;//15
cout<<sizeof(zz1)<<endl;//28

}

我们看上面的代码是用C++的方案写出的。我们可以看出关于内容长度上C++的length还是3;其中的capacity是预存空间(随着编译器的变化而变化);但是看sizeof这个时候的存储空间就是整个string的存储空间,不再单独是字符串的存储空间。而且string类的内容很多,也跟利于字符串的使用,这就是C++的升级。


2.redis库

简介:

Redis 是一个开源的、使用 ANSI  C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。它通常被称为数据结构服务器,因为值(value)可以是字符串(strings)、哈希(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)、位图(bitmaps)、超日志(hyperloglogs)和地理空间(geospatial)索引半径查询的索引等类型。


对于处理字符串的好处:

1.性能高效:Redis是基于内存的数据库,所以存取字符串的速度非常快,非常适合处理高频次的数据读写操作。
2.灵活的数据类型:虽然叫做字符串,但Redis的字符串实际上可以存储任何形式的字符串,包括二进制数据,这让它非常灵活。
3.丰富的操作命令:Redis提供了许多操作字符串的命令,比如SET、GET、INCR(用于整数类型的字符串,实现自增)、DECR(自减)等,可以满足各种复杂场景的需求。
4.原子性操作:Redis的很多字符串操作都是原子性的,这意味着这些操作在执行过程中不会被其他客户端的指令打断,保证了数据的一致性。
5.易于使用:Redis的字符串操作接口简单,易于理解和使用,无论是对于开发者还是运维人员来说,都是非常友好的。
6.这些好处使得Redis在处理字符串类型的数据时,相比其他类型的数据库或存储系统,具有非常明显的优势!

关于这个库的使用这里就先不讲,不然内容肯定会十分繁杂。

这是链接,可以自行看一下源码。

redis库             GitHub里的redis库


🆗到这里,这篇关于C语言字符串缺陷就说完了,求一个免费的赞,感谢阅读。还有一部分内容放到下期。

下期预告:C语言字符串缺陷的补充

 

 

 

  • 14
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值