• 【C++从入门到入门】C++基础:.cpp 基本结构,基本数据类型,引用,指针,函数


    C++基础笔记

    一、HelloWord.cpp 代码含义

    c++中,用于编写代码的文件为 .cpp 文件(类似于.java文件)

    
    // 这句话是预处理的操作,在源代码被编译前,替换文件
    // 相当于 Java 种的 import,导入了一个java文件
    //  中定义了 C++的输入与输出(相当于IO流)
    #include 
    
    // using 是一个编译指令,namespace 用来指定命名空间
    // 此命名空间与 Vue 的类似,也相当于 Java 的包名(浅显理解)
    using namespace std;
    
    // C++ 的程序必须含有一个 main 函数作为入口
    int main() {
    
            int age = 18;
    
            // 这里是声明了一个引用 ref,并且将 age 与 ref 绑定起来
            int& ref = age;
    
            ref += 20;
    
            // cout 是输出流,cin 是输入流
            // 如果上面么有使用 std 命名空间
            // 这里就可以书写成: std::cout 表示我要使用std里的cout函数
            // << 表示将值传给谁,箭头指向表示值的流向
            // 使用 cin 就是 cin >> ref
            // 上述含义: 接收一个命令行输入的值,赋值给 ref 变量
            cout << ref;
    }       
    
    
    • 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

    二、基本数据类型

    c++中的基本数据类型,有算术类型和空类型

    算数类型分为整型和浮点型。

    整型

    算术类型字节位备注
    short至少16位
    int至少与short一样大
    long至少32位需 ≥int
    long long至少64位需 ≥long
    char8位
    bool未定义就是Boolean类型

    浮点型

    浮点型字节位备注
    float至少32位
    double≥48至少 ≥float
    long double≥double

    无符号类型:类型前面加上 unsigned 即可表示无符号类型,无符号类型表示的最大值是有符号类型的两倍。(假设同样的内存空间,有符号类型可表示 -10 到 10。那么不带符号,也就不用表示负数,表示负数的空间就可以用来表示更大的整数,0-20)

    char:默认既不是有符号,也不是无符号。(与符号无关)
    可以在 c++ 代码中显示设定: signed char jeep; unsigned char bar;

    扩展字符型

    扩展字符型字节位备注
    wchar_t≥16宽字符
    char16_t≥16Unicode 字符集,c++11新增
    char32_t≥32Unicode 字符集,c++11新增

    注意项:

    JS将 非0,非null,非undefined看成true,Java 中的if()只能接收一个boolean类型

    c++ 将 非0 看作 true。将 true 看作1。

    c++ 中的声明与定义
    
    // 对于基本数据类型,c++ 会给 i 一个默认值0,那么也就给 i 分配了一个内存空间
    int i;
    
    // 下面代码,只是单纯的声明了 j ,不会给默认值0,也不会给 j 分配内存空间
    // 这就是声明而非定义
    extern int j;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    三、c++ 中的复合类型

    c++ 中的符合类型包括:数组,字符串,枚举,结构体,共用体,引用,指针。

    数组、字符串、枚举 与 Java 的差不多。

    1. 结构体
    
    // 通过 struct 关键字,定义了一个结构体 Cat
    // 数组只能存储同一个类型的数据,当我们需要存储不同类型数据的时候就可以使用 结构体
    //  c++的结构体和类都可以存储不同类型的数据。
    // c++的结构体和类的区别在于某些默认权限修饰符的不同(暂时理解)
    struct Cat
    {
            char name[20];
            int age;
    }
    
    // 如下,定义了一个 Cat 类型的结构体,变量名为 tom
    Cat tom = {
            "tom",
            3
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    2. 共用体

    共用体的作用:在相同的内存位置存储不同的数据类型。

    一个共用体中可定义多个不同类型的成员,但任何时候只能有一个成员含有值,共用体提供了一种使用相同内存位置的有效方式。

    和 TS 中的联合类型很相似

    
    // 通过 union 关键字,定义了一个共用体 Animal
    union Animal
    {
            Cat cat;
            Dog dog;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    3. 引用

    引用相当于变量的别名,是对一个已经存在的对象起的另一个名字。(引用与对象之间是绑定到一起的)

    
    // 定义一个 int 类型的变量 age 赋值 1
    int age = 1;
    
    // 定义了一个 int 类型的引用 ref,将 age 与 ref 绑定
    int& ref = age;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    注意项

    1. 引用不能重新绑定
    2. 引用必须初始化

    有啥用呢?

    #include 
    using namespace std;
    
    // 一个简单的 交换两个数的函数
    void transform(int a, int b) {
        int temp = a;
        a = b;
        b = temp;
    }
    
    int main() {
        int aa = 10;
        int bb = 20;
        transform(aa, bb);
        cout << aa << endl;
        cout << bb << endl;
        // 实际上输出的结果是 aa=10 bb=20
        // 这是因为 c++ 是值传递
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    
    // 一个简单的 交换两个数的函数
    void transform(int a, int b) {
        // 当调用 transform 时,传入了 aa,bb 的值
        // 使得 a = 10, b = 20,可以理解为初始化了两个新的变量
        // 这两个新变量只是内容和
        int temp = a;
        a = b;
        b = temp;
        // 执行完上述三行代码后,仅仅只是 a 和 b 的值互相交换了,
        // 并不会影响函数外的 aa bb
        cout << "a=" << a << endl;
        cout << "b=" << b << endl;
        // 输出的结果是 a=20 b=10
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    
    // 将函数声明中的参数列表更改为 (int& a, int& b)
    // 这里接收的参数就是引用
    // 当我们传入 aa 和 bb 时,就是将 引用 a 和 aa 绑定,引用 b 和 bb 绑定
    // 当转换 a 和 b 时,就转换了 aa 和 bb
    void transform(int& a, int& b) {
        //xxx
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    Java,JS 也是值传递,Java,JS 执行上述类似代码,结果是一样的,不会更改方法外面 aa bb 的值。

    值传递

    首先记录一下形参和实参。参数列表上的参数,称作形参(a和b)。传入函数的值,称作实参(aa和bb)。实参是形参的初始值。

    什么是值传递? 形参是实参的拷贝,改变形参的值不会影响外部实参的值。

    想改变值传递,可以使用引用作为形参,接收实参,操作引用就可达到操作实参的目的。

    易混淆点

    Java,JS 中的对象作为实参传入到函数的参数列表中,在函数中,调用对象的方法、属性,更改了对象中的某个属性的值。这种操作,函数外面的实参,是会变化的。这和上面描述的场景是两回事!!

    调用对象的方法、属性,形参指向的目标不会变。但是通过等号进行的赋值操作,会使形参的指向发生变化。

    引用需要注意的点

    • 引用不能重新绑定
    • 引用必须初始化
    • 可以利用引用初始化另一个引用
    • 引用类型的初始值必须是一个对象(变量)(就是说不能直接给一个引用赋值基本类型)
    • 引用的类型要和与之绑定的对象的类型严格匹配
    4. 指针

    (曾经只会Java的我一直以为指针和引用是一个东西。)

    指针也是复合类型变量的一种,英文名为 pointer。与引用类似,指针也实现了对其它对象的间接访问,但是指针和引用相比有一些不同点。

    • 指针本身就是一个对象,允许对指针赋值和拷贝,而且在指针的生命周期内,指针可以先后指向几个不同的对象。
    • 指针无需在定义时初始化。
    
    // 使用 * 定义指针,下面代码就定义了一个 int 类型的指针 ip
    int* ip;
    
    // 定义一个 int 类型的变量 temp
    int temp = 2;
    
    // 将变量 temp 的地址赋值给指针 ip
    // 在这里 & 称作 取地址符
    ip = &temp;
    
    // 这里输出的值为 2
    // * 在这里使用,被称作 解引用符
    // ip 指的是上面那个 叫 ip 的指针,*ip 才是 ip 指针指向的地址(就是temp的地址)
    // 所以通过 *ip 就能找到 temp
    // 使用 *ip 相当于使用变量 temp
     cout << *ip;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    &、*不同用法的含义记录

    符号紧随类型名出现在表达式中
    &声明引用取地址符
    *声明指针解引用符

    void类型的指针

    1. 可存任意类型对象的地址
    2. 可存任意类型的指针

    引用和指针最大的区别

    可以给指针重新赋值,指向一个新对象。
    引用不能重新赋值。

    指向指针的指针

    通过 * 的数量来区分指针的级别。
    **p 表示指向指针 *p 的指针
    ***p 表示指向 (指向指针 *p 的指针**p)的指针

    简单了解并没有验证的内容
    C 中开辟内存的函数为 malloc()
    C++ 中使用 new 关键字即可(也可使用 malloc())。
    C++ 中没有垃圾回收机制。(Java 中的GC)

    
    // 开辟了一个可以存放 int 类型变量的内存空间
    int* pn = new int;
    // 释放该空间
    delete pn;
    
    // 开辟了一个可以存放 int 类型数组的内存空间
    int* pn = new int[10];
    // 释放 pn 数组的空间
    delete[] pn;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    注意项
    使用指针的时候,要注意使用 * 解引用符得到真正的值。

    5. const

    const 是 Java 中的保留字,不是关键字。在 Java 中并没有使用到 const 的地方,只是也不让我们用而已,这种 Java 不用也不让我们用的,叫做保留字。 java 用了,不让我们用的,叫关键字。

    C++ 中 cosnt 修饰的变量不能更改,且必须初始化。(最近用 Vue3 + TS,猛写 const

    const 修饰的变量不能更改,const 修饰的类、结构体、其成员也不能改变。

    
    struct TestStruct
    {
        char name[20];
        int age;
    };
    
    void test() {
        const TestStruct temp = {
            'name',
            20
        };
        // 下面这句会报错
        // 因为 temp 被 const 修饰,所以不可更改 age 属性
        temp.age = 30;
        
        // 因为变量 temp 被 const 修饰,则指向变量 temp 的指针也应该用 const 修饰
        const TestStruct* pT = &temp;
        
        // 指针pT 调用 name 属性的话,使用 ->
        
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    6. 函数

    函数分为两类:

    1. 没有返回值的函数(Void函数)
    2. 有返回值的函数

    C++ 中的代码是从上到下顺序执行的。

    
    int main() {
        test();
    }
    
    void test() {
        int a = 20;
        cout << a;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    上述代码会报错,找不到 test() 函数,因为当 main 函数执行时,test 函数还未被加载。

    解决方式,可以将 test 函数写在 main 函数上方,也可以使用 函数声明

    函数声明
    函数声明也叫做函数原型,函数声明和函数的定义类似,唯一的区别是函数声明不需要函数体。
    (一直不太清楚前端TS中有时会需要写 .d.ts 文件是在干嘛。)

    
    // 这里就是函数的声明
    void test();
    
    int main() {
        test();
    }
    
    void test() {
        int a = 20;
        cout << a;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    函数声明一般都放在头文件 .h 中,而不是放在源文件 .cpp

    // func.h 文件中内容
    void test();
    
    • 1
    • 2
    
    // 使用 func.h 需要先 include
    #include "func.h"
    
    int main() {
        test();
    }
    
    void test() {
        int a = 20;
        cout << a;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    默认参数

    默认参数指的是函数调用时省略了实参时,自动使用的参数。

    • 默认参数必须从右边开始赋值。
    • 如果函数同时有声明和实现,默认参数只能放在函数声明中。

    内联函数

    使用 inline 关键字修饰函数的声明或实现,可以使其变为内联函数。

    内联:将函数的调用直接展开为函数体,作为代码插入调用位置。

    inline 关键字:向编译器申请,将该函数内联,但是编译器会做出检测,判断该函数是否可以内联,若检测出该函数体量大,流程繁琐,则不会内联该函数。递归就不会被内联。

    什么是函数调用的开销?
    
    当我们调用了一个函数,会先开辟栈空间,当调用完毕后,该空间被回收。从开辟空间到回收空间的过程的消耗,称为函数调用的开销。多次调用某一函数时,就会频繁的开辟,回收。将函数置为内联函数,就可以避免这部分开销。
    
    • 1
    • 2
    • 3

    内联函数使用场景:适合用于优化那些规模较小、流程直接、频繁调用的函数。
    优缺点:内联函数可以避免函数调用的开销,但是会增加代码行数。

  • 相关阅读:
    Golang 并发编程指南
    由于flutter_app依赖于flutter_swiper>=0.0.2,不支持零安全,版本解决失败。
    2022第8届中国大学生程序设计竞赛CCPC桂林站, 签到题4题
    学习MySQL-第一章
    看 Serverless Task 如何解决任务调度&可观测性中的问题
    前端缓存汇总
    字节跳动端智能工程链路 Pitaya 的架构设计
    electron + vue3 + ts 打包后安装打开白屏解决
    【minitab实战】--控制图制作
    NAVICAT 15-自动运行-自动导出EXCEL 并自动发送邮件
  • 原文地址:https://blog.csdn.net/android_zyf/article/details/127734309