C++基础容器 -- C的数组和字符串和C++的数组和字符串

news/2024/11/25 10:58:07/

文章目录

  • C++基础容器
    • 序列型容器
      • 数组
        • off-by-one error(差一错误)
        • 数组的增删改查
        • 二维数组的访问
      • 动态数组 std::vector
        • vector插入操作
        • vector删除操作
      • 字符串和字符数组
        • Unicode编码
        • 字符串的指针表示方法
        • 字符串的常见操作
        • 字符串操作的问题
      • C++中的std::string

C++基础容器

序列型容器

数组

  • 概念

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

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

    • 每个元素都有下标,通过下标可以直接访问任意一个元素
    • 下标从0开始到元素个数减一为止
    • 超过范围的下标不可以使用
    • 数组名称和下标一起可以表述数组里面的元素。arr[4]
  • 优点

    • 可以编写循环依次处理数组里面所有的元素
    • 循环变量可以依次代表所有有效下标
    • 下标标识了一个元素在数组的位置

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

  • 考虑问题原则
    • 首先考虑最简单的情况的特例,然后将结果外推
    • 仔细计算边界
    • 一般使用左闭右开的区间来表示范围

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

  1. 让这个区间是非对称区间
  2. 让下界可以取到,让上界取不到

这样设计的好处:

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

数组的增删改查

  1. 在尾部添加和删除时间复杂度为O(1);

  2. 不在尾部添加和删除时间复杂度为O(n);

  3. 数组遍历高效,时间复杂度为O(1);

  4. 数组查找的时间复杂度为O(n),取决于数组容量;

二维数组的访问

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

代码展示:

#include <iostream>
using namespace std;
#include <vector>
int main()
{// 数组访问int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 0, 0};// 推荐方式  ++ 写在前面避免拷贝构造 提速for (int index = 0; index < 10; ++index)cout << a[index] << " ";cout << endl;// 不推荐方式for (int index = 0; index <= 9; ++index)cout << a[index] << " ";// 数组的查找int b[] = { 1, 2, 3, 4 };int len = sizeof(b) / sizeof(b[0]);//得到数组容量for (int index = 0; index < len; ++index){if (b[index] == 5){cout << index << endl;return 0;}}//二维数组的访问:int c[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 << c[row][col] << " ";}cout << endl;}return 0;
}

动态数组 std::vector

vector是面向对象的动态数组 – 使用简单的数组是无法动态扩容插入元素,因为容量有限

vector插入操作

  • vec.insert(–vec.end(), 6);

  • vec.push_back(5);

vector删除操作

  • vec.pop_back();
  • vec.erase(vec.end() - 2);

示例代码:

#include <iostream>
#include <vector>
using namespace std;int main()
{// 创建动态数组vectorvector<int> vec = { 1,2,3,4 };cout << "size is " << vec.size() << endl;cout << "capacity is " << vec.capacity() << endl;// 遍历所有元素for (int index = 0; index < vec.size(); ++index){cout << vec[index] << endl;}// 在尾部插入一个元素5vec.push_back(5);cout << "size is " << vec.size() << endl;cout << "capacity is " << vec.capacity() << endl;// 遍历所有元素for (int index = 0; index < vec.size(); ++index){cout << vec[index] << endl;}// 在中间插入一个元素6vec.insert(--vec.end(), 6);cout << "size is " << vec.size() << endl;cout << "capacity is " << vec.capacity() << endl;// 遍历所有元素for (int index = 0; index < vec.size(); ++index){cout << vec[index] << endl;}// 在尾部移除一个元素vec.pop_back();cout << "size is " << vec.size() << endl;cout << "capacity is " << vec.capacity() << endl;// 遍历所有元素for (int index = 0; index < vec.size(); ++index){cout << vec[index] << endl;}// 在任意位置移除一个元素vec.erase(vec.end() - 2);cout << "size is " << vec.size() << endl;cout << "capacity is " << vec.capacity() << endl;// 遍历所有元素for (int index = 0; index < vec.size(); ++index){cout << vec[index] << endl;}return 0;
}

字符串和字符数组

  • 字符串变量

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

    • 字符串常量是一对双引号括起来的字符序列
    • 字符串中每个字符作为一个数组元素存储 “helloworld”

ASCII码一览表,ASCII码对照表 (biancheng.net)

Unicode编码

  • 最初目的是把世界上的文字都映射到一套字符空间中

  • 为了表示Unicode字符集,有五种Unicode编码方式,这里说3中

    • utf-8 : 1byte 表示,可以兼容ascii
      • 存储效率高,变长,无字节序问题
    • utf-16
      • 特点是定长,有字节序的问题(不可作为外部编码)
    • utf-32
      • 特点是定长,有字节序问题(不可作为外部编码)
  • 编码错误的根本原因是在于编码方式和解码方式的不统一

windows文件可能有Bom 如果在其他平台可以去掉bom

字符串的指针表示方法

  • 指针表示方法 – char* pStrHelloWrold = “helloworld”;

字符串的常见操作

  • 字符串长度:strlen(s);

  • 字符串比较:strcmp(s1, s2);

  • 字符串拷贝:strcpy(s1, s2); 复制s2到s1s

  • 复制指定长度字符串:strncpy(s1, s2, n);

  • 字符串拼接:strcat(s1, s2);

  • 查找字符:strchr(s1, ch);

  • 查找字符串:strstr(s1, s2);

字符串操作的问题

  • C中原始字符串操作在安全性和效率存在一定的问题
    • 缓冲区溢出问题
    • strlen的效率可以提升:空间换时间
#include <string.h>
#include <iostream>
using namespace std;
int main()
{// 定义一个数组char strHelloWorld[11] = { "helloworld" };     // 这个定义可以char* pStrHelloWrold = "helloworld";pStrHelloWrold = strHelloWorld;//strHelloWorld = pStrHelloWrold;               // 数组变量的值不允许改变// 字符0, '\0', '0'的区别char c1 = 0;char c2 = '\0';char c3 = '0';// 通过数组变量遍历修改数组中的元素值for (int index = 0; index <  strlen(strHelloWorld); ++index){strHelloWorld[index] += 1;std::cout << strHelloWorld[index] << std::endl;}// 通过指针变量遍历修改数组中的元素值for (int index = 0; index < strlen(strHelloWorld); ++index){pStrHelloWrold[index] += 1;std::cout << pStrHelloWrold[index] << std::endl;}cout << endl;  // 换行// 计算字符串长度cout << "字符串长度为: " << strlen(strHelloWorld) << endl;cout << "字符串占用空间为:  " << sizeof(strHelloWorld) << endl;return 0;
}
#include <string.h>                    //使用C库的头文件
#include <iostream>
using  namespace std;
const unsigned int MAX_LEN_NUM = 16;
const unsigned int STR_LEN_NUM = 7;
const unsigned int NUM_TO_COPY = 2;
int main()
{char strHelloWorld1[ ] = { "hello" }; char strHelloWorld2[STR_LEN_NUM] = { "world1" };char strHelloWorld3[MAX_LEN_NUM] = {0};//strcpy(strHelloWorld3, strHelloWorld1);                                    // hellostrcpy_s(strHelloWorld3, MAX_LEN_NUM, strHelloWorld1);//strncpy(strHelloWorld3, strHelloWorld2, NUM_TO_COPY);      // wollostrncpy_s(strHelloWorld3, MAX_LEN_NUM,  strHelloWorld2, NUM_TO_COPY);//strcat(strHelloWorld3, strHelloWorld2);                                    //  wolloworld1strcat_s(strHelloWorld3, MAX_LEN_NUM, strHelloWorld2);//unsigned int len = strlen(strHelloWorld3);unsigned int len = strnlen_s(strHelloWorld3, MAX_LEN_NUM);for (unsigned int index = 0; index < len; ++index){cout << strHelloWorld3[index] << " ";}cout << endl;	// 小心缓冲区溢出//strcat(strHelloWorld2, "Welcome to C++");strcat_s(strHelloWorld2, STR_LEN_NUM, "Welcome to C++");return 0;
}

C++中的std::string

  • C++中提供了string类型专门表示字符串
  • 使用string可以更加安全方便的管理字符串

使用起来比原始的C风格的方法更安全和方便,对性能要求不是特别高的常见可以使用。

示例代码:

#include <iostream>
#include <string>
using namespace std;
int main()
{// 字符串定义string s1;//定义空字符串string s2 = "helloworld";//定义并初始化string s3("helloworld");string s4 = string("helloworld");// 获取字符串长度cout << s1.length() << endl;cout << s1.size() << endl;cout << s1.capacity() << endl;//  字符串比较s1 = "hello", s2 = "world";cout << (s1 == s2) << endl;cout << (s1 != s2) << endl;//  转换成C风格的字符串const char *c_str1 = s1.c_str();cout << "The C-style string c_str1 is: " << c_str1 << endl;//  随机访问for (unsigned int index = 0; index < s1.length(); ++index){cout << c_str1[index] << " ";}cout << endl;for (unsigned int index = 0; index < s1.length(); ++index){cout << s1[index] << " ";}cout << endl;// 字符串拷贝s1 = "helloworld";s2 = s1;// 字符串连接s1 = "helllo", s2 = "world";s3 = s1 + s2;               //s3: helloworlds1 += s2;                    //s1: helloworldreturn 0;
}

http://www.ppmy.cn/news/82516.html

相关文章

【实践篇】领域驱动设计:DDD工程参考架构 | 京东云技术团队

背景 为什么要制定参考工程架构 不同团队落地DDD所采取的应用架构风格可能不同&#xff0c;并没有统一的、标准的DDD工程架构。有些团队可能遵循经典的DDD四层架构&#xff0c;或改进的DDD四层架构&#xff0c;有些团队可能综合考虑分层架构、整洁架构、六边形架构等多种架构…

Activity的onCreate方法是怎样被调用的?

Activity的onCreate方法是怎样被调用的&#xff1f; 按前面源码分析的介绍&#xff0c;在Activity的onCreate方法中&#xff0c;添加如下的log&#xff1a; android.util.Log.i("wztest", "Activity onCreate", new Exception());重新编译后&#xff0c;…

GC之查看GC日志

写在前面 本文一起看下如何查看GC日志。 1&#xff1a;环境准备 为了能更模拟真实的业务环境生成GC日志&#xff0c;我们首先来准备一个测试类&#xff0c;详细的注释已经在代码中&#xff0c;如下&#xff1a; import java.util.Random; import java.util.concurrent.TimeU…

docker下不同容器的网络互相访问问题

目录 背景 ​编辑 docker网络模式 解决方法 mysql下 docker-compose下网络设置 nacos 效果 背景 我这边有两个容器&#xff0c;宿主机ip为 192.168.1.115&#xff0c;一个mysql&#xff0c;一个nacos&#xff0c;部署在主机上&#xff0c;使用的默认网络bridge&#xff…

selenium driver相关使用

1) 打开浏览器&#xff0c;创建driver对象 from selenium import webdriver import time from selenium.webdriver.common.by import Bydriver webdriver.Chrome() driver.maximize_window() driver.implicitly_wait(5) url "https://www.baidu.com/" driver.get(u…

RabbitMQ部署指南

文章目录 RabbitMQ部署指南1.单机部署1.1.下载镜像1.2.安装MQ 2.集群部署2.1.集群分类2.2.设置网络 RabbitMQ部署指南 1.单机部署 我们在Centos7虚拟机中使用Docker来安装。 1.1.下载镜像 方式一&#xff1a;在线拉取 docker pull rabbitmq:3-management方式二&#xff1a…

C++线程安全队列

在异步编程中&#xff0c;经常需要一个多线程安全的队列来作为线程间通讯的结构&#xff0c;但STL本身提供的std::queue并不是线程安全的&#xff0c;所以需要自己手动实现。 #pragma once#include <queue>#include <mutex>#include <condition_variable>tem…

西南交通大学智能监测 培训课程练习1

2023.05.24培训 task1&#xff1a;ER的用法、对应数据库的设计 task2&#xff1a;熟悉数据库基本操作、使用Navicat 目录 一、E-R图是什么 二、E-R图的组成要素 三、E-R图绘制 四、E-R图实例 4.1E-R图转换到关系模式 4.2具体数据表设计 五、Mysql基础操作 5.1操作数据库…