C++学习笔记——语法篇

目录

一、初识C++

1、固定格式

2、第一个程序:hello world

3、注释

4、变量与常量

5、关键字/标识符

二、数据类型

1、整型

2、实型(浮点型)

3、字符型和字符串类型

4、转义字符

5、布尔类型

6、数据的输入

三、运算符

1、算数运算符

2、赋值运算符

3、比较运算符

4、逻辑运算符

四、程序运行结构

1、选择结构:if语句

2、循环结构:while语句、for语句

五、数组

1、一维数组

2、二维数组

六、函数

1、函数的定义

2、函数的调用

3、函数的常见样式

4、函数的声明

七、指针

1、指针的定义和使用

2、指针所占的内存空间

3、空指针和野指针

4、const修饰指针

5、指针和数组、指针和函数

八、结构体

1、结构体的定义和使用

2、结构体数组

3、结构体指针

4、结构体嵌套结构体

5、结构体做函数参数

6、结构体中的const使用场景

7、结构体案例


一、初识C++

1、固定格式

#include <iostream>
using namespace std;
int main()
{  
    // 这里写代码...   
    system ("pause"); 
    return 0;
}

2、第一个程序:hello world

#include <iostream>
using namespace std;

int main()
{
    cout << "hello world" << endl;
    return 0;
}

3、注释

单行注释://     

多行注释:/* */

4、变量与常量

变量:数据类型 变量名=变量值;

int a = 5;

常量:宏常量、const修饰变量

宏常量:#define 常量名 常量值

#include <iostream>
using namespace std;

int main()
{
    #define day 7
    cout << "一周总共有" << day << "天" << endl;
    return 0;
}

const修饰变量:const 数据类型 常量名=常量值

#include <iostream>
using namespace std;

int main()
{
    const int month = 12;
    cout << "一年有" << month << "个月" << endl;
    return 0;
}

5、关键字/标识符

在定义变量或者常量的时候不要用下面这些关键字。

标识符命名规则:

1、不能是关键字;2、只能由字母、数字、下划线组成;

3、第一个字符必须为字母或下划线;4、字母严格区分大小写。

二、数据类型

1、整型

int 变量名 = 变量值;

数据类型存在的意义:给变量分配合适的内存空间。

sizeof关键字:sizeof(数据类型/变量)

利用sizeof关键字可以统计数据类型所占内存大小。

2、实型(浮点型)

单精度:float

双精度:double

float 变量名 = 变量值;

两者唯一的区别在于表示的有效数字范围不同。

float:占用4字节,7位有效数字。

double:占用8字节,15-16位有效数字。

还有一种小数表示法:科学计数法(少用),float a = 3e2,3e2表示:3*10^2

float a = 3.14f;一般我们会在数字后面加上一个f,否则编译器会默认是双精度类型的。

float默认情况下会在小数点后显示5位。

3、字符型和字符串类型

字符型:char 变量名 = 一个字符;

注:只能用单引号,不能用双引号,而且只能有一个字符,不能是字符串。

C和C++中都只占用1个字节。

字符型变量并不是把字符本身放到内存中存储,而是将对应的ASCII编码放入到存储单元。

查看字符的ASCII码:cout << (int)a << endl;

 (int)a:把字符型强制转化成整型,a是97,A是65。

字符串类型:

C语言:char 变量名[] = 字符串值;

C++:string 变量名 = 字符串值;

这两种风格在C++中都可以用,记得要用双引号。

4、转义字符

现阶段常用的有:\n、\\、\t

\t一共占8个位置,如果是aaaa\t,那么输出结果为:aaaa+4个空格,如果是aaa\t,输出结果为:aaa+5个空格。

5、布尔类型

bool 变量名 = true/false;

bool型只有两种:true、false,本质上1代表真值,0代表假值,布尔类型只占1个字节大小。

6、数据的输入

cin >> 变量1 >> 变量2 >> 变量3

输入之前记得先声明变量类型。

三、运算符

1、算数运算符

两个整数相除,结果依然是整数,去抹去小数部分。

前置递增++a表示:先让变量+1,然后再进行表达式的运算;

后置递增a++表示:先进行表达式的运算,后让变量+1。

#include <iostream>
using namespace std;

int main()
{
    int a = 10;
    int b = ++a *10;
    int c = 10;
    int d = c++ *10;

    cout << "a=" << a << endl;
    cout << "b=" << b << endl;
    cout << "c=" << c << endl;
    cout << "d=" << d << endl;
    // 输出的结果:a=11,b=110,c=11,d=100

    return 0;
}

2、赋值运算符

=、+=、-=、*=、/=、%=

3、比较运算符

==相等于,!=不等于

>、<、>=、<=

4、逻辑运算符

四、程序运行结构

程序运行结构:顺序结构、选择结构、循环结构

1、选择结构:if语句

单行:if(条件){条件满足执行的语句}

多行:if(条件){条件满足执行的语句}

           else{条件未满足执行的语句}

多条件:if(条件1){条件1满足执行的代码}

              else if(条件2){条件2满足执行的代码}

               ......

              else{以上条件都不满足执行的代码}

#include <iostream>
using namespace std;

int main()
{
    // 用户输入分数,如果在500-600区间内,恭喜考上本科,如果大于600,恭喜考上重点,否则,复读。
    int score = 0;
    cout << "请输入一个分数:" << endl;
    cin >> score;

    if(score>600)
    {
        cout << "考上重点大学!" << endl;
    }

    else if(500<=score && score<=600)
    {
        cout << "考上本科!" << endl;
    }

    else
    {
        cout << "去复读!" << endl;
    }

    return 0;
}

嵌套if语句:if语句中再嵌套if语句

接上面的例子,在大于600分的重点档里,600-630:211,630-680:985,680+:清北。

#include <iostream>
using namespace std;

int main()
{
    int score = 0;
    cout << "请输入一个分数:" << endl;
    cin >> score;

    if(score>600)
    {
        if (score > 600 && score <= 630)
        {
            cout << "考上211大学!" << endl;
        }

        else if(score > 630 && score <= 680)
        {
            cout << "考上985大学!" << endl;
        }

        else
        {
            cout << "考上清北!" << endl;
        }
    }

    else if(500<=score && score<=600)
    {
        cout << "考上本科!" << endl;
    }

    else
    {
        cout << "去复读!" << endl;
    }

    return 0;
}

小练习:三只小猪称体重:分别输入三只小猪的体重,判断哪只最重。

#include <iostream>
using namespace std;

int main()
{
    int a=0,b=0,c=0;
    cin >> a >> b >> c;

    if(a>b)
    {
        if(a>c)
        {
            cout << a << endl;
        }

        else
        {
            cout << c << endl;
        }
    }

    else
    {
        if(b>c)
        {
            cout << b << endl;
        }

        else
        {
            cout << c << endl;
        }
    }

    return 0;
}

三目运算符和switch语句

三目运算符:条件?条件满足执行的语句:条件不满足执行的语句;

switch语句:

switch(需要判断的变量)

{

  case 常量1 :当变量=常量1时需要执行的语句;break;

  case 常量2 :当变量=常量2时需要执行的语句;break;

  ......

  default:其他情况下执行的语句;break;

}

注意在判断时只能是一个整型或者字符型,不能是一个区间。

优点是结构清晰,执行效率高于if。

练习:给电影打分。

#include <iostream>
using namespace std;

int main()
{  
    int score = 0;  
    cin >> score;
    switch(score)
    {
        case 9:
        cout << "经典佳作!" << endl;
        break;

        case 8:
        cout << "不错的电影!" << endl;
        break;
        
        // ...

        default:
        cout << "都一般!" << endl;
        break;
    }

    return 0;
}

2、循环结构:while语句、for语句

while语句:while(条件){条件满足时执行的语句}

练习:系统随机生成1-100之间的数字,玩家进行猜测,如果猜错,提示玩家数字过大或者过小,如果猜对,恭喜玩家获得胜利,并退出游戏。

生成随机数:rand()%要生成的随机数的区间最大值,如rand()%100,表示生成0-99的随机数。

#include <iostream>
using namespace std;
#include <ctime>

int main()
{  

    // 添加随机数种子,利用当前系统时间生成随机数,防止每次随机数都一样。
    srand((unsigned int)time(NULL));
    int num = rand()%100+1;
    int guess = 0;

    while(1)
    {  
        cin >> guess;
        if(guess>num)
        {
            cout << "猜大了" << endl;
        }

        else if(guess<num)
        {
            cout << "猜小了" << endl;
        }

        else
        {
            cout << "猜对了" << endl;
            break;
        }
    }

    return 0;
}

do...while语句:do(循环语句)while(循环条件)

与while不同的是,它会先执行一次循环语句,再判断循环条件。

练习:水仙花数是指一个3位数,它的每个位上的数字的3次幂之和等于它本身,例如:1^3+5^3+3^3=153,请利用do...while语句,求出所有3位数中的水仙花数。

#include <iostream>
using namespace std;

int main()
{  
    // 1、先获取所有的三位数100-999,;2、在所有的三位数中找到水仙花数。
    int num = 100;

    do
    {  
        int a,b,c;

        // a:个位,b:十位,c:百位。
        // 如果想拿到一个数字的个位数,只需要对它模以10即可。
        a = num % 10;
        b = num / 10 % 10;
        c = num / 100;    

        if(a*a*a + b*b*b + c*c*c == num)
        {
            cout << num << endl;
        }

        num++;
    } while (num<1000);

    return 0;
}

for语句:for(起始表达式;条件表达式;末尾循环体){满足条件执行的循环语句}

eg:for(inti=1;i<10;i++){cout << i << endl;}

练习:敲桌子游戏:从1开始到数字100,如果数字个位或者十位含有7,或者该数字是7的倍数,敲桌子,其余数字输出。

#include <iostream>
using namespace std;

int main()
{  
    for(int i=1;i<=100;i++)
    {
        if(i%7==0 || i%10==7 || i/10==7)

        {
            cout << "敲桌子" << endl;
        }

        else
        {
            cout << i << endl;
        }
    }

    return 0;
}

嵌套循环:在循环体中再嵌套一层循环。

练习:利用嵌套循环打印下面的乘法口诀表。

#include <iostream>
using namespace std;

int main()
{  
    // 1、列数*行数=结果;2、列数<=当前行数
    for(int i=1;i<=9;i++)
    {
        for(int j=1;j<=i;j++)
        {
            cout << i << "x"  << j << "=" << j*i << " ";
        }
        cout << endl;
    }

    return 0;
}

跳转语句:break、continue、goto

break:用于跳出选择结构或者循环结构。

continue:跳过本次循环中余下未执行的语句,继续执行下一次循环。

goto:可以无条件跳转语句。goto 标记,如果标记的名称存在,则会直接跳转到标记的语句执行。

#include <iostream>
using namespace std;

int main()
{  
    cout << "11111" << endl;
    cout << "22222" << endl;

    goto FLAG;

    cout << "33333" << endl;
    cout << "44444" << endl;

    FLAG:

    cout << "55555" << endl;
    return 0;

}

// 输出结果为:11111 22222 55555

五、数组

所谓数组,就是一个集合,里面存放了相同类型的数据元素。

特点:1、数组中的每个数据元素都是相同的数据类型;2、数组是由连续的内存位置组成的。

从0开始进行索引。

1、一维数组

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

1、数据类型 数组名[数组长度];

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

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

如果规定了数组长度为5,但是只写入3个数,剩下的数会自动用0填充。

定义的时候必须初始化它的长度。

#include <iostream>
using namespace std;

int main()
{  

    // 1、数据类型 数组名[数组长度];
    int a[3];

    // 给数组中的元素进行赋值:
    a[0] = 10;
    a[1] = 20;
    a[2] = 30;

    // 2、数据类型 数组名[数组长度] = {值1,值2,...};
    int b[3] = {10,20,30};

    // 3、数据类型 数组名[] = {值1,值2,...};
    int c[] = {10,20,30};

    // 访问数组元素:利用循环输出数组元素。
    for(int i=0;i<3;i++)
    {  
        cout << a[i] << endl;
    }

    for(int j=0;j<3;j++)
    {    
        cout << b[j] << endl;
    }

    for(int s=0;s<3;s++)
    {
        cout << c[s] << endl;
    }

    return 0;
}

直接cout<< a << endl;出来的是它的十六进制地址:0x61fe14

一维数组名的用途:

1、可以统计整个数组在内存中的长度;

2、可以获取数组在内存中的首地址。

注:数组名是一个常量,不可以进行赋值操作。

#include <iostream>
using namespace std;

int main()
{  

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

    // 统计整个数组所占用的内存长度,这个输出为20
    cout << sizeof(a) << endl;

    // 统计单个元素所占的内存空间,这个输出为4,可以通过sizeif(a)/ sizeof(a[0])来获取数组长度。
    cout << sizeof(a[0]) << endl;

    // 获得整个数组首地址,为了方便查看,可以利用long long把它转成十进制,这个输出为:6422016
    cout << (long long)a << endl;

    // 获得某个元素的首地址,因为第一个元素的首地址和整个数组的首地址是一样的,这里演示第二个元素,输出为:6422020
    cout << (long long)&a[1] << endl;

    return 0;
}

练习:数组元素逆置。

#include <iostream>
using namespace std;

int main()
{  
    int set[5] = {1,2,3,4,5};

    cout << "原数组元素为:" << endl;
    for(int i=0;i<5;i++)
    {
        cout << set[i] << endl;
    }

    // 获取起始元素下标位置和末尾元素的下表位置
    int start = 0;
    int end = (sizeof(set)/sizeof(set[0]))-1;

    while (start<end)
    {
        // 首尾元素互换
        int temp = set[start];
        set[start] = set[end];
        set[end] = temp;

        // 下标更新
        start++;
        end--;
    }

    //打印输出逆置后的数组
    cout << "数组元素逆置后为:" << endl;
    for(int j=0;j<5;j++)
    {
        cout << set[j] << endl;
    }

    return 0;
}

冒泡排序:最常用的排序算法,对数组内元素进行排序。

升序排序、降序排序。

练习:对42805719进行升序排列

1、比较相邻的元素,如果第一个比第二个大,就交换他们两个。

      第一轮对比完成后结果为:240571389

2、找到第一个最大值:9

     这个9就像一个气泡一样冒出来,所以叫它冒泡排序。

3、重复上面的步骤,每次比较次数-1,直到不需要比较。

     第一轮对比8次(元素数-1),第二轮对比7次...

#include <iostream>
using namespace std;

int main()
{  
    int set[9] = {4,2,8,0,5,7,1,3,9};
    cout << "未排序之前的数组为:" << endl;
    for(int i=0;i<9;i++)
    {
        cout << set[i] << endl;
    }

    // 开始冒泡排序:总共排序的轮数=元素个数-1
    for(int i=0;i<9-1;i++)
    {
        // 内层循环对比=元素个数-当前轮数-1
        for(int j=0;j<9-i-1;j++)
        {
            // 如果第一个数字比第二个数字大,交换两个数字
            if(set[j] > set[j+1])
            {  
                // 实现两个元素的交换。
                int temp = set[j];
                set[j] = set[j+1];
                set[j+1] = temp;
            }
        }
    }

    cout << "排序后结果为:" << endl;
    for(int s=0;s<9;s++)
    {
        cout << set[s] << endl;
    }

    return 0;
}

2、二维数组

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

1、数据类型 数组名[行数][列数];

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

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

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

推荐第二种,更为直观。

按照以下坐标进行访问:

利用for循环打印二维数组中的每个元素:

#include <iostream>
using namespace std;

int main()
{  
    int set[2][3] = {{1,2,3},{4,5,6}};

    for(int i=0;i<2;i++)
    {
        for(int j=0;j<3;j++)
        {
            cout << set[i][j] << endl;
        }
    }

    return 0;
}

二维数组名:

1、查看二维数组所占用的内存空间;

2、获取二维数组首地址。

#include <iostream>
using namespace std;

int main()
{  
    int set[2][3] = {{1,2,3},{4,5,6}};

    // 1、查看二维数组占用的内存空间大小
    cout << "二维数组占用的内存空间为:" << sizeof(set) << endl; 
    cout << "二维数组第一行占用的内存空间为:" << sizeof(set[0]) << endl;

    // 可以利用sizeof求行数:整个/每行;求列数:每行/每个。
    cout << "二维数组的行数为:" << sizeof(set)/sizeof(set[0]) << endl;
    cout << "二维数组的列数为:" << sizeof(set[0])/sizeof(set[0][0]) << endl;

  
    // 2、查看二维数组的首地址
    cout << "二维数组的首地址为:" << set <<endl;
    // 转成十进制:
    cout << "二维数组的首地址为:" << (long long)set <<endl;
    cout << "二位数组第一行首地址为:" << (long long)&set[0] <<endl;
    cout << "二位数组第一个元素首地址为:" << (long long)&set[0][0] << endl;
    // 二维数组的首地址=二维数组第一行的首地址=位数组第一个元素的首地址

    return 0;
}

练习:考试成绩统计:

#include <iostream>
using namespace std;

int main()
{  
    int grade[3][3] = {{100,100,100},{90,50,100},{60,70,80}};
    for(int i=0;i<3;i++)
    {  
        int sum = 0;
        for(int j=0;j<3;j++)
        {  
            sum += grade[i][j];
            // cout << grade[i][j];
        }
        cout << sum << endl;
    }

    return 0;
}

六、函数

1、函数的定义

函数的定义要有以下五个步骤:

返回值类型、函数名、形参列表、函数体语句、return表达式

返回值类型 函数名 (形参列表)

{

   函数体语句;

   return表达式;

}

如:计算两个数相加的函数。

int add(int a,int b)

{

    int sum = a + b;

    return sum;

}

2、函数的调用

函数名(实参)

练习:调用上面的加法函数。

int main()

{  

    int num1 = 10;

    int num2 = 20;

    int s = add(num1,num2);

    cout << s << endl;

    return 0;

}

在函数定义的时候,a和b并没有真实的数据,只是一个形式上的参数,简称形参;后面调用的时候,实参的值会传递给形参。

函数调用时实参将数值传递给形参,这就叫值传递。

3、函数的常见样式

常见四种:无参无返、有参无返、无参有返、有参有返。

无返回值都用void声明返回值类型。

#include <iostream>
using namespace std;

// 1、无参无返:void
void test01()
{
    cout << "test01函数" << endl;
}

// 2、有参无返:void
void test02(int a)
{
    cout << "test02函数,传入的参数:" << a << endl;
}

// 3、无参有返
int test03()
{
    cout << "test03函数" << endl;
    return 3;
}

// 4、有参有返
int test04(int b)
{
    cout << "test04函数,传入的参数:" << b << endl;
    return b;
}

int main()
{  
    // 调用无参无返函数
    test01();

    // 调用有参无返函数
    test02(2);

    // 调用无参有返函数,如果有返回值了就需要有变量来接收。
    int s = test03();
    cout << "test03返回值为:" << s << endl;

    // 调用有参有返函数
    int t = test04(4);
    cout << "test04返回值为:" << t << endl;

    return 0;
}

4、函数的声明

告诉编译器函数名称及如何调用函数,函数的实际主体可以单独定义。

为什么要写函数的声明?——之前只能在main函数体前写函数,这样程序才会执行,但是如果想把函数写在main函数体后面,需要先告诉编译器函数的存在,这就需要利用函数的声明。

声明可以写多次,但是定义函数只有一次。

练习:比较函数,两个整形数字进行比较,返回较大的值。

#include <iostream>
using namespace std;

// 声明比较函数max的存在
int max(int a,int b);

int main()
{  
    int a = 10;
    int b = 20;
    cout << max(a,b) << endl;
    return 0;
}

// 定义比较函数max
int max(int a,int b)
{
    return a>b?a:b;
}

七、指针

1、指针的定义和使用

指针的作用:可以通过指针间接访问内存。

内存编号是从0开始记录的,一般用十六进制数字表示,可以用指针变量保存地址。

指针的定义:

数据类型 变量名 = 变量值;

数据类型 * 指针变量名;

指针变量名 = &变量名;

或者直接:数据类型 * 指针变量名 = &变量名

指针的使用:

通过解引用的方式来找到指针指向的内存。

* 指针变量名

&取地址,*取值。

#include <iostream>
using namespace std;

int main()
{
    int a = 10;

    // 定义指针
    int* p;
    p = &a;
    // 或者直接:int* p = &a;其中,p就是指针(地址)。

    // 获取指针中存放的地址:
    cout << "指针中存放的地址编号为:" << p << endl;
    // 输出结果为:指针中存放的地址编号为:0x61fe14

    // 获取指针中存放的地址中存放的数据:解引用,在指针前加一个*就是解引用,可以找到指针指向的内存中的数据。
    cout << "指针中地址编号中存放的数据为:" << *p << endl;
    // 输出结果为:指针中地址编号中存放的数据为:10

    return 0;
}

2、指针所占的内存空间

指针也是一种数据类型,一般来说,在32位操作系统下占4个字节,64位下占8个字节。

3、空指针和野指针

空指针:指针变量指向内存为0的空间,用于初始化指针变量。

空指针指向的内存是不可以访问的。

如果一开始不知道指针指向哪里合适,可以用空指针。

#include <iostream>
using namespace std;

int main()
{
    // 1、空指针用于初始化指针变量
    int* p = NULL;

    // 2、空指针不可访问
    *p = 100;
    // 这个运行会报错!

    return 0;
}

野指针:指针变量指向非法的内存空间。

在程序中要尽量避免出现。

#include <iostream>
using namespace std;

int main()
{
    // 野指针:我们随便编了一个内存地址
    int* p = (int*)0x1100;
    // 这个运行会报错!

    return 0;
}

4、const修饰指针

①const修饰指针:常量指针——指针指向可以修改,指针指向的值不能修改。

const int * p = & a;

②const修饰常量:指针常量——指针指向的值能修改,指针指向不能修改。

int * const p = & a;

③const既修饰指针,又修饰常量——指针指向和指针指向的值都不能修改。

小技巧:可以把const译成常量,*译成指针,const *就是常量指针,*const就是指针常量。

5、指针和数组、指针和函数

1、指针和数组:利用指针访问数组中的元素。

#include <iostream>
using namespace std;

int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    int *p = arr;

    // 数组名就是地址,数组名是第一个元素的地址,和数组地址虽然值一样,但指向大小不一样。
    cout << "利用指针来访问第一个元素:" << *p << endl;

    // 让指针往后移4个字节即可(一个整型 元素占4个字节)
    p++;
    cout << "利用指针来访问第二个元素:" << *p << endl;

    return 0;
}

还可以直接p[i],下标从0开始

2、指针和函数:利用指针作函数参数,可以修改实参的值。

#include <iostream>
using namespace std;

// 函数:两个数字进行交换
// 1、值传递
void swap01(int a,int b)
{
    int temp = a;
    a = b;
    b = temp;
    cout << "swap01中的a=" << a << endl;
    cout << "swap01中的b=" << b << endl;
}

// 2、地址传递:如果我们想在函数体中真的修改外部的a、b的数据,就用这个
void swap02(int *p1,int *p2)
{
    int temp = *p1;
    *p1 = *p2;
    *p2 = temp;
    cout << "swap02中的a=" << *p1 << endl;
    cout << "swap02中的b=" << *p2 << endl;
}

int main()
{
    int a = 10;
    int b = 20;

    // 1、值传递
    swap01(a,b);
    cout << "运行swap01后外部的a=" << a << endl;
    cout << "运行swap01后外部的b=" << b << endl;

    // 2、地址传递
    swap02(&a,&b);
    cout << "运行swap02后外部的a=" << a << endl;
    cout << "运行swap02后外部的b=" << b << endl;

    return 0;
}

原因:地址传递是直接改了地址,地址交换了,里面存储的数据自然也就交换了。

3、指针配合函数、数组的案例:

案例:封装一个函数,利用冒泡排序,实现对整型数组的升序排序。

例如一个数组:int arr[10] = {4,3,6,9,1,2,10,8,7,5};

#include <iostream>
using namespace std;

// 冒泡排序函数:参数1:数组地址,参数2:数组长度
void bubble(int *arr,int len)
{
    for(int i=0;i<len-1;i++)
    {
        for(int j=0;j<len-i-1;j++)
        {
            if(arr[j]>arr[j+1])
            {
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
}

// 打印数组的函数:
void printarr(int *arr,int len)
{
    for(int i=0;i<len;i++)
    {
        cout << arr[i] << endl;
    }
}

int main()
{
    int arr[10] = {4,3,6,9,1,2,10,8,7,5};
    int len = sizeof(arr)/sizeof(arr[0]);

     // 一般来说,需要传入数组、数组的长度。
    bubble(arr,len);
    printarr(arr,len);

    return 0;
}

核心:

如何把一个数组传入一个函数中?——用指针接收首地址;

熟练运用冒泡排序;

在函数中使用数组,最好还要传入它的长度。

八、结构体

结构体属于用户自定义的数据类型,允许用户储存不同的数据类型。

整型、字符型等,这些数据类型都属于内置的数据类型。

如果要写一个动物的数据类型?——结构体可以实现。

1、结构体的定义和使用

定义结构体:struct 结构体名 {结构体成员列表};

使用结构体的三种方式:

1、struct 结构体名 变量名

2、struct 结构体名 变量名 = {成员1值,成员2值...}

3、定义结构体时顺便创建变量

#include <iostream>
using namespace std;
#include <string>

// 创建学生数据类型,学生包括:姓名、年龄、分数
// 自定义数据类型就是一些内置数据类型的集合。
struct Student
{  
    // 成员列表:姓名、年龄、分数
    string name;
    int age;
    int score;
}s3; // 方法三:定义结构体的时候顺便创建变量

int main()
{  
    // 方法一:struct 结构体名 变量名
    struct Student s1;
    // 给s1属性赋值,通过.访问结构体变量中的属性
    s1.name = "张三";
    s1.age = 18;
    s1.score = 100;
    cout << "姓名:" << s1.name << endl << "年龄:" << s1.age << endl << "分数:" << s1.score << endl;

    // 方法二:struct 结构体名 变量名 = {值1,值2...};注意按顺序
    struct Student s2 = {"李四",19,80};
    cout << "姓名:" << s2.name << endl << "年龄:" << s2.age << endl << "分数:" << s2.score << endl;


    // 方法三:定义结构体的时候顺便创建变量
    s3.name = "王五";
    s3.age = 20;
    s3.score = 90;
    cout << "姓名:" << s3.name << endl << "年龄:" << s3.age << endl << "分数:" << s3.score << endl;

    return 0;
}

一般来说用第一种、第二种比较多,第三种少一点。

定义的时候struct关键字不可以省略,创建的时候可以省略。

利用.访问它的成员。

2、结构体数组

struct 结构体名 数组名[元素个数] = {{},{},...{}}

#include <iostream>
using namespace std;
#include <string>

// 1、定义学生结构体,包括:姓名、年龄、分数
struct Student
{  
    string name;
    int age;
    int score;
};

int main()
{  
    // 2、创建结构体数组,给结构体数组中的元素赋值
    struct Student stu_arr[3] = {{"张三",18,100},{"李四",19,80},{"王五",20,90}};

    // 3、修改结构体数组中的元素值
    stu_arr[2].name = "尼古拉斯·赵四";

    // 4、遍历结构体数组并输出
    for(int i=0;i<3;i++)
    {
        cout << "姓名:" << stu_arr[i].name << endl;
        cout << "年龄:" << stu_arr[i].age << endl;
        cout << "分数:" << stu_arr[i].score << endl;
    }

    return 0;
}

3、结构体指针

#include <iostream>
using namespace std;
#include <string>

// 1、定义学生结构体,包括:姓名、年龄、分数。
struct Student
{  
    string name;
    int age;
    int score;
};

int main()
{  
    // 2、创建学生结构体变量。
    struct Student s = {"张三",18,100};

    // 3、通过指针指向结构体变量。
    struct Student* p = &s;
   
    // 4、通过指针访问结构体变量数据,需要利用符号->,也可以用(*p).访问。
    cout << "姓名:" << p->name << endl << "年龄:" << p->age << endl << "分数:" << p->score << endl;

    return 0;
}

4、结构体嵌套结构体

结构体中的成员可以是另一个结构体,如老师辅导学员,一个老师的结构体中记录一个学生的结构体。

#include <iostream>
using namespace std;
#include <string>

// 定义学生结构体(要先于老师),包括:姓名、年龄、分数
struct Student
{  
    string name;
    int age;
    int score;
};

// 定义老师结构体:工号、姓名、年龄、学生结构体
struct Teacher
{
    int id;
    string name;
    int age;
    struct Student stu;    
};

int main()
{  
    struct Teacher tea;
    tea.id = 1010;
    tea.name = "孙老师";
    tea.age = 32;

    tea.stu.name = "张三";
    tea.stu.age = 18;
    tea.stu.score = 100;

    cout << "老师工号:" << tea.id << endl << "老师姓名:" << tea.name << endl << "老师年龄" << tea.age << endl << "老师带的学生:" << tea.stu.name << endl << "学生年龄:" << tea.stu.age << endl << "学生分数:" << tea.stu.score << endl;

    return 0;
}

5、结构体做函数参数

将结构体作为参数向函数中传递,传递方式有两种:值传递和地址传递。

#include <iostream>
using namespace std;
#include <string>

// 定义学生结构体,包括:姓名、年龄、分数
struct Student
{  
    string name;
    int age;
    int score;
};

// 1、值传递
void print01(struct Student s1)
{  
    s1.age = 20;
    cout << "值传递中打印的s1信息为:" << endl << "姓名:" << s1.name << endl << "年龄:" << s1.age << endl << "分数:" << s1.score << endl;
}

// 2、地址传递
void print02(struct Student * p)
{
    p->age = 20;
    cout << "地址传递中打印的s2信息为:" << endl << "姓名:" << p->name << endl << "年龄:" << p->age << endl << "分数:" << p->score << endl;
}

int main()
{  
    struct Student s1;
    s1.name = "张三";
    s1.age = 18;
    s1.score = 100;
    print01(s1);
    cout << "值传递后打印的s1信息为:" << endl << "姓名:" << s1.name << endl << "年龄:" << s1.age << endl << "分数:" << s1.score << endl;

    struct Student s2;
    s2.name = "李四";
    s2.age = 19;
    s2.score = 80;
    print02(&s2);
    cout << "地址传递后打印的s2信息为:" << endl << "姓名:" << s2.name << endl << "年龄:" << s2.age << endl << "分数:" << s2.score << endl;

    return 0;
}

 地址传递会真正改变实参,值传递不会。

6、结构体中的const使用场景

用const来防止误操作。

#include <iostream>
using namespace std;
#include <string>

struct Student
{  
    string name;
    int age;
    int score;
};

// 打印函数。
// 如果用值传递,当数据量过大时,值传递要拷贝的数据就很多了,为了节省空间,通常会用地址传递(指针),指针只占4个字节,而且还不会多余复制一份数据副本。
void print(const struct Student *p)
{  
    // 在这种地址传递的函数中,有可能会误更改数据比如:p->age=20;这样就会修改全局变量,为了防止这种情况发生,就会在前面加上const。
    cout << "姓名:" << p->name << endl << "年龄:" << p->age << endl << "分数:" << p->score << endl;
}

int main()
{  
    struct Student s = {"张三",18,100};
    print(&s);

    return 0;
}

7、结构体案例

案例1:每名老师带5个学生,共有3名老师。设计学生和老师结构体,其中在老师结构体中,有姓名和一个存放5名学生的数组。学生结构体有姓名、考试分数。

创建数组存放3名老师,通过函数给每个老师及学生赋值,最终打印出所有数据。

#include <iostream>
using namespace std;
#include <string>
#include <Ctime>

struct Student
{
    string name;
    int score;
};

struct Teacher
{
    string name;
    struct Student stu_arr[5];
};

// 给老师和学生赋值的函数,函数接收数组有两种方法:一种是指针,一种是下面这种
void assignment(struct Teacher tea_arr[],int len)
{
    // 给老师赋值
    string name_tealist = "ABC";
    for(int i=0;i<len;i++)
    {  
        // 做一个拼接字符串的操作:
        tea_arr[i].name = "teacher_";
        tea_arr[i].name += name_tealist[i];

        // 给每名老师带的学生赋值
        for(int j=0;j<5;j++)
        {  
            // 学生姓名
            string name_stulist = "ABCDE";
            tea_arr[i].stu_arr[j].name = "student_";
            tea_arr[i].stu_arr[j].name += name_stulist[j];

            // 学生成绩,随机数,后面的51表示0-50之间的一个数。
            int random = rand()%51 +50;
            tea_arr[i].stu_arr[j].score = random;
        }
    }
}

void print(struct Teacher tea_arr[],int len)
{
    for(int i=0;i<len;i++)
    {
        cout << "老师姓名:" << tea_arr[i].name << endl;
        for(int j=0;j<5;j++)
        {
            cout << "所带学生姓名:" << tea_arr[i].stu_arr[j].name << ",分数:" << tea_arr[i].stu_arr[j].score << endl;
        }
    }
}

int main()
{    
    // 随机数种子
    srand((unsigned int) time(NULL));

    // 1、创建3名老师的数组
    struct Teacher tea_arr[3];

    ///2、通过函数给3名老师赋值,并给老师带的学生赋值
    int len = sizeof(tea_arr)/sizeof(tea_arr[0]);
    assignment(tea_arr,len);

    // 3、打印输出所有的老师及学生信息
    print(tea_arr,len);

    return 0;
}

案例2:设计一个英雄的结构体,包括:姓名、年龄、性别。

创建结构体数组,数组中存放5名英雄(自己定义)。

通过冒泡排序算法,将数组中的英雄按照年龄进行升序排序,并打印结果。

#include <iostream>
using namespace std;
#include <string>

struct Hero
{
    string name;
    int age;
    string gender;
};

void bubble(struct Hero hero[],int len)
{
    for(int i=0;i<len-1;i++)
    {
        for(int j=0;j<len-i-1;j++)
        {
            if(hero[j].age > hero[j+1].age)
            {
                struct Hero temp = hero[j];
                hero[j] = hero[j+1];
                hero[j+1] = temp;
            }
        }
    }
}

void print(struct Hero hero[],int len)
{
    for(int s=0;s<len;s++)
    {
        cout << "姓名:" << hero[s].name << ",年龄:" << hero[s].age << ",性别:" << hero[s].gender << endl;
    }
}

int main()
{    
    struct Hero hero[5] = {{"刘备",23,"男"},{"关羽",22,"男"},{"张飞",20,"男"},{"赵云",21,"男"},{"貂蝉",19,"女"}};
    int len = sizeof(hero)/sizeof(hero[0]);
    bubble(hero,len);
    print(hero,len);

    return 0;
}

  • 30
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值