• C++ 基础二


    四、流程控制语句

    顺序结构、选择结构、循环结构
    
    • 1

    4.1 选择结构

    4.1.1 if语句

    用于执行基于条件的代码块。
    
    • 1

    if语句的三种形式
    单行格式if语句
    多行格式if语句
    多条件的if语句

    (1).单行格式if语句:if(条件){ 条件满足执行的语句 }
    if条件表达式后不要加分号
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    if (sum==100)
    	{
    	  cout<<"sum=="<<100<<endl;
    	}
    
    • 1
    • 2
    • 3
    • 4

    ( 2 ) .多行格式if语句:

    `if(条件){ 条件满足执行的语句 }
    else{ 条件不满足执行的语句 };`
    
    • 1
    • 2

    ( 3 ).多行格式if语句:

    `if(条件){ 条件满足执行的语句 }
    else{ 条件不满足执行的语句 };`
    
    • 1
    • 2

    4.1.2 三目运算符

    语法:表达式1 ? 表达式2 :表达式3

    	int a = 10;
    	int b = 20;
    
    	int c = a > b ? a : b;
    	cout << "c = " << c << endl;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4.1.3 switch语句

    switch - case

    每个case标签之后不会自动执行到下一个case标签,除非使用break语句来显式终止switch块。

    switch(表达式)
    
    {
    
    	case 结果1:执行语句;break;
    
    	case 结果2:执行语句;break;
    
    	...
    
    	default:执行语句;break;
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    举例代码:

    #include 
    
    int main() {
        int choice = 2;
    
        switch (choice) {
            case 1:
                std::cout << "选项1" << std::endl;
            case 2:
                std::cout << "选项2" << std::endl;
            case 3:
                std::cout << "选项3" << std::endl;
            default:
                std::cout << "默认选项" << std::endl;
        }
    
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    这是因为没有break语句来终止case标签,导致控制流“直通”到后续的case标签。如果您想要避免这种行为,应在每个case块的末尾使用break语句来显式退出switch块。

    注意事项

    1. switch语句中的表达式类型通常只能是整型或字符型。这是因为case标签中的常量值需要与表达式的类型匹配。

    2. 如果在case标签中没有使用break语句,程序会继续执行下一个case标签,这就是所谓的“直通”行为。

    3. switch语句在处理多个条件判断时具有结构清晰和执行效率高的优点。它适用于在一系列离散值中选择执行不同的代码块。

    4. 一个switch语句的缺点是它不能直接判断区间,只能针对离散的值进行判断。要处理区间,通常需要使用一系列if语句或其他逻辑结构。

    这些特点使switch成为一种适用于某些情况下的有效控制结构,但在其他情况下可能需要使用不同的条件控制方式。

    4.1.4 if和switch的区别【CHAT】

    `if`更灵活,适用于各种条件逻辑,
    `switch`更适用于多个等值条件的情况下,代码更具可读性。
    
    • 1
    • 2
    1. 用法

      • if语句适用于任何条件判断,可以处理各种复杂的条件表达式,包括比较、逻辑运算等。它可以用来实现灵活的条件控制。
      • switch语句通常用于根据一个表达式的不同值来选择执行不同的代码块。它适用于多个等值条件的情况。
    2. 条件

      • if语句可以处理各种条件,包括布尔表达式、比较表达式、逻辑表达式等,可以实现更灵活的条件逻辑。
      • switch语句通常用于处理整数或字符类型的表达式,用于离散的值判断,而不适用于范围或其他类型的条件。
    3. 多条件

      • if语句可以轻松处理多个条件,通过嵌套if语句或使用else if来实现多个条件分支。
      • switch语句通过多个case标签来处理多个等值条件,通常更适用于处理相对简单的多条件情况。
    4. 可读性

      • switch语句通常在处理多个等值条件时更具可读性,因为所有条件都集中在一起。
      • if语句用于处理复杂的条件逻辑时可能需要更多的嵌套,可读性可能较差。
    5. 执行流程

      • if语句是根据条件的真假来决定是否执行某个代码块。
      • switch语句是基于表达式的值来选择执行哪个case块,然后执行该块内的代码,之后需要使用break语句来终止switch块,否则会"直通"到下一个case

    综上所述,选择使用if还是switch取决于您的需求。

    4.2 循环结构

    4.2.1 while循环语句

    语法: while(循环条件){ 循环语句 }
    在这里插入图片描述

    int num = 0;
    	while (num < 10)
    	{
    		cout << "num = " << num << endl;
    		num++;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    执行循环语句时确实必须提供跳出循环的出口,否则可能会陷入死循环,导致程序永远不会停止执行。以下是一些常见的方法来实现循环的退出

    4.2.2 do…while循环语句

    语法: do{ 循环语句 } while(循环条件);
    与while的区别在于do…while会先执行一次循环语句,再判断循环条件
    在这里插入图片描述

    4.2.3 for循环语句

    语法: for(起始表达式;条件表达式;末尾循环体) { 循环语句; }
    for循环中的表达式,要用分号进行分隔

    九九乘法表

    在这里插入图片描述
    在这里插入图片描述

    4.3 跳转语句

    4.3.1 break语句

    1. switch语句中:break语句用于终止当前的case标签块,并跳出switch语句。这可以防止"直通"到下一个case标签。

    2. 在循环语句中(如forwhiledo-while):break语句用于提前跳出当前循环,即使循环条件仍然满足。它用于终止循环的执行,使程序流程进入循环后的下一个语句。

    3. 在嵌套循环中:如果存在多个嵌套循环,break语句通常跳出最近的内层循环,而不是整个外层循环。这允许您有选择性地退出嵌套循环中的一个循环,而不必退出所有嵌套层次。

    break语句是控制流的重要工具,用于在满足特定条件时改变程序的执行路径。要注意,滥用break可能会导致代码难以理解和维护,因此应该慎重使用。

    4.3.2 continue语句

    continue并没有使整个循环终止,而break会跳出循环

    4.3.3 goto语句:- goto关键字。

    语法: goto 标记;

    `goto`语句是一种在编程中用来无条件跳转到程序中的标记(label)处的控制语句。
    
    • 1
    goto 标记;
    
    • 1
    • 标记是在程序中的一个标签,通常是一个带有冒号的标识符,例如 label:

    使用goto语句可以使程序跳转到指定标记的位置,继续执行代码。这可以在某些情况下用于实现特定的控制流程,但要小心使用,因为滥用goto可能导致程序难以理解和维护,产生不可预测的行为。

    大多数现代编程语言鼓励避免使用goto,并提供更结构化的控制结构,如条件语句和循环,以更清晰和可维护的方式实现控制流程。在实际编程中,通常不需要使用goto,并且可以通过其他方法来实现相同的目标。

    五、数组

    同样的数组在C++11后也是可以省略掉“=”号的double num[3]{1.2e4,2e1,1.2,3.3};
    类型、数组名、数量
    只有在定义数组时才能使用初始化,此后就不能使用了,也不能将一个数组赋给另一个数组

    //可以:
    int a[2]={1,2};
    int b[2];
    //不可以
    b[2]={2.1}
    b=a;
    //其中的97虽然看起来是整数,但是其是应该转换的字符
    char arr[4]{'h',97,'\n','1}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    (1)数据类型相同: 数组中的每个数据元素都必须是相同的数据类型。这意味着如果您创建一个整数数组,每个元素都必须是整数;如果是字符数组,每个元素都必须是字符,以此类推。

    (2)连续内存跑【要确保只使用有效的下标值】: 数组的元素在内存中是连续存储的,这意味着数组中的元素在内存中相邻,没有额外的空间分隔它们。这也是数组的一个重要特点,因为它允许通过索引来快速访问元素,索引值可用于计算元素的内存地址。

    5.1 一维数组

    一维数组定义的三种方式:

    1. 数据类型 数组名[ 数组长度 ];
    2. 数据类型 数组名[ 数组长度 ] = { 值1,值2 ...};
    3. 数据类型 数组名[ ] = { 值1,值2 ...};

    (1). 可以统计整个数组在内存中的长度sizeof(arr) / sizeof(arr[0])
    (2)可以获取数组在内存中的首地址(int)arr
    在这里插入图片描述

    CLion中有错误:cast from ‘int*’ to ‘int’ loses precision [-fpermissive]问题解决

    该这里是因为基于Linux内核的64位系统上指针类型占用8个字节,而int类型占用4个字节,所以会出现loses precision。

    可以先将int* 转成long类型,long类型可以隐式类型转换到int类型。直接修改为long long即可

    cout << "数组首地址为:" << (long long)arr << endl;  
    cout << "数组第一个元素地址为:" << (long long)&arr[0] << endl;
    cout << "数组第二个地址为:" << (long long)&arr[1] << endl;
    
    • 1
    • 2
    • 3

    冒泡排序

    int main() {
    
    	int arr[9] = { 1,7,5,3,4,8,6,2,3};
    
    	for (int i = 0; i < 9 - 1; i++)
    	{
    		for (int j = 0; j < 9 - 1 - i; j++)
    		{
    			if (arr[j] > arr[j + 1])
    			{
    				int temp = arr[j];
    				arr[j] = arr[j + 1];
    				arr[j + 1] = temp;
    			}
    		}
    	}
    
    	for (int i = 0; i < 9; i++)
    	{
    		cout << arr[i] << endl;
    	}
        
    	system("pause");
    
    	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

    C语言内置的qsort

    #include 
    #include 
    
    // 比较函数,用于告诉qsort如何比较元素
    int compare(const void *a, const void *b) {
        return (*(int *)a - *(int *)b);
    }
    
    int main() {
        int arr[] = {5, 2, 9, 1, 5, 6};
        int length = sizeof(arr) / sizeof(arr[0]);
    
        // 使用qsort对整数数组进行升序排序
        qsort(arr, length, sizeof(int), compare);
    
        // 打印排序后的数组
        printf("排序后的数组:");
        for (int i = 0; i < length; ++i) {
            printf("%d ", arr[i]);
        }
        printf("\n");
    
        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

    5.2 二维数组

    二维数组定义的四种方式:

    1. 数据类型 数组名[ 行数 ][ 列数 ];
    2. 数据类型 数组名[ 行数 ][ 列数 ] = { {数据1,数据2 } ,{数据3,数据4 } };
    3. 数据类型 数组名[ 行数 ][ 列数 ] = { 数据1,数据2,数据3,数据4};
    4. 数据类型 数组名[ ][ 列数 ] = { 数据1,数据2,数据3,数据4};

    5.3 数组的替代品(1)vector

    普通数组的大小在编译时确定且不可变,而vector的大小在运行时动态变化。此外,vector提供了许多便利的方法来管理元素,如动态添加、删除和访问元素。

    #include 
    #include 
    
    using namespace std;
    
    int main() {
        vector<int> numbers = {1, 2, 3, 4, 5};
    
        for (int number : numbers) {
            cout << number << " ";
        }
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    举例子说明区别,最好对比

    #include 
    #include 
    
    using namespace std;
    
    int main() {
        // 普通数组
        int arr[3] = {1, 2, 3};
        arr[2] = 4;  // 可以修改元素的值
        // arr = {1, 2, 4};  // 无法直接改变数组的大小
        cout<<arr<<endl;
    
        // vector
        vector<int> numbers = {1, 2, 3};
        numbers.push_back(4);  // 可以动态添加元素
        // numbers = {1, 2, 3, 4};  // 大小可以动态改变
    //    cout<
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在C++中,cout 不能直接输出整个 vector 对象,因为 vector 是一个复杂的数据结构,而 cout 无法直接处理它。要输出 vector 中的元素,您需要使用循环或迭代器来逐个输出元素。

    #include 
    #include 
    
    using namespace std;
    
    int main() {
        // 普通数组
        int arr[3] = {1, 2, 3};
        arr[2] = 4;  // 可以修改元素的值
        cout << "Array: ";
        for (int i : arr) {
            cout << i << " ";
        }
        cout << endl;
    
        // vector
        vector<int> numbers = {1, 2, 3};
        numbers.push_back(4);  // 可以动态添加元素
        cout << "Vector: ";
        for (int number : numbers) {
            cout << number << " ";
        }
        cout << 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
    • 24
    • 25
    • 26

    在这里插入图片描述

    5.3 数组的替代品(2)array对象

    #include 
    #include 
    
    using namespace std;
    
    int main() {
        // 使用模板类 array
        array<int, 3> arr = {1, 2, 3};
        arr[2] = 4;  // 可以修改元素的值
        cout << "Array: ";
        for (int i : arr) {
            cout << i << " ";
        }
        cout << endl;
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    5.4 比较数组、vector对象和array对象

    // 在 C++ 中,数组、vector 对象和 array 对象都可以用来存储一系列的元素。
    
    // 1. 数组(Array)是一种静态数据结构,其大小在编译时确定,不可改变。
    int arr[5]; // 声明一个包含 5 个整数的数组
    
    // 2. vector 对象是 C++ 标准库中的动态数组,其大小可以动态增长或缩小。
    #include 
    std::vector<int> vec; // 声明一个整数类型的 vector 对象
    
    // 3. array 对象是 C++ 标准库中的固定大小数组,其大小在编译时确定,但提供了更多的操作函数。
    #include 
    std::array<int, 5> arr; // 声明一个包含 5 个整数的 array 对象
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    #include 
    #include 
    #include 
    
    int main() {
        // 操作数组
        int arr[5] = {1, 2, 3, 4, 5};
        std::cout << "Array elements: ";
        for (int i : arr) {
            std::cout << i << " ";
        }
        std::cout << std::endl;
    
        // 操作 vector 对象
        std::vector<int> vec = {1, 2, 3, 4, 5};
        std::cout << "Vector elements: ";
        for (int i : vec) {
            std::cout << i << " ";
        }
        std::cout << std::endl;
    
        // 操作 array 对象
        std::array<int, 5> arrObj = {1, 2, 3, 4, 5};
        std::cout << "Array elements using range-based for loop: ";
        for (int num : arrObj) {
            std::cout << num << " ";
        }
        std::cout << std::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
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    六、字符串

    风格

    /*【1】c语言的*/
    //(1)每个单引号至少一个字符,空字符停止
    char arr[4] = {'a','s','c','\0'};
        cout<<arr;
     //   (2)字符串常量或者字符串字面量用双引号扩起的
     char brr[]="hello world";
     char crr[3]="aa";//因为需要结束
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述
    拼接
    在这里插入图片描述

    注意,拼接时不会在被连接的字符串之间添加空格,第二个字符串的第一个字符将紧跟在第一个字符串的最后一个字符(不考虑\0)后面。第一个字符串中的\0字符将被第二个字符串的第一个字符取代。

    每次读一行getline()

    在C++中,getline()函数是std::istream类的一个成员函数,用于从输入流中读取一行文本。这个函数可以读取换行符之前的所有字符,并将其存储在给定的字符数组中。

    getline()函数有两个参数:

    第一个参数是一个指向字符数组的指针,这个数组用于存储从输入流中读取的文本。
    第二个参数是最大的读取字符数。如果这个数字为20,那么函数最多会读取19个字符,因为最后一个位置需要存储空字符(‘\0’)。

    #include   
    #include   
      
    int main() {  
        char buffer[20];  
        std::cin.getline(buffer, 20);  
        std::cout << "You entered: " << buffer << '\n';  
        return 0;  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    string类

    char arr[]={"12"}
    char arr[]{"12"}
    string vrr={"dws"}
    string vrr{"dws"}
    
    • 1
    • 2
    • 3
    • 4

    使用string类时,某些操作比使用数组时更简单。例如,不能将一个数组赋给另一个数组,但可以将一个string对象赋给另一个string对象:

    七、函数

    将一段经常使用的代码封装起来,减少重复代码
    
    • 1

    (cpp中的模块)

    返回值类型 函数名 (参数列表)
    {
    
           函数体语句
    
           return表达式
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    int add(int num1, int num2)
    {
        //函数体语句
    	int sum = num1 + num2;
        //return表达式
    	return sum;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    调用 函数名(参数)

    int add(int num1, int num2) //定义中的num1,num2称为形式参数,简称形参(形参列表)
    {
        int sum = num1 + num2;
        return sum;
    }
    
    int add(int num1, int num2, int num3) {
        int sum = num1 + num2 + num3;
        return sum;
    }
    
    int main() {
    
        int a = 10;
        int b = 10;
        //调用add函数
        int sum = add(a, b);//调用时的a,b称为实际参数,简称实参
        cout << "sum = " << sum << endl;
    
        int sum1 = add(a, b, 10);
        cout << "sum1 = " << sum1 << endl;
    
        a = 100;
        b = 100;
    
        sum = add(a, b);
        cout << "sum = " << sum << endl;
    
        system("pause");
    
        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

    值传递

    值传递时,形参是修饰不了实参的

    形参无论发生什么变化都不会影响实参

    void swap(int num1, int num2)
    {
    	cout << "交换前:" << endl;
    	cout << "num1 = " << num1 << endl;
    	cout << "num2 = " << num2 << endl;
    
    	int temp = num1;
    	num1 = num2;
    	num2 = temp;
    
    	cout << "交换后:" << endl;
    	cout << "num1 = " << num1 << endl;
    	cout << "num2 = " << num2 << endl;
    
    	//return ; 当函数声明时候,不需要返回值,可以不写return
    }
    
    int main() {
    
    	int a = 10;
    	int b = 20;
    
    	swap(a, b);
    
    	cout << "mian中的 a = " << a << endl;
    	cout << "mian中的 b = " << b << endl;
    
    	system("pause");
    
    	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

    在这里插入图片描述

    如果想要改变实参 – 互换地址的内容:

    void swap(int num1, int num2)
    {
        cout << "交换前:" << endl;
        cout << "num1 = " << num1 << endl;
        cout << "num2 = " << num2 << endl;
        cout << "&num1="<< &num1<<endl;
        cout << "&num2="<< &num1<<endl;
    
    
        int temp = num1;
        num1 = num2;
        num2 = temp;
        cout << "&temp="<<&temp<<endl;
    
        cout << "交换后:" << endl;
        cout << "num1 = " << num1 << endl;
        cout << "num2 = " << num2 << endl;
        cout << "&num1="<< &num1<<endl;
        cout << "&num2="<< &num1<<endl;
    
        //return ; 当函数声明时候,不需要返回值,可以不写return
    }
    
    int main() {
    
        int a = 10;
        int b = 20;
    
        swap(a, b);
    
        cout << "mian中的 a = " << a << endl;
        cout << "mian中的 b = " << b << endl;
        cout << "&a="<< &a<<endl;
        cout << "&b="<< &b<<endl;
        system("pause");
    
        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

    在这里插入图片描述

    八、结构体

    
    #include 
    
    using namespace std;
    struct student{
        string name;
        int age;
        double  score;
        //...
    };
    void printStudent(student stu){
        cout << "name: " << stu.name << endl;
        cout << "age: " << stu.age << endl;
        cout << "score: " << stu.score << endl<<endl;
    }
    int main() {
        student stu;
        stu.name = "Y";
        stu.age = 20;
        stu.score = 99.5;
    
        student stu2{"Jerry", 19, 99.5};
        printStudent(stu);
        printStudent(stu2);
        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

    在这里插入图片描述
    结构是用户定义的类型,而结构声明定义了这种类型的数据属性。定义了类型后,便可以创建这种类型的变量。因此创建结构包括两步。首先,定义结构描述–它描述并标记了能够存储在结构中的各种数据类型。然后按描述创建结构变量(结构数据对象)。

    8.2 结构体中的带上一个

    #include 
    using namespace std;
    
    struct teacher{
        string name="T";
        int age=12;
    };
    
    struct student{
        string name;
        int age;
        double  score;
        teacher t;
    };
    
    void printStudent(student stu){
        cout << "name: " << stu.name << endl;
        cout << "age: " << stu.age << endl;
        cout << "score: " << stu.score << endl<<endl;
        cout<<"teacher's name: "<<stu.t.name<<endl;
        cout<<"teacher's age: "<<stu.t.age<<endl;
        cout<<endl;
    }
    
    int main() {
        student stu;
        stu.name = "Y";
        stu.age = 20;
        stu.score = 90;
    
        student stu2{"LZ", 19, 99.5, {"Tom", 30}};
        printStudent(stu);
        printStudent(stu2);
        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

    在这里插入图片描述

    九、共用体

    union 的大小取决于其成员中占用空间最大的那个成员的大小。这是因为 union 中所有成员共享同一块内存,因此为了能够容纳最大的成员,整个 union 的大小会被设置为最大成员的大小。

    //
    // Created by 86156 on 2023/12/26.
    //
    #include 
    
    using namespace std;
    union test01 {
        int int_testa;
        long long_testa;
        char char_testa;
        double double_testa;
        float float_testa;
        bool bool_testa;
    
    };
    
    int main() {
        union test01 test01;
        test01.int_testa = 10;
        cout << test01.int_testa <<" "<< typeid(test01.int_testa).name() <<" "<<&test01.int_testa<<endl;
        cout << test01.long_testa <<" "<< typeid(test01.int_testa).name() <<" "<<&test01.int_testa<<endl;
        cout << test01.char_testa <<" "<< typeid(test01.int_testa).name() <<" "<<&test01.int_testa<<endl;
        cout << test01.double_testa <<" "<< typeid(test01.int_testa).name() <<" "<<&test01.int_testa<<endl;
        cout << test01.float_testa <<" "<< typeid(test01.int_testa).name() <<" "<<&test01.int_testa<<endl;
        cout << test01.bool_testa <<" "<< typeid(test01.int_testa).name() <<" "<<&test01.int_testa<<endl;
    }
    
    
    • 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

    在这里插入图片描述
    sizeof(test01.int_testa) 返回的是 int_testa 的大小,而 sizeof(test01) 返回的是整个 union 的大小。在这个例子中,int_testa 的大小是 4 字节,而整个 union 的大小是 8 字节,因为它会被对齐到最大的成员的大小。
    在这里插入图片描述
    union 的大小取决于其成员中占用空间最大的那个成员的大小。这是因为 union 中所有成员共享同一块内存,因此为了能够容纳最大的成员,整个 union 的大小会被设置为最大成员的大小。
    在这里插入图片描述

    十、引用

    作用:起别名

    C++ 中的引用本质上是一个别名,
    它允许我们通过一个变量名访问另一个变量的内容。
    引用在声明时必须初始化,
    并且一旦初始化后就不能再指向其他变量。
    引用通常用于函数参数传递和返回值,
    以及在某些情况下作为变量的别名使用_**

    写法:数据类型 &别名 = 原名

    int main() {
        int a=10;
        int &b=a;
        int* c=&a;
        int* d=&b;
        cout<<a<<" "<<&a<<" "<<*(&a)<<endl;
        cout<<b<<" "<<&b<<" "<<*(&b)<<endl;
        cout<<c<<" "<<&c<<" "<<*c<<endl;
        cout<<d<<" "<<&d<<" "<<*d<<endl<<endl;
    
        a=200;
        cout<<a<<" "<<&a<<" "<<*(&a)<<endl;
        cout<<b<<" "<<&b<<" "<<*(&b)<<endl;
        cout<<c<<" "<<&c<<" "<<*c<<endl;
        cout<<d<<" "<<&d<<" "<<*d<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    第一段cout输出了变量a的值、地址和解引用值,以及引用b的值、地址和解引用值,指针c的值、地址和解引用值,以及指针d的值、地址和解引用值。

    第二段cout输出了变量a的新值、地址和解引用值,引用b的值、地址和解引用值,指针c的值、地址和解引用值,以及指针d的值、地址和解引用值。

    在这里插入图片描述

    10.1 注意事项

    1. 引用必须初始化,不能像指针一样,先声明后赋值。
    2. 引用一旦初始化后,就不能再指向其他变量。
    3. 引用必须与被引用的变量具有相同的类型。
    
    • 1
    • 2
    • 3
    #include 
    
    using namespace std;
    int main(){
        int a=12;
        int &b=a;
        int c=213;
    
    //   将变量b赋值为c实际上是一个赋值操作,而不是更改引用。
    //因为引用不允许更改,所以这行代码实际上将a的值改为了c的值,
    //而不是改变了引用b指向的变量。
    
        b=c;
        cout<<a<<endl;
        cout<<b<<endl;
        cout<<c<<endl;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    10.1.1 为什么不可改变

    个整数变量a,并且创建了一个引用ref指向a。在main函数中,a被赋值为20,然后输出a和ref的值。接着调用了func函数,该函数接受一个整数的引用,并将其值设为100。

    #include 
    
    using namespace std;
    //转换为 int* const ref =&a;
    void func(int& ref){
        ref=100; //转换为 *ref=100;
    }
    int main(){
    
        int a=10;
        //指针常量是指向不可以更改(值可以更改是什么),说明了为什么引用不课更改哦
        int &ref=a;
        ref=20; // *ref=20;
    
        cout<<a<<endl;
        cout<<ref<<endl;
        func(ref);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    十一、引用做函数参数

    11.1. 值传递

    #include 
    using namespace std;
    
    void swap(int a, int b) {
        int temp = a;
        a = b;
        b = temp;
    }
    
    int main() {
        int x = 10;
        int y = 20;
        swap(x, y);
        cout << "x = " << x << ", y = " << y << endl;
        return 0;
    }   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    11.2地址传递

    #include 
    using namespace std;
    
    void swap(int *a, int *b) {
        int temp = *a;
        *a = *b;
        *b = temp;
    }
    
    int main() {
        int x = 10;
        int y = 20;
        swap(&x, &y);
        cout << "x = " << x << ", y = " << y << endl;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    11.3 引用传递

    #include 
    using namespace std;
    
    void swap(int &a, int &b) {
        int temp = a;
        a = b;
        b = temp;
    }
    
    int main() {
        int x = 5;
        int y = 10;
        cout << "Before swap: x = " << x << ", y = " << y << endl;
        swap(x, y);
        cout << "After swap: x = " << x << ", y = " << y << endl;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    引用传递和地址传递都可以用来在函数间传递参数,但它们有一些重要的区别:

    1. 关系和区别:
    • 引用传递:使用引用作为参数,可以直接操作原始变量,不需要通过指针来访问。在函数内部对引用的修改会影响原始变量。
    • 地址传递:使用指针作为参数,需要通过解引用操作来访问原始变量,需要注意指针的空值和指针算术运算。
    1. 用法上需要注意的:
    • 引用传递:需要注意避免悬空引用(指向已释放的内存)和引用的生命周期问题。
    • 地址传递:需要注意指针的空值和指针算术运算,以及指针的生命周期管理。

    在使用时,引用传递更直观和安全,而地 址传递更灵活,可以实现更复杂的功能,但需要更多的注意和小心。

    11.4 引用函数做返回值

    //1.不要返回局部变量的引用。
    //2.函数的调用作为左值

    在函数test02中,使用static关键字声明了一个静态变量a,并返回了它的引用。这意味着可以将函数test02的返回值作为左值使用,可以对其进行赋值操作,就像对变量一样。在main函数中,演示了如何使用函数返回的引用进行赋值操作,并且对其进行加法运算。需要注意的是,静态变量的生命周期延长到程序结束,因此在整个程序执行过程中,test02函数返回的引用都指向同一个静态变量。

    #include 
    //引用函数的返回值:
    
    using namespace std;
    //1.不要返回局部变量的引用。
    //int& test01(){
    //    int a=10;
    //    return a;
    //}
    
    //2.函数的调用作为左值
    int &test02() {
        static int a = 1022;//static 静态变量不在栈上,再全局去,会再程序结束后释放
        return a;
    }
    
    int main() {
    //    int &a=test01();
        int &a2 = test02();
        cout << a2 << endl;
        cout << test02() << endl;
    //函数的返回追是引用,这函数的调用苦于作为左值
    
    /*    函数 test02() 返回的是一个引用,因此可以将函数调用作为左值使用。
        这意味着你可以对函数返回的引用进行赋值操作,就像对变量一样。
        在这段代码中,test02() 函数返回的引用可以被赋值给其他变量,也可以直接被赋值。*/
        test02() = 990;
        cout << test02() << endl;
        cout << a2 + 9 << endl << endl;
    
    
        int c = test02();
        cout << test02() << endl;
        cout << c << endl;
        test02() = 1;
        cout << test02() << endl;
        cout << c << 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
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    11.5 引用的本质

    C++中的引用在内部实际上被实现为指针变量。

    //转换为 int* const ref =&a;
    void func(int& ref){
        ref=100; //转换为 *ref=100;
    }
    int main(){
        
        int a=10;
        //指针常量是指向不可以更改(值可以更改是什么),说明了为什么引用不课更改哦
        int &ref=a;
        ref=20;
        
        cout<
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    看05.cpp的介绍

    11.6常量引用

    常量引用在C++中的存在有几个目的:

    1. 防止意外修改:常量引用可以用来传递参数,同时防止被调用函数意外修改传入的数值。
      防止形参改变实参
      2节约内存:使用常量引用可以避免在函数调用时产生参数的副本,从而节约内存和提高效率。
    2. 与C语言兼容:C++中的常量引用也可以用于与C语言的接口交互,以便在C++中使用C语言的函数和数据结构。
    #include 
    using namespace std;
    // 通过常量引用传递参数,防止意外修改
    // 通过引用修改传入的值的函数
    void displayValue1(int &value) {
        value = 10; // 将传入的值修改为10
        cout << "Value: " << value << endl << endl; // 输出修改后的值
    }
    
    // 通过常量引用显示传入的值的函数
    void displayValue2(const int &value) {
        // value = 10; // 这行被注释掉,因为不允许修改常量引用
        cout << "Value: " << value << endl; // 输出传入的常量引用的值
    }
    
    int main() {
        const int& ref = 10; // 创建一个指向值为10的常量引用 ref
    
        int num = 5; // 用值5初始化变量 num
        cout << "Value: " << num << endl; // 输出 num 的初始值
        displayValue1(num); // 调用函数修改 num 的值
    
        displayValue2(num); // 调用函数显示 num 的值
        cout << "Value: " << num << endl; // 输出 num 的最终值
        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

    示了如何使用常量引用来防止意外修改参数。在函数displayValue1中,参数value被声明为非常量引用,试图修改它会导致编译错误。而在函数displayValue2中,参数value被声明为常量引用,因此试图修改它也会导致编译错误。在main函数中,演示了如何调用这两个函数,并展示了参数num的值不会被修改。

    十二、函数

    12.1简单说明

    函数用于封装可重复使用的代码块,
    提高代码的模块化和可维护性。
    函数还可以帮助组织代码,使其更易于理解和调试。

    自定义函数示例(C++):

    #include 
    using namespace std;
    
    // 自定义函数
    int add(int a, int b) {
        return a + b;
    }
    
    int main() {
        int result = add(3, 4);
        cout << "The result is: " << result << endl;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    内置函数示例(C++):

    #include 
    #include 
    using namespace std;
    
    int main() {
        double num = 16.0;
        double squareRoot = sqrt(num); // 使用内置函数计算平方根
        cout << "The square root of " << num << " is: " << squareRoot << endl;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    12.2创造函数需要注意哪些方面

    定义(函数名、参数、返回值)、实现原型(函数体、可见性、注释)、调用。

    函数名:

    • 函数名应该能够清晰地表达函数的功能。
    • 函数名应该遵循命名规范,使用驼峰命名方式,以提高代码的可读性和可维护性。

    参数:

    • 参数应该尽可能地精简,只包含必要的参数,避免传递不必要的参数。
    • 参数应该按照重要性排序,重要的参数放在前面,不重要的参数放在后面。
    • 参数应该提供默认值,避免在函数调用时传递不必要的参数。

    返回值:

    • 返回值应该尽可能地精简,只包含必要的返回值,避免返回不必要的值。
    • 返回值应该按照重要性排序,重要的返回值放在前面,不重要的返回值放在后面。
    • 返回值应该提供默认值,避免在函数调用时传递不必要的返回值。

    实现原型:

    • 实现原型应该与定义相匹配,包括函数名、参数、返回值。
    • 实现原型应该提供详细的注释,包括函数的功能、参数的类型和含义、返回值的类型和含义。
    • 实现原型应该提供单元测试,确保函数的正确性和稳定性。

    调用:

    • 调用函数时,应该按照参数的顺序传递参数值。
    • 调用函数时,应该提供必要的参数值
    //1.>默认参数必须从右到左进行赋值
    //如果某个位置已经有了默认参数,那么从这个位置往后,从左到右都必须有默认值
    int func1(int a,int b,int c=10){
        return a+b+c;
    }
    
    
    //2.声明有默认参数,函数实现就不能有默认参数,声明和实现只能其中一个带上默认参数
    int func2(int a,int b=1,int c=20);
    int func2(int a,int b,int c){
        return a+b+c;
    }
    //占位参数
    //数据类型 函数名(数据类型){}
    void func(int a,int) {
        cout<<"hello"<<a<<endl;
    }
    int main(){
        cout<<func1(1,2 )<<endl;
        cout<<func1(1,2,13 )<<endl;
    
    
        cout<<func2(1,2 )<<endl;
        cout<<func2(1,2 ,13)<<endl;
    
    	 func(1,2);
    }
    
    • 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

    12.2.1 定义函数

    分为有无返回值的函数。

    void 函数名(参数列表)
    {
        函数体;
    }
    
    返回值类型 函数名(参数列表)
    {
        函数体;
        return 返回值;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    12.2.2 参数

    分为有参和无参函数。

    void 函数名(参数列表)
    {
        函数体;
    }
    void 函数名()
    {
        函数体;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    12.3 重载

    #include 
    
    using namespace std;
    void test01() {
            cout << "hello world_空参" << endl;
    }
    void test01(int  n) {
        for (int i = 0; i < n; ++i){
            cout << "hello world—"<<n << endl;
        }
    }
    //注意事项:
    // 函数的返回值不可以作为函数重载的条件A
    int test01(long n){
        return n+1;
    }
    float test01(float n){
        return n+1.1f;
    }
    int test02(int n){
        return n+1;
    }
    int test02(int n,int m){
        return n+m+1;
    }
    int main() {
        cout<<"test01()函数调用前"<<endl;
        test01();
        test01(5);
        cout<<"test01()函数调用完成"<<endl;
        cout<<test02(10)<<endl;
        cout<<test02(10,20)<<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
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
  • 相关阅读:
    【大数据】HDFS概述(学习笔记)
    【Vivado使用】从0开始 综合后生成门级网表
    Anaconda 配置镜像源——命令大全
    了解Oracle中的Dual系统表
    uniapp使用uQRCode绘制二维码,下载到本地,调起微信扫一扫二维码核销
    机器人导航+OPENCV透视变换示例代码
    【optimtool.unconstrain】无约束优化工具箱
    Linux学习笔记(二)
    DoozyUI⭐️二十一、Input:按键输入监听组件
    PMP考前最后2天思路整理
  • 原文地址:https://blog.csdn.net/m0_74154295/article/details/133467360