C++_Chapter 3 数组、vector与字符串

Chapter 3 数组、vector与字符串

3-1 数组的引入

# include <iostream>
# include <type_traits>

int main()
{
    int a;//int
	int b[10]; //int[10]

	std::cout << std::is_same_v<decltype(b),int[10]> << '\n';//输出为1
}
int x;
std::cin >> x;
int b[x];		//该表达式不合法,类型原本应为int[x],但在编译器内无法处理该x,x是在编译之后地运行期输入的
// variable length array C++

int和int[1]是不同的类型,尺寸上相同,但是操作是不同的

数组初始化
int b[3]; //缺省初始化
int b[3] = {1,2,3}; // 聚合初始化(aggregate initialization)
int b[3] = {1,2}; // 前两个元素用给出元素初始化,最后一个用0初始化
int b[3] = {}; // 用0初始化所有元素
int b[] = {1,2,3}  // decltype(b) == int[3]
int b[]; // 不合法
# include <typeinfo>

int main()
{
	auto b = {1,2,3};
	std::cout << typeid(b).name() <<std::endl;//std::initializater_list<int>
}

数组不支持复制

int b[3] = {1,2,3};
auto a = b;// a的类型为指针
auto& a = b;// a的类型为int(&)[3]

b[3]为内建数组,考虑易用性,有vector、string

char str[] = "Hello"; //str为char[6]类型
char str[] = {'H','e','l','l','o'}; //str为char[5]类型
数组的复杂声明
指针的数组
int x1;
int x2;
int x3;
int* a[3] = {&x1,&x2,&x3}; // a中包含三个元素,每个元素都是指针
数组的指针
int b[3];
int (*a)[3] = &b; // a是一个指针,指向一个包含三个元素的数组
std::cout << std::is_same_v<decltype(a),int(*)[3]> << std::endl;//输出结果为1
声明数组的引用
int b[3];
int (&a)[3] = b;

C++当中不能定义引用的数组;

数组中的元素访问
int a[3] = {1,2,3};
// l-value:locator value--有地址的值,数组是左值
std::cout << a[0] << std::endl;//输出结果为1
//解释左值:
const int x = 3;
std::cout << std::is_same_v<decltype((x)),const int> << std::endl;//(x)表示x是一个表达式,此时输出为0
std::cout << std::is_same_v<decltype((x)),const int&> <<std::endl;//输出为1
int a[3] = {1,2,3};
auto b = a; //--->a作为右值,隐式转换为int*,指向a中的第一个元素a[0]所在的地址

x[y]—>会被翻译为*((x)+(y)),即x+y的解引用,需要防止数组溢出

3-2 从数组到指针

数组到指针的隐式转换
int a[3] = {1,2,3};
auto b = a; // decay
// sizeof和decltype等不会产生隐式转换
// 隐式转换会丢失部分类型信息
// 可以通过声明引用来避免隐式转换
auto& b = a; //--->不产生隐式转换,int(&)[3]

注意,不要用extern指针来声明数组

# include <iostream>

void fun();
extern int* array;
int main(){
    std::cout << array[1] << std::endl;
}
//source.cpp
# include <iostream>

int array[4] = {1,2,3,4};

void fun()
{
    std::cout << array << std::endl;
}
// 运行错误
// 不是编译错误:每一个cpp都没有问题
// 不是链接错误:main.cpp.o与source.cpp.o没有类型信息
// 为什么运行的时候会报错?
// array打印出来是一个十六进制的数字--->指针
// fun()函数打印的地址和main函数打印的地址不同
// main()会打印出array里面的数
// fun()会打印数组的首个元素地址
// 可行的方案
# include <iostream>

void fun();
extern int array[];
int main(){
    std::cout << array[1] << std::endl;
}
//source.cpp
# include <iostream>

int array[4] = {1,2,3,4};

void fun()
{
    std::cout << array << std::endl;
}

Unknown Bounded Array 声明:
在一个程序里面需要用,在主程序里面需要声明,但不关注该数组的size

extern int array[]; —> 不完整类型

获得指向数组开头和结尾的指针
# include <iostream>

void fun();
extern int array[];

int main(){
    int a[3] = {1,2,3};
    //(&a[0])/a指向数组开头的指针
    std::cout << a + 3 << ' ' << &(a[3]) std::endl;
    std::cout << std::begin(a) <<std::endl;
    std::cout << std::end(a) << std::endl;
    
    // std::cbegin(a);  // const int*只能读,不能写
}
指针算数
int a[] = {1,2,3};
auto ptr = a;
auto ptr2 = a + 3;
// 加减
ptr = ptr + 1; // 指针指向下一个int*

// 比较
std::cout << (ptr == ptr2) << std::endl; // 指向相同指针的时候可以做比较,但是指向不同数组的时候不建议

// 求距离
int distance = ptr2 - ptr;

// 解引用
std::cout << *ptr << std::endl;

// 指针索引
std::cout << (ptr) << std::endl;

3-3 其他操作

求元素个数操作
int a[3];

// 方法1:sizeof()  C当中就已经引入,但存在不便(如类型更新)
std::cout << sizeof(a) / sizeof(int) << std::endl;

// 方法2:std::size  the best method
std::cout << std::size(a) << std::endl;

// 方法3:end - begin  不太好,会增加运行期的负担
std::cout << std::cend(a) - std::cbegin(a) << std::endl;
元素遍历
基于元素个数遍历
int main(){
    int a[3] = {2,3,4};
    
    size_t index = 0;
    while (index < std::size(a))
    {
        std::cout << a[index] << std::endl;
        index = index + 1;
    }
}
基于©begin/©end遍历
int main(){
    int a[3] = {2,3,4};
    
    auto ptr = std::cbegin(a);
    while (ptr != std::cend(a))
    {
    	std::cout << *ptr << std::endl;
    	ptr = ptr + 1;
    }
}
基于range-based for循环
int main(){
    int a[3] = {2,3,4};
    
	for (int x : a)
	{
		std::cout << x << std::endl;
	}
}

C++ insights:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BRt6JwdE-1652760807791)(C:\Users\quany\AppData\Roaming\Typora\typora-user-images\image-20220516200617226.png)]

3-4 C字符串

# include <cstring>

int main()
{
	char str[] = "Hello"; // char[6] numm-terminated string
    auto ptr = str; // char*
    // 遍历到'\0'结束
    // C语言还提供了:strlen、strcmp来支持C字符串相关操作
    std::cout << strlen(str) << std::endl;
}

C字符串需要’\0’的支持

3-5 多维数组

多维数组的本质是数组的数组

int a[3][4]; // a[3]-->每个里面包含一个int[4]
int x2[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int x3[3][4] = {1,2,3,4,5};
多维数组的索引与遍历
int x2[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};

x2[0][3]; // 索引
// 遍历方式1
for (auto& p : x2)
{
    for (auto q:p)
    {
        std::cout << q << '\n';
    }
}
// 遍历方式2
size_t index0 = 0;
while (index0 < 3)
{
    size_t index1 = 0;
    while (index1 < 4)
    {
        std::cout << x2[index0][index1] << std::endl;
        index1 = index1 + 1;
    }
    index0 = index0 + 1;
}
// 遍历方式3,推荐进行x[0][0~3] x[1][0~3] x[2][0~3]遍历
size_t index1 = 0;
while (index1 < std::size(x2[0]))
{
    size_t index0 = 0;
    while (index0 < std::size(x2))
    {
        std::cout << x2[index0][index1] <<std::endl;
        index0 = index0 + 1;
    }
    index1 = index1 + 1;
}
// 遍历方式4
int main()
{
    int x2[3][4];
    auto ptr = std::begin(x2);
    while (ptr != std::end(x2))
    {
        auto ptr2 = std::begin(*ptr);
        while (ptr2 != std::end(*ptr2))
        {
            std::cout << *ptr2 << std::endl;
            ptr2 = ptr2 + 1;
        }
        ptr = ptr + 1;
    }
}

【问题】为何不能用range-based for进行遍历?

3-6 vector

C++标准库中的一个类模板,模拟数组

序列容器,更侧重易用性

# include <iostream>
# include <vector>

int main()
{
    int a[3];
    int b[3] = a;//报错
	std::vector<int> x; // vector<int>
    std::vector<int> y;
    y = x;//不会报错
    
}

vector可以复制,可以在运行期动态改变元素个数(付出性能成本)

std::vector<int> = {1,2,3}; // 聚合初始化
std::vector<int> = x(3);
std::vector<int> = x(3,1); // {1,1,1}
std::vector<int> = x{3,1}; // {3,1}

其他方法

// 计算元素个数
std::cout << x1.size() << std::endl;
// 判断是否为空
std::cout << x1.empty() << std::endl;
// 添加元素
x1.push_back(2);
// 删除元素
x1.pop_back(); // 弹出最后一个元素
// vector的比较
std::cout << (x1 == x2) << std::endl;
std::cout << (x1 < x2) << std::endl; // 按元素次序进行比较,从头开始,如果x1的第一个元素小于x2的第一个元素,就会返回为1,如果相等,比较下一个元素

vector的遍历

std::vector<int> = {1,2,3};
std::cout << x1[2] << std::endl; //返回3
std::cout << x1.at(2) << std::endl; //如果越界,会再运行期报错
auto b = std::begin(x1); // x1.begin()
auto a = std::end(x1); // x1.end()
while (b != x1.end())
{
    std::cout << *b << std::endl;
    b = b + 1;
}
// 或者
for (auto val : x1)
{
    std::cout << val << std::endl;
}

std::begin(x1)不再是指针,而是迭代器

*b;--->解引用
b[1] --->*(b + 1) //下标访问
b = b + 1;---> 移动
std::cout << a - b << std::endl;// 两个相减求距离

vector相关的其他内容

// 迭代器失效
std::vector<int> = {1,2};
auto b = std::begin(x1); // x1.begin()
auto a = std::end(x1); // x1.end()
x1.push_back(3); // 可能b和a就不再有效了

多维vector

std::vector<std::vector<int>> x;
x.push_back(std::vector<int>());
x[0].push_back(1);
std::cout << x[0][0] << std::endl;
std::vector<int> x;
std::cout << x.size() << std::endl;

std::vector<int>* ptr = &x;
std::cout << (*ptr).size << std::endl;
std::cout << ptr->size() << std::endl; // 上下相同

3-7 string

是C++标准库中定义的一个类模板特化别名,用于内建字符串的替代品

# include <iostream>
# include <string>

int main()
{
	std::string x = "Hello world";
	std::string y = x; // std::string y(x);
	y = y + '!';
	std::string z(3,'a');
}
//支持size/empty
//支持比较
//支持赋值
//支持拼接
//支持索引
//可转换为C字符串
std::string y("Hello");
auto ptr = y.c_str(); // 转换为C字符串
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值