• 嵌入式养成计划-41----C++ auto--lambda表达式--C++中的数据类型转换--C++标准模板库(STL)--list--C++文件操作


    九十九、auto

    99.1 概念

    • C++11引入了自动类型推导,和Python不一样,C++中的自动类型推导,需要auto关键字来引导
    • 比如 :auto a = 1.2; 会被编译器自动识别为 a 为 double 类型

    99.2 作用

    • auto修饰变量,可以自动推导变量的数据类型。

    99.3 注意

    1. auto修饰变量时,必须初始化
    2. auto的右值,可以是右值,可以是表达式,可以函数的返回值
    3. auto不能修饰函数的形参
    4. auto不能修饰数组
    5. auto不能修饰非静态数据成员

    99.4 用途

    在这里插入图片描述

    1. auto一般修饰数据类型比较冗长的类型
    2. auto还可以用于依赖函数模板的模板参数
    3. auto还可以修饰lambda表达式

    例如 :

    #include 
    using namespace std;
    
    int fun(int a, char b, float c, int *d, char *e, bool f,int g)
    {
        return 1+2;
    }
    int main()
    {
        //定义一个函数指针,指向该函数
        int (*p)(int , char , float , int *, char *, bool ,int ) = fun;
        //auto修饰指针
        auto p2 = fun;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    #include 
    using namespace std;
    
    int fun(int a, char b, float c, int *d, char *e, bool f,int g)
    {
        return 1+2;
    }
    //创建一个函数模板
    template <typename T>
    int fun2(T a)
    {
        auto b = a;
        cout << typeid (b).name() << endl;
    }
    int main()
    {
        //定义一个函数指针,指向该函数
        int (*p)(int , char , float , int *, char *, bool ,int ) = fun;
        //auto修饰指针
        auto p2 = fun;
        fun2(12);
        fun2('2');
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    一百、lambda表达式

    100.1 作用

    • 当需要一个匿名的、临时的,可以捕获外界变量的函数时,可以用lambda表达式完成。

    • 一般用在函数的实参

    100.2 格式

    [](){}  //lambda表达式
    
    
    [捕获外界变量的方式](函数的形参列表)->return type{函数体内容}
    
    [] :捕获外界变量的方式
        1.[变量1,变量2] :值捕获,外界的变量和函数体内部捕获到的变量的值相同,
    					但地址不同,表示不同的变量,不可以对该变量进行修改操作,
    					如果想在函数体内修该变量的值,可以加上mutable
        2.[=] :值捕获,对外界所有的变量进行值捕获
        3.[&变量1, &变量2] :引用捕获(地址捕获),外界的变量和函数体内部捕获到的变量的值相同,
        					地址也相同,是同一个变量,可以对变量修改操作,可以不用mutable
        4.[&] :引用捕获,对外界所有的变量进行引用捕获
        5.[=,&变量1, &变量2] :
        6.[变量1,变量2,&] :
    
    () :函数的形参列表
    
    ->  函数的返回类型
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    示例 :

    #include 
    using namespace std;
    
    int main()
    {
        int a = 100, b =200, c = 300;
        cout << a << " main  "  << &a << endl;
        //auto fun = [a,b]()mutable{
        //auto fun = [=]()mutable{
        //auto fun = [&a,&b](){
        auto fun = [&](string name = "hello")->int{
             cout << a << "  fun "  << &a << endl;
             a = 200;
             cout << a << " fun  "  << &a << endl;
             cout << c << endl;
             //return name; 指定返回类型,就不可以随意返回类型
        };
        cout << a << "  main "  << &a << endl;
        
        cout << fun("hello kitty") << endl;
        cout << a << "  main "  << &a << endl;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    一百零一、C++中的数据类型转换

    101.1 概念

    • C++中存在多种数据类型的转换方式,用于在不同的数据类型之间进行转换。

    101.2 种类

    以下是常见的数据类型转换方式:

    • 隐式类型转换(自动类型转换):
      这是C++编译器自动执行的类型转换,通常在表达式中出现时发生。
      例如,将较小的整数转换为较大的整数类型,将整数提升为浮点数等。
      int num_int = 10;
      double num_double = num_int;  // 隐式将int转换为double
      
      • 1
      • 2
    • 显示类型转换(强制类型转换)
      通过使用强制类型转换操作符来显示执行类型转换。
      这种转换可能会导致数据的截断或者精度丢失,因此要小心使用。
      1. 静态转换(static_cast):
        用于基本数据类型之间的转换
        以及父类指针/引用转换为子类指针/引用
        还可以用于不同类型的指针之间的转换
        double num_double = 3.14;
        int num_int = static_cast<int>(num_double);  // 显式将double转换为int
        
        • 1
        • 2
      2. 动态转换(dynamic_cast):
        通常用于多态类之间的指针或引用类型转换,确保类型安全。
        在运行时进行类型检查,只能用于具有虚函数的类之间的转换
        class Base {
            virtual void foo() {}
        };
        class Derived : public Base {};
        
        Base* base_ptr = new Derived;
        Derived* derived_ptr = dynamic_cast<Derived*>(base_ptr);  // 显式将基类指针转换为派生类指针
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
      3. 常量转换(const_cast):
        用于添加或移除指针或引用的常量性。它可以用来去除const限定符,但要注意潜在的未定义行为
        const int a =10; //
        int *p;
        p = &a; // 合不合法?   no
        
        • 1
        • 2
        • 3
        const int num_const = 5;
        int* num_ptr = const_cast<int*>(&num_const);  // 去除const限定符
        
        • 1
        • 2
      4. 重新解释转换(reinterpret_cast):
        执行低级别的位模式转换,通常用于指针之间的类型转换。
        它可能导致未定义行为,因此要谨慎使用
        int num = 42;
        float* float_ptr = reinterpret_cast<float*>(&num);  // 重新解释转换
        
        • 1
        • 2
    • C风格类型转换 : 与C语言中的类型转换方式类似,包括以下几种:
      • c样式转换:
        使用强制类型转换 操作符进行转换,类似与C语言中的类型转换
        int num_int = 10;
        double num_double = (double)num_int;  // C样式强制类型转换
        
        • 1
        • 2
      • 函数样式转换(函数式转换):
        使用C++中的类型转换函数进行转换
        int num_int = 10;
        double num_double = double(num_int);  // C++函数样式类型转换
        
        • 1
        • 2

    101.3 注意

    需要注意的是,尽管C++提供了多种类型转换方式,
    但应该谨慎使用,以避免潜在的错误和问题。
    特别是在使用强制类型转换时,务必确保转换操作是安全的,以避免不必要的问题。

    C++关键字 :
    在这里插入图片描述

    1. asm:
      这是一个用于嵌入汇编语言代码的关键字。它允许你在C++代码中直接插入汇编指令,通常用于执行特定的底层操作。然而,由于现代C++提供了更强大的抽象和跨平台性,通常不建议使用这个关键字。
    2. explicit:
      这个关键字通常用于禁止隐式类型转换的发生。当一个构造函数被声明为explicit时,它将不会在隐式类型转换中被调用,只能在显式构造函数调用中使用。
    3. export:
      在C++中,export关键字用于指示一个模板的定义将在另一个文件中实例化。然而,在实际的C++标准中,export关键字的语法并未最终确认,并且在许多编译器中也未被实现。在C++20中,export被重新引入,但是它的主要用途是与模块化编程相关,而不是之前模板实例化的用法。
    4. goto:
      goto是一个跳转语句,允许你无条件地将程序的控制转移到指定的标签处。然而,由于使用goto会导致代码结构变得混乱和难以维护,现代编程实践通常建议避免使用它。
    5. register:
      在早期的C语言标准中,register关键字用于建议编译器将变量存储在寄存器中,以便提高访问速度。然而,现代编译器已经能够智能地管理寄存器分配,所以使用register关键字通常不再有明显的性能提升,并且在C++17中已被弃用。
    6. volatile:
      volatile关键字用于告诉编译器不要对标记为volatile的变量进行优化,因为这些变量的值可能会在未知的时间被外部因素改变,比如硬件中断或多线程环境中的共享变量。这可以防止编译器对这些变量的读取和写入操作进行优化,以确保程序的行为是可预测的。
    • 数据类型相关的关键字

      1. bool、true、false:对于bool类型数据的相关处理,值为true和false
      2. char、wchar_t:char是单字符数据,wchar_t多字符数据
      3. int、short、float、double、long:整数和实数的数据类型
      4. signed、unsigned:定义有符号和无符号数据的说明符
      5. auto:在c语言中,是存储类型,但是在C++中,是类型自动推导,注意事项有两个:
        1. 连续定义多个变量时,初始值必须是相同数据类型,否则报错
        2. auto p=&m; 与auto* p = &m;规定是一样
          explicit:防止数据隐式转换
          typedef:类型重定义
          sizeof:求数据类型的字节运算
    • 语句相关的关键字

      1. switch、case、default:实现多分支选择结构
      2. do、while、for:循环相关的关键字
      3. break、continue、goto:跳转语句
      4. if、else:选择结构
      5. inline:内联函数
      6. return:函数返回值
    • 存储类型相关的关键字
      static、const、volatile、register、extern、auto

    • 构造数据类型相关

      1. struct、union:结构体和共用体
      2. enum:枚举
      3. class:类
    • 访问权限:public、protected、private

    • 异常处理:throw、try、catch

    • 类中相关使用关键字

      1. this:指代自己的指针
      2. friend:友元
      3. virtual:虚
      4. delete、default:对类的特殊成员函数的相关使用
        例如:Test(const Test &) = default; ~Test() = delete;
      5. mutable:取消常属性
      6. using:引入数据,有三种使用方式
        1. 使用命名空间的关键字
        2. 相当于类型重定义
        3. 修改子类中从父类继承下来成员的权限
      7. operator:运算符重载关键字
    • 类型转换相关的关键字
      static_cast、dynamic_cast、const_cast、reinterpret_cast

    • 模板相关的关键字:template、typename

    • 命名空间相关:using、namespace

    • export:导入相关模板类使用

    • 内存分配和回收:new、delete

    一百零二、C++标准模板库(STL)

    • C++中的标准模板库(Standard Template Library),STL是标准库之一。
    • 标准模板库中使用了大量的函数模板和类模板,用来对数据结构和算法的处理。
    • STL的组成:容器、算法、迭代器

    102.1 vector容器

    • vector也是数组,称为单端数组,和普通数组有区别,普通数组是静态空间,而vector容器空间是动态拓展的。
    • 动态拓展:不是在原来的空间续接新的空间,而是重新申请空间,把原来的数据拷贝到新的空间中去。

    102.2 vector的构造函数

    函数原型:
    	vector< T > v; //无参构造
    	
    	vector(const vector &v)//拷贝构造函数
    	vector(v.begin(), v.end()) ;  //把区间[ v.begin(), v.end() )的数据拷贝给本对象
    	vector(n, elem);  //把n个elem拷贝给本对象
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    示例 :

    #include 
    #include   //包含头文件vector
    
    using namespace std;
    
    void printVector(vector<int> &v) //算法
    {
        vector<int>::iterator iter; //迭代器
        for(iter = v.begin(); iter != v.end(); iter++)
        {
            cout << *iter << " ";
        }
        cout << endl;
    }
    int main()
    {
        vector<int> v; //vector容器
        v.push_back(10); //尾插
        v.push_back(20);
        v.push_back(30);
        v.push_back(40);
        v.push_back(50);
    
        printVector(v);
    
        vector<int> v1 = v;  //v1(v)
    
        printVector(v1);
    
        vector<int> v2(v1.begin(), v1.end());
        printVector(v2);
        
        vector<int> v3(3,99);
        printVector(v3);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    102.3 vector的赋值函数

    函数原型:
    	vector &operator=(vector &v); //拷贝赋值函数
    	assgin(v.begin(), v.end()); //把区间[ v.begin(), v.end() )的数据赋值给本对象
    	assgin(n, elem);  //把n个elem赋值给本对象
    
    • 1
    • 2
    • 3
    • 4

    示例 :

    #include 
    #include   //包含头文件vector
    using namespace std;
    
    void printVector(vector<int> &v) //算法
    {
        vector<int>::iterator iter; //迭代器
        for(iter = v.begin(); iter != v.end(); iter++)
        {
            cout << *iter << " ";
        }
        cout << endl;
    }
    int main()
    {
        vector<int> v; //vector容器
        v.push_back(10); //尾插
        v.push_back(20);
        v.push_back(30);
        v.push_back(40);
        v.push_back(50);
    
        printVector(v);
    
        vector<int> v1 = v;  //v1(v)
    
        printVector(v1);
    
        vector<int> v2(v1.begin(), v1.end());
        printVector(v2);
    
        vector<int> v3(3,99);
        printVector(v3);
    
         v1 = v3;
         printVector(v1);
    
         v1.assign(v2.begin(), v2.end());
         printVector(v1);
    
         v1.assign(6,8);
         printVector(v1);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    102.4 vector的容量大小

    empty();	//判断是否为空
    size();		//容器的大小,元素的个数
    capacity();	//容量的大小
    resize();	//重新设置大小 
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    102.5 vector的插入和删除

    函数原型:
    	push_back();					//尾插
    	pop_back();						//尾删
    	insert(iterator pos, elem);		//在迭代器所指向的位置,插入数据
    	insert(iterator pos, n, elem);	//在迭代器所指向的位置,插入n个数据
    	erase(v.begin(), v.end());		//把这个区间的数据删除
    	clear();						//清空
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    示例 :

    #include 
    #include   //包含头文件vector
    using namespace std;
    
    void printVector(vector<int> &v) //算法
    {
        vector<int>::iterator iter; //迭代器
        for(iter = v.begin(); iter != v.end(); iter++)
        {    cout << *iter << " ";    }
        cout << endl;
    }
    int main()
    {
        vector<int> v; //vector容器
        v.push_back(10); //尾插
        v.push_back(20);
        v.push_back(30);
        v.push_back(40);
        v.push_back(50);
    
        printVector(v);
    
        vector<int> v1 = v;  //v1(v)
    
        printVector(v1);
    
        vector<int> v2(v1.begin(), v1.end());
        printVector(v2);
    
        vector<int> v3(3,99);
        printVector(v3);
    
         v1 = v3;
         printVector(v1);
    
         v1.assign(v2.begin(), v2.end());
         printVector(v1);
    
         v1.assign(6,8);
         printVector(v1);
         
         if(!v1.empty())
         {
             cout << v1.size() << endl;
             cout << v1.capacity() << endl;
         }
         v1.resize(3);
         printVector(v1);
    
         v1.push_back(99);
         printVector(v1);
    
         v1.pop_back(); //尾删
         printVector(v1);
    
         printVector(v2);
         v2.insert(v2.begin()+1,99);
         printVector(v2);
    
         v2.insert(v2.begin()+3,3,99);
         printVector(v2);
    
         v2.erase(v2.begin()+2);
         printVector(v2);
         cout << "=====================" << endl;
         //v2.erase(v2.begin(),v2.end());
         //printVector(v2);
         v2.clear();
         printVector(v2);
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    102.6 vector的元素提取

    函数原型
    	at(int idx);			//下标为 idx 的元素
    	operator[](int idx);
    	front();				//第一个元素
    	back();					//最后一个元素
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    一百零三、list

    103.1 概念

    • 功能:将数据进行链式存储

    • 链表(list) : 是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的。

    • 链表的组成 :链表由一系列节点组成

    • 节点的组成 :一个是存储数据元素的数据域,另一个是存储下一个节点地址的指针域

    • STL中的链表是一个双向链循环链表

    • list的优点:

      • 采用动态存储分配,不会造成内存浪费和溢出
      • 链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素-
    • list缺点:

      • 链表灵活,但是空间(指针域)和 时间(遍历)额外消耗比较大

    103.2 list构造函数

    函数原型:
    	list lst; //无参构造函数
    	list(beg, end); //构造函数将[begin,end)区间中对的元素拷贝给本身
    	list(n, elem); //构造函数将n个elem拷贝给本身
    	list(const list& l); //拷贝构造函数
    
    • 1
    • 2
    • 3
    • 4
    • 5

    103.3 list赋值和交换

    函数原型:
    	assign(beg, end); //将[beg,end)区间中的数据拷贝赋值给本身
    	assign(n, elem); //将n个elem拷贝赋值给本身
    	list& operator=(const list &lst); //重载赋值符
    	swap(lst); //将lst与本身的元素互换
    
    • 1
    • 2
    • 3
    • 4
    • 5

    103.4 list大小操作

    函数原型:
    	size();				//返回容器中元素的个数
    	empty();			//判断容器是否为空
    	resize(num);		//重新指定容器的长度为um,若容器变长,则以默认值填充新空间
    						//如果容器变短,则末尾超出容器长度的元素则被删除
    	resize(num, elem);	//重新指定容器的长度为num,若容器变长,则以elem值填充新空间
    						//如果容器变短,则末尾超出容器的元素被删除。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    103.5 list插入和删除

    函数原型:
    push_back();						//尾部插入元素
    pop_back();							//删除最后一个元素
    push_front(elem);					//在容器的开头插入一个元素
    pop_front();						//在容器的开头删除一个元素
    insert(const_iterator pos, ele);	//迭代器指向位置pos插入元素ele
    insert(const_iterator pos, int count, ele);	//迭代器指向位置pos 插入count个元素ele
    insert(pos,beg, end);				//在pos位置插入[beg,end)区间的数据,无返回值。
    erase(const_iterator pos);			//删除迭代器指向的元素
    erase(const_iterator start, const_iterator end);	//删除迭代器从start到end之间的元素
    clear();							//删除容器中所有的元素
    remove(elem);						//删除容器中所有与elem值匹配的元素。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    103.6 list 数据存取

    函数原型:
    front(); //返回第一个元素
    back(); //返回最后一个元素
    
    • 1
    • 2
    • 3

    一百零四、C++文件操作

    • 文件相关的头文件 #include
    • 文件相关的三大类
      • 读文件 ifstream
      • 写文件 ofstream
      • 读写文件 fstream

    104.1 写入数据

    1. 包含头文件
      #include
    2. 创建流对象
      ofstream ofs;
    3. 打开文件
      ofs.open(“文件名路径” , 打开方式);
      打开方式 :ios::out
    • 文件的打开方式 :
      在这里插入图片描述
    1. 写入数据
      ofs << 数据
    2. 关闭文件
      ofs.close();

    104.2 读取数据

    1. 包含头文件
      #include

    2. 创建流对象
      ifstream ifs;

    3. 打开文件
      ifs.open(“文件名路径” , 打开方式);
      ios::in

    4. 读取数据
      ifs >> 存放的变量

    5. 关闭文件
      ifs.close();

    104.3 示例

    #include 
    //1.包含头文件
    #include 
    using namespace std;
    
    int main()
    {
        //写入数据
        //2.创建流对象
        ofstream ofs;
        //3.打开文件
        ofs.open("C:/Users/admin/Desktop/stu.txt",ios::out);
        //4.写入数据
        ofs << "姓名:张三  ";
        ofs << "年纪:18"  << endl;
        //5.关闭文件流
        ofs.close();
    
        //2.创建流对象
        ifstream ifs;
        //3.打开文件
        ifs.open("C:/Users/admin/Desktop/stu.txt",ios::in);
        //4.读取数据
        char buff[1024];
        while (ifs >> buff)
        {
            cout << buff << endl;
        }
        //5.关闭文件流
        ifs.close();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
  • 相关阅读:
    Git常用操作
    Redis 7 第八讲 集群模式(cluster)架构篇
    vue 插槽 - 具名插槽
    LeetCode【41】缺失的第一个正数
    js如何区分数组和对象
    查看当前所有的数据库
    flutter出现entrypoint isn‘t within the current project
    对于云原生时代的后端业务开发和项目系统学习,选Go Or Java?
    Linux下运行Java Jar程序
    C++初阶 Vector模拟实现
  • 原文地址:https://blog.csdn.net/qq_52625576/article/details/133826088