C++基础容器

1.序列容器——数组

概念:

  • 代表内存里一组连续的同类型存储区
  • 可以用来把多个存储区合并成一个整体

比如:

int arr[10] = {
    
    1,2,3,4,5,6,7,8};

数组声明:

  • int arr[10];
  • 类型名称int表示数组里所有元素的类型
  • 名称arr是数组的名称
  • 整数10表示数组里包含的元素个数
  • 数组里元素个数不可以改变

2.off-by-one error数组下标

-off-by-one error(差一错误)

假定x的边界条件x>=16并且x<=37,那么此范围内x的可能取值个数有多少?
我们进行思考时有两个思考问题的原则:

  1. 首先考虑最简单情况的特例,然后将结果外推;
  2. 仔细计算边界;

x的上界与下界重合时,即x>=16 && x <=16,显示个数为1;假定下界位low,上界位high;当low与high重合时,low=high时,个数为1;据此外推,high-low+1个元素;所以这里37-16+1=22

这里最容易出错就是high-low+1;

  • 使用数学上的左闭右开区间[,)来表示 范围
    问题表示位:x >= 16 并且 x <= 37 -> (x >= 16 && x < 38),这样38-16=22

  • C语言中设计数组下标的原则:从0开始,使用非对称区间;

  • 1.让这个区间是一个非对称的区间[,);

  • 2.让下界(左侧)可以取到值,让上界(右侧)取不到值;

在这里插入图片描述
这样设计的好处

  1. 取值范围的大小:上界-下界;
  2. 如果这个取值范围为空,上界值=下界值;
  3. 即使取值范围为空,上界值永远不可能小于下界值;

3.数组增删改查及二维数组

一维数组

增加:O(n)
减少:O(n)
修改:O(1)
访问:O(1)
对数组a,
数组下标index方式访问:a[2] = 5;
指针方法访问:

int * p = a;
*(p+2) = 5;

二维数组

二维数组:包含行列两个维度的数组

二维数组的访问:

int a[2][4] = {
    
    {
    
    1,2,3,4}{
    
    5,6,7,8}};
for(int row = 0;row < 2;++row)
{
    
    
	for(int col = 0;col < 4;++col)
	{
    
    
		cout<<a[row][col]<<" ";
	}
	cout<<endl;
}

能否一列一列访问,当然可以!
但是tips:循环时尽可能要满足"空间局部性":

  1. 在一个小的时间窗口内,访问的变量地址越接近越好,这样执行速度快;
  2. 也就是说:一般来说,需要将最长的循环放在最内层,最短的循环放在最外层,以减少CPU跨切循环层的次数;

4.动态数组vector

  • vector是面向对象方式的动态数组
  • vector尾部添加操作
#include<vector>
using namespace std;
vector<int> vec = {
    
    1,2,3,4};
vec.push_back(5);
  • vector的遍历操作(也可以使用迭代器)
for(int index = 0;index < vec.size();++index)
{
    
    
	cout<<vec[index[<<endl;
}

注意:可以使用vec的capacitysize方法来查看vector当前的容量和已经存储的元素个数;

  • vector的插入操作:
vec.insert(--vec.end(),4);//在尾部前一个元素插入4
  • vector的删除操作:
    两种方法:

    1. vec.pop_back();
    2. vec.erase(vec.end()-1);//删除尾部操作,需要减1
  • 两个vector合并:

	std::vector<string> vec1;
    std::vector<string> vec2;
    //将vec2插入到vec1尾部
    vec1.insert(vec1.end(),vec2.begin(),vec2.end());

vector与数组互转:
(有空添加上)

5.字符串简介

字符串变量与常量

字符串变量

  • 字符串是以空字符('\0')结束字符数组
  • 空字符’\0’自动添加到字符串的内部表示中
  • 在声明字符串变量时,应该为这个空结束符预留一个额外元素的空间
    如:char strHelloWorld[11] = {"helloworld"};

字符串变量

  • 字符串变量是一对双引号括起来的字符序列

  • 字符串每个字符作为一个数组元素存储

  • 例如字符串"helloworld"

  • 0,’\0’与’0’
    在计算机内部的机器码表示:

char c1 = 0;	//0x00
char c2 = '\0';	//0x00
char c3 = '0';	//0x30

字符串与字符数组互转:
(有空添加上)

6.Unicode编码

  • Unicode编码:最初的目的是把世界上的文字都映射到一套字符空间中
  • 为了表示Unicode字符集,有3种(确切说是5种)Unicode的编码方式:

一、UTF-8:1byte来表示字符,可以兼容ASCII码;特点是存储效率高,变长(不方便内部随机访问),无字节序问题(可作为外部编码)
二、UTF-16:分为UTF-16BE、UTF-16LE;特点是定长(方便内部随机访问),有字节序问题(不可作为外部编码)
三、UTF-32:分为UTF-32BE、UTF-32LE;特点是定长(方便内部随机访问),有字节序问题(不可作为外部编码)

  • 编码错误的根本原因在于编码方式和解码方式的不统一;

7.字符串的指针标识

  • 指针表示方法:
char* pStrHelloWrold = "helloworld";
  • char[]和char*的区别,把握两点:
    • 地址和地址存储的信息;
    • 可变与不可变;
      如:
char strHelloWorld1[11] = {
    
    "helloworld"};

strHelloWorld不可变,strHelloWorld[index]的值可变;char* pStrHelloWorld = “helloworld”;
pStrHelloWrold可变,但是pStrHelloWrold[index]的值可变不可变取决于所指区间的存储区域是否可变(比如常量区域不可以改变)

8.字符串基本操作

头文件:#include<string.h>

字符串基本操作:

  • 字符串长度:strlen(s)
    返回字符串s的长度(注意:s的长度不包括'\0')
  • 字符串比较:strcmp(s1,s2)
    如果s1和s2是相同的,则返回0;
    如果s1<s2则返回小于0;
    如果s1>s2则返回大于0;
    两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇到’\0’为止。
  • 字符串拷贝:strcpy(s1,s2)
    复制字符串s2到字符串s1
  • 复制指定长度字符串:strncpy(s1,s2,n)
    将字符串s2中前n个字符拷贝到s1中,可能会出现缓冲器溢出,安全版本strncpy
  • 字符串拼接:strcat(s1,s2)
    将字符串s2接到s1后面,可能会出现缓冲器溢出,安全版本strcat_s
  • 查找字符串:strchr(s1,ch)
    指向字符串s1中字符ch的第一次出现的位置
  • 查找字符串:strstr(s1,s2)
    指向字符串s1中字符串s2的第一次出现的位置

注:请使用strnlen_s,strcpy_s,strncpy_s,strcat_s等API函数,更安全!!!
注:按住F1,VS可以查找该方法的使用方法。

字符串操作中的问题

C中原始字符串的操作在安全性效率存在一定的问题;
举例:
1.缓冲区溢出问题举例

char strHelloWorld1[11] = {
    
    "helloworld"};
char strHelloWorld2[11] = {
    
    'h','e','l','l','o','w','o','r','l','d','\0'};
strcat(strHelloWorld2,"Welcome to the C++'s world");

2.strlen的效率可以提升:空间换时间

  • Redis字符串的设计:https://redis.io/
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/XZ2585458279/article/details/109467112