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

Posted infoworld

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[C/C++]_[初级]_[关于把字符串string作为字节数组存储的注意点]相关的知识,希望对你有一定的参考价值。

场景

  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

以上是关于[C/C++]_[初级]_[关于把字符串string作为字节数组存储的注意点]的主要内容,如果未能解决你的问题,请参考以下文章

[C/C++]_[初级]_[关于编译时出现有符号-无符号不匹配的警告-sizeof使用注意事项]

[C/C++]_[初级]_[关于编译时出现有符号-无符号不匹配的警告-sizeof使用注意事项]

[C/C++]_[初级]_[关于编译时出现有符号-无符号不匹配的警告-sizeof使用注意事项]

[C/C++]_[初级]_[声明和使用字符串常量和字节常量]

[C/C++11]_[初级]_[使用正则表达式库regex]

[C/C++20]_[初级]_[信号量semaphore]