[C/C++]_[初级]_[关于把字符串string作为字节数组存储的注意点]

本文介绍了将C++的std::string对象作为字节数组使用时需要注意的问题。直接设置字符串大小可能导致未定义行为,因为字符串会自动扩充容量。正确操作包括通过添加、插入或覆盖数据来改变大小。推荐遵循标准库的方法来避免错误,如通过迭代器或成员函数操作,确保容量与大小的安全。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

场景

  1. 在使用string标准字符串的时候,有时候会把它作为动态字节数组来使用。这个string能不能先存储字节数据,再设置它的字节数据大小?

说明

  1. 答案是不行,会有未定义行为。在做字节数组使用时,会使用reverse()方法来创建它的容量最小大小。设置完之后实际的容量大小可以通过capacity()方法来获得。容量大小即它开闭的内存数组大小,存储数据如果超过它,那么就会有未定义行为,比如越界访问的异常。

  2. string的实际大小,通过size()获得当前大小,它的大小必然是小于等于它的容量的。 大小只能通过以下方式改变。

    • 构造函数: 设置它的初始大小和初始数据。
    • append(): 通过在末尾添加数据,并且增加对应数据大小的差值。
    • assign(): 覆盖原来的数据。
    • insert(): 指定索引位置插入数据,并增加对应数据大小的差值。
    • erase(): 删除指定索引区间的值,当然也会改变大小。
    • clear(): 清空数据,大小为0,容量不变。
    • resize(): 直接创建指定大小的数据,新增加的区域默认是\0
      void resize(size_type _Newsize, _Elem _Ch)
      {	// determine new length, padding with _Ch elements as needed
      if (_Newsize <= this->_Mysize)
      	erase(_Newsize);
      else
      	append(_Newsize - this->_Mysize, _Ch);
      }
      
  3. 可见想先用存储空间再设置它的大小是容易出错的,基本都会覆盖原来的数据。

  4. 注意,string的容量会根据内部的算法进行自动扩充,除此以外就只能通过reverse提前设置好容量。

  5. string里使用数组来存储字节数据;可以使用data()来作为数组首地址使用;在C++17以后才会提供一个返回CharT*数据,不需要强制转换。

string str;
str.reserve(8);
sprintf((char*)str.data(),"%d",100)

例子

  1. 这里举例使用string作为字节数组存储数据,并查看它的容量和大小的关系。
#define pKeyValue(a) cout << #a << ": " << a << endl
#define pValue(a) cout << #a << endl
#define exec(a) cout << #a << endl;a

void TestStringCapacity()
{
	string str;

	pValue(===============================);
    exec(str.reserve(8192)); // 设置容量的最小大小,不一定是8192.
	pKeyValue(str.capacity());
    pKeyValue(str.size());
    
	pValue(===============================);
	exec(str.append("44\0\0\0", 5));
    pKeyValue(str.size());
	pKeyValue(str.capacity());
	pKeyValue(str);

	pValue(===============================);
	exec(str.resize(8));
	pKeyValue(str.size());
	pKeyValue(str);
	
	pValue(===============================);
	exec(str.resize(2));
	pKeyValue(str.size());
	pKeyValue(str);

	pValue(===============================);
    exec(auto iteSize = str.end() - str.begin());
    pKeyValue(iteSize);
    exec(str.clear());
    pKeyValue(str.capacity());

	// `string`里使用数组来存储字节数据;可以使用data()来作为数组首地址使用;
	//      -- 在C++17以后才会提供一个返回`CharT*`数据,不需要强制转换。
	//      -- 注意str里开辟的缓存大小>=8192,通过之前的reverse设置.
	pValue(===============================);
	exec(sprintf((char*)str.data(),"%d",100));
	pKeyValue(str.size());
	pKeyValue(str.c_str());

	// -- 如果是存储字符串,那么只能通过strlen(str.c_str())来获取长度.
	pValue(========);
	pKeyValue(strlen(str.c_str()));
	
	// -- 如果是存储字节数据,那么只能先通过resize来设置长度再进行存储数据.
	pValue(========);
	exec(str.resize(8));
	exec(memset((void*)str.data(),'A',str.size()));
	pKeyValue(str.size());
	pKeyValue(str.c_str());

	// -- 千万不要先存储字节再resize,因为resize会把大于原有大小的空间填充\0,造成数据错误或丢失.
	pValue(========);
	exec(sprintf((char*)str.data(),"%d%d%d%d",100,100,100,100));
	pKeyValue(str.c_str());
	pKeyValue(str);
	exec(str.resize(12));
	pKeyValue(str.size());
	pKeyValue(str.c_str());

}

输出

===============================
str.reserve(8192)
str.capacity(): 8207
str.size(): 0
===============================
str.append("44\0\0\0", 5)
str.size(): 5
str.capacity(): 8207
str: 44
===============================
str.resize(8)
str.size(): 8
str: 44
===============================
str.resize(2)
str.size(): 2
str: 44
===============================
auto iteSize = str.end() - str.begin()
iteSize: 2
str.clear()
str.capacity(): 8207
===============================
sprintf((char*)str.data(),"%d",100)
str.size(): 0
str.c_str(): 100
========
strlen(str.c_str()): 3
========
str.resize(8)
memset((void*)str.data(),'A',str.size())
str.size(): 8
str.c_str(): AAAAAAAA
========
sprintf((char*)str.data(),"%d%d%d%d",100,100,100,100)
str.c_str(): 100100100100
str: 10010010
str.resize(12)
str.size(): 12
str.c_str(): 10010010

参考

  1. std::basic_string
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Peter(阿斯拉达)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值