前言
文中程序使用C11,使用codeite集成开发环境。
1.数组
定义:将一到多个相同类型的对象串连到一起,所组成的类型。数组可以类比数学中的矩阵。在C++中数组是一种类型。
声明数组时,必须让编译器知道数组的大小,如:
int a[10]; //[]括号里的数要大于0,括号里可以填常量。这里a的类型是int[10]
int b[] = {1, 2, 3}; //编译器可以自动推断出数组的大小
cout << is_same< decltype(a), int[10]>::value << endl; //结果是1
错误写法:
int b[]; //错误
int c[2] = {1, 2, 3, 4}; //错误,初始化元素超过数组定义的大小
对于如下语句:
int b[5] = {1, 1, 3}; //b里包含的元素是1 1 3 0 0。系统会自动补全数组。
注:
- 不能使用 auto 来声明数组类型。
- 数组不能复制。
- 元素个数必须是一个常量表达式(编译期可计算的值)。
- 读取数组元素是不要超过数组的大小如:
int b[3] = {1, 2, 3};
std::cout << b[13] << std::endl; //这个虽然有输出,但这个值是不对的
1.1 数组的复杂声明
注意:数组不存在引用。
看如下程序
#include <iostream>
int main()
{
int a[3]= {1,2,3};
std::cout<< a <<' '<< &(a[0])<<' '<<std::begin(a)<<std::endl;
std::cout<< a+3 <<' '<< &(a[3])<<' '<<std::end(a)<<std::endl;
}
输出结果:
0x7ffdfc342a7c 0x7ffdfc342a7c 0x7ffdfc342a7c
0x7ffdfc342a88 0x7ffdfc342a88 0x7ffdfc342a88
Hit any key to continue...
如上面的程序,数组在使用时通常会转换成相应的指针类型。再看下面的程序:
# include <iostream>
int main()
{
int a[3]= {1,2,3};
std::cout<< *(a+2) <<std::endl; //a这里相当与一个指针,可以直接解引用
std::cout<< a[2] <<std::endl;
}
输出:
3
3
Hit any key to continue...
1.2 数组与指针
1.2.1 数组到指针的隐式转换
使用数组对象时,通常情况下会产生数组到指针的隐式转换。隐式转换会丢失一部分类型信息,可以通过声明引用来避免隐式转换。
注:不要使用 extern 指针来声明数组。
1.2.2 相关的基本操作
- 获得指向数组开头与结尾的指针 :
std::(c)begin, std::(c)end
- 数组可以利用指针的相关算数使用,包括: 增加、减少,比较,求距离,解引用,指针索引。
#include <iostream>
int main()
{
constexpr size_t num = 5;
int a[num] = {1, 2, 3, 4, 5};
int* ptr = a;
int* ptr2 = a + 4;
std::cout << *ptr << std::endl; //a[0]
std::cout << *ptr2 << std::endl; //a[4]
}
- 求元素的个数
1.sizeof 方法
#include <iostream>
int main()
{
int a[3];
std::cout<< sizeof(a) <<std::endl;
std::cout<< sizeof(a)/sizeof(int) <<std::endl; //最后的元素个数,输出3
}
- std::size 方法
注:c17以上才有c.size()才有这样的方法,c是一个数组。
int a[3];
std::cout<< std::size(a) <<std::endl; //这个输出12,其输出的是整个数组包含的字节数。使用cobra编译
- (c )end - (c )begin 方法
std::cout<< std::end(a) - std::begin(a)<<std::endl; //输出3
std::cout<< std::cend(a) - std::cbegin(a)<<std::endl; //输出3,cend可以理解为只读
- 遍历数组
方法一(使用while循环):
#include <iostream>
int main()
{
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;
}
}
方法二(range-based for 循环):
#include <iostream>
int main()
{
int a[4] = {2, 3, 5, 7};
for(int x : a) //这里可以遍历整个容器
{
std::cout<<x<<std::endl;
}
}
1.2.3 字符串
对字符串的操作函数一般在cstring库里,如下面的程序。
#include <iostream>
#include <cstring>
int main()
{
char str1[] = "hello"; //这个程序的末尾默认有结束符'\0'
char str2[] = {'h','e','l','l','o'}; //这样写一些编译系统可以通过,但不要这个样写,如果这样定义须在末尾加'\0'。这样定义使用cstring的字符串处理函数输出的结果是不对的
char str3[] = {'h','e','l','l','o', '\0'};
char str4[] = "word";
std::cout << strlen(str3) << std::endl;
std::cout << strcmp(str1, str2) << std::endl; //如果str1=str2就输出0,str1大于str2输出为正,str1小于str2输出为负。这里str1与str2不等价
std::cout << strcmp(str1, str3) << std::endl; //str1与str3等价
std::cout << strcat(str1, str3) << std::endl; //将str3拼接在srt1后
std::cout << strcpy(str1, str4) << std::endl; //用str4替换srt1
}
输出结果:
5
-119
0
hellohello
word
Hit any key to continue...
1.2.4 多维数组
本质:数组的数组,如
int a[3][4]; //大小为3的数组,每个元素包含4个元素。三行四列
- 多维数组的初始化
//第一种方法
int a[3][4] = { {1, 2, 3, 4}, {1, 2, 3, 4}, {1, 2, 3, 4}}; //这里不能使用()代替{}
//第二种方法
int a[3][4] = { 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4}; //与第一种方法等价
// 第三种
int a[3][4] = { {1}, {1}, {1}}; //这个相当于int a[3][4] = { {1, 0, 0, 0}, {1, 0, 0, 0}, {1, 0, 0, 0}};
//第四种
int a[3][4] = { 1, 2, 3}; //剩下的位置补0
遍历方法:
#include <iostream>
#include <cstring> //include strlen
#include <type_traits>
int main()
{
int x[3][4][5] = {1, 2, 3, 4, 5};
for (auto& p : x)
{
for (auto &q : p)
{
for (auto r : q)
{
std::cout<< r << std::endl;
}
}
}
}
#include <iostream>
#include <cstring> //include strlen
#include <type_traits>
int main()
{
int x[3][4] = {1, 2, 3, 4, 5};
size_t index0 = 0;
while (index0 < 3)
{
size_t index1 = 0;
while (index1 < 4)
{
std::cout << x[index0][index1] <<std::endl;
index1 = index1 + 1;
}
index0 = index0 + 1;
}
}
- 指针与多维数组
- 多维数组可以隐式转换为指针,但只有最高维会进行转换,其它维度的信息会被保留。
- 使用类型别名来简化多维数组指针的声明。
- 使用指针来遍历多维数组。
2. vector
vector是 C++ 标准库中定义的一个类模板,它也被称作容器。一般情况下程序中用vector代替数组的使用。与内建数组相比,更侧重于易用性,它可复制、可在运行期动态改变元素个数。vector类似与堆栈。
- 定义与初始化
std::vector<std::vector<int>> x; //基本的定义方式
std::vector<std::vector<int>> x1(x2); //x1包含x2的所有元素,xi与x2的类型要i一致
//等价于std::vector<std::vector<int>> x1 = x2;
std::vector<std::vector<int>> x3(n, 1); //x3包含n个1
std::vector<std::vector<int>> x4{1, 2, 3, 4}; //x4包含1 2 3 4
//等价于 std::vector<std::vector<int>> x4 = {1, 2, 3, 4};
- 一些基本操作
std::vector<std::vector<int>> x;
x.push_back(1); //增加元素,向x末尾添加1
x.empty(); //判断x是否为空
x.size(); //返回x的大小
x.pop_back(): //删除x中最后一个元素
x.clear(): //清空x中所有元素
3.string
是 C++ 标准库中定义的一个类模板特化别名,用于内建字符串的代替品。与内建字符串相比,更侧重于易用性,其可复制、可在运行期动态改变字符个数。使用时需要添加string头文件。