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

简介: 这样设计的好处:1.取值范围:下界到上界2.如果这个取值范围为空,上界值==下界值3.即使取值范围为空,上界值永远不可能小于下界值

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()
{
    // 创建动态数组vector
    vector<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;
    }
    // 在尾部插入一个元素5
    vec.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;
    }
    // 在中间插入一个元素6
    vec.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);                                    // hello
  strcpy_s(strHelloWorld3, MAX_LEN_NUM, strHelloWorld1);
  //strncpy(strHelloWorld3, strHelloWorld2, NUM_TO_COPY);      // wollo
  strncpy_s(strHelloWorld3, MAX_LEN_NUM,  strHelloWorld2, NUM_TO_COPY);
  //strcat(strHelloWorld3, strHelloWorld2);                                    //  wolloworld1
  strcat_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: helloworld
    s1 += s2;                    //s1: helloworld
    return 0;
}


目录
相关文章
|
4月前
|
搜索推荐 编译器 C语言
【C++核心】特殊的元素集合-数组与字符串详解
这篇文章详细讲解了C++中数组和字符串的基本概念、操作和应用,包括一维数组、二维数组的定义和使用,以及C风格字符串和C++字符串类的对比。
106 4
|
2月前
|
存储 设计模式 C++
【C++】优先级队列(容器适配器)
本文介绍了C++ STL中的线性容器及其适配器,包括栈、队列和优先队列的设计与实现。详细解析了`deque`的特点和存储结构,以及如何利用`deque`实现栈、队列和优先队列。通过自定义命名空间和类模板,展示了如何模拟实现这些容器适配器,重点讲解了优先队列的内部机制,如堆的构建与维护方法。
42 0
|
3月前
|
存储 搜索推荐 C++
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
69 2
|
3月前
|
存储 C++ 容器
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器1
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
76 5
|
3月前
|
存储 编译器 C++
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
85 2
|
3月前
|
缓存 网络协议 API
C/C++ StringToAddress(字符串转 boost::asio::ip::address)
通过上述步骤和示例代码,你可以轻松地在C++项目中实现从字符串到 `boost::asio::ip::address`的转换,从而充分利用Boost.Asio库进行网络编程。
99 0
|
3月前
|
编译器 C语言 C++
C/C++数字与字符串互相转换
C/C++数字与字符串互相转换
|
3月前
|
设计模式 存储 C++
【C++】C++ STL探索:容器适配器 Stack 与 Queue 的使用及模拟实现(二)
【C++】C++ STL探索:容器适配器 Stack 与 Queue 的使用及模拟实现
|
3月前
|
存储 C++ 容器
【C++】C++ STL探索:容器适配器 Stack 与 Queue 的使用及模拟实现(一)
【C++】C++ STL探索:容器适配器 Stack 与 Queue 的使用及模拟实现
|
4月前
|
C++
C++(十一)对象数组
本文介绍了C++中对象数组的使用方法及其注意事项。通过示例展示了如何定义和初始化对象数组,并解释了栈对象数组与堆对象数组在初始化时的区别。重点强调了构造器设计时应考虑无参构造器的重要性,以及在需要进一步初始化的情况下采用二段式初始化策略的应用场景。

热门文章

最新文章