数组向量字符串
数组的初始化
数组的大小可以缺省,必须是常量,但不能小于0,也不能是变量
数组不能直接复制,可以使用auto进行引用
字符串数组的特殊性,初始化的方法有两种
#include<iostream>
#include <type_traits>
using namespace std;
int main() {
int b[] = { 1,2,3,4,5,56 };
//cpp 17标准,CPP11的标准
char ch[] = "hello";
char ch1[] = { 'h','e' };
cout << is_same_v<decltype(ch), char[6]> << endl;
cout << "hello wpf!";
return 0;
}
缺省初始化,
会将数组中的每一个元素都按照缺省初始化的方式进行初始化,
局部变量初始化为随机值,
全局变量、线程相关变量和静态变量初始化为0。
int b[3] = {1,2,3}; //初始化为1,2,3
int b[3] = {1,2}; //初始化为1,2,0
int b[3] = {}; //初始化为0,0,0
int b[] = {1,2,3}; //初始化为1,2,3并自动推导b的类型为int[3]
int b[]; //不合法的代码
int b[2] = {1,2,3}; //不合法的代码
指针数组,和数组的指针概念的理解
//对应数组指针和指针数组的区别
//a 这个数组的每一个元素都是一个指针,指针数组
int m, n;
int* a[3] = {&m,&n};
//a的类型是一个指针,
int (*p)[4];
cout << is_same_v<decltype(p), int(*)[4]> << endl;
声明数组的引用
不能定义引用数组
可以定义数组的引用
原因:引用,本身是地址,别名而不是对象
数组元素的访问:
数组的对象是一个左值,能够放在等号的左边, 左值可以作为右值使用
使用时转换为相应的指针类型,数据类型decay退化到指针类型,如果a是数组则,a变为右值,退化
auto b =a;
隐式转换可能会丢失一些信息,编译器不会检查,是否超越信息,会检测到相应的结果。
声明引用来避免隐式类型转换。
auto &b =a;
不要使用extern指针声明数组
extern的使用方法
数组访问的形式x[y]会被解析为((x)+(y))*
标准库的指针对应序号的编写
int a[3] = {1,2,3};
std::begin(a); // 指向数组第一个元素的指针
std::end(a); // 指向数组最后一个元素的下一个元素的指针
std::cbegin(a); // 指向数组第一个元素的指向常量的指针
std::cend(a); // 指向数组最后一个元素的下一个元素的指向常量的指针
指针的算数
增加,减少
比较
求距离
解引用
指针索引
数组的方法
求数组的大小
- sizeof,占用的字节数(不推荐)
- 通过sizeof可以实现size()获取元素的个数
- 使用begin,end 也可以获得使用这个值球差,必须球差,但是相对的差不变(不推荐)
求数组中元素的个数
sizeof
int a [3];
sizeof(a)/sizeof(int); // 使用sizeof数组没有退化成指针,获取到的是数组所占用的内存大小
std::size
int a[3];
std::size(a); // 直接获取数组内元素的个数
(c)end - (c)begin
int a[3];
std::cend(a) - std::cbegin(a); // 直接获取数组内元素的个数
前两种方法数组尺寸是编译期获取的,而最后一个方法是在运行期获取的,所以不推荐使用最后一种方法。而前两种方法中sizeof方法需要针对特定类型做除法,不易于修改,所以三种方法中最推荐使用std::size
数组遍历
- 基于元素的个数
- 基于begin end的方法
- 基于range base for的方法C++的语法
//基于元素个数
int a[4] = {2,3,5,7};
size_t index = 0;
while(index < std::size(a)){
std::cout << a[index] << std::endl;
index = index + 1;
}
//基于(c)begin和(c)end
int a[4] = {2,3,5,7};
auto ptr = std::cbegin(a);
while(ptr != std::cend(a)){
std::cout << *ptr << std::endl;
ptr = ptr + 1;
//基于范围的for循环
int a[4] = {2,3,5,7};
for(int x:a){
std::cout << x << std::endl;
}
字符串
获得字符串的长度
strlen(),来自于ctring
strcmp(),
了解字符串的开始结束的定义
末尾加\0主要是为了在运行期使用指针形式对字符串操作时获取字符串的长度
多维数组
多维数组的理解
i
n
t
−
x
[
3
]
[
4
]
int_{-}x[3][4]
int−x[3][4]
表示的是
x首先是一个数组包含三个元素,每一个元素包含int[4]的类型的数据,包含四个元素
x
[
0
]
−
>
i
n
t
[
4
]
(
i
n
t
i
n
t
i
n
t
i
n
t
)
(
i
n
t
i
n
t
i
n
t
i
n
t
)
.
.
.
.
x[0] ->int[4] \\ (int\quad int\quad int \quad int)\quad (int\quad int\quad int \quad int)\quad....
x[0]−>int[4](intintintint)(intintintint)....
数组是行优先的矩阵
学会理解二维数组的基本含义
注意必须给定后面维的大小,只能省略第一维的大小
多维数组的初始化
缺省初始化
全局变量是用0来初始化
局部变量是用随机初始化
初始化方法
int x[3][4] = {1,2,3,4,5};
int x3[3][4]= {{1,2,3},{4,5,6}};//推荐方法
//只能省略第一位的数字,其余不能省略
二维数组的遍历方法
其一使用range base for进行遍历
其二使用指针进行遍历
vector的数据结构
数组可以隐式转换为指针,多维数组同样可以隐式转换为指针,但是只有最高维会进行转换,其他维度的信息会被保留,比如
int x[3][4];
auto ptr = x; // 类型为int (*) [4]
向量
-
数组是内建的数据结构,更侧重于易用性,
数组不能直接复制
-
向量是标准模板库**,可以复制**,可以在运行期间动态改变元素的个数
-
vector支持复制
初始化的方法,聚合初始化,列表初始化
其他的方法
插入删除,比较元素,获得大小
这就使得开销增大,性能下降
vector的初始化可以使用以下方法
缺省初始化
聚合初始化
std::vector x = {1,2,3};
1
其他的初始化方式,具体的可以参考这里
std::vector x(3); // 包含三个元素,其中的每个元素都为0
std::vector x(3,1); // 包含三个元素,其中的每个元素都为1
std::vector x{3,1}; // 包含2个元素,值为3,1
1
2
3
vector提供了一系列的方法:
获取元素个素
std::vector<int> x(3);
x.size(); // 返回3
判断其是否为空
std::vector<int> x(3);
x.empty();
插入、删除元素
std::vector<int> x(3);
x.push_back(1); // 插入
x.pop_back(1); // 删除
比较
std::vector<int> x1(3);
std::vector<int> x2(2);
x1 == x2; // 按顺序逐个比较
x1 > x2; // 按顺序逐个比较,若元素相同尺寸不同,则按照元素个数大小来判断
关于vector还有一些其他的内容需要了解:
向vector中添加元素可能会使得迭代器失效
可以构造多维vector
std::vector<std::vector<int>> x{{1,2,3},{1,2}}; // 每一维包含的元素不相同
x.push_back(std::vector<int>());
x[0].push_back(1);
*与->的理解
std::vector<int> x;
x.size();
std::vector<int> * ptr = &x;
x->size();
对于指针来说ptr->等价于`(*ptr).
vector内部也会定义一些类型,比如
size_type:size方法的返回值类型
iterator/const iterator
除了构造和初始化方法,string还支持很多其他的方法
尺寸相关的方法(size/empty)
比较
赋值
拼接
索引
std::string x = "Hello world";
x[0]; // H
转换为C风格字符串
std::string x = "Hello world";
auto y = x.c_str(); // 返回类型为 const char *
作业
使用for合并指针遍历输出二维数组的数据
使用指针遍历输出二维数组的数据
//数组的两种遍历方法
int a45[3][5] = {1,2,34,656,7,8,923,23,645,7,9,3,34};
//第一种遍历方法
for (auto& x :a45) {
for (auto y : x)
cout << y << "_" ;
}
//指针遍历方法
auto ptr = begin(a45);
while (ptr != end(a45)) {
auto ptr1 = begin(*ptr);
while (ptr1 != end(*ptr))
{
cout << *ptr1 ;
ptr1 += 1;
}
ptr += 1;
}
//vector的遍历方法
vector<int> v1(3, 1);//表示三个1
cout << "_-------------" << endl;
for (auto x : v1) {
cout << x << endl;
}