C++(三)

📒 笔记 · 2023-09-11

C++语法:数组、函数


C++ (一):常量、变量、关键字、标识符、数据类型(整形、浮点型、字符型、字符串型、布尔型)
C++ (二):选择、循环、嵌套、跳转语句
C++ (三):数组、函数
C++ (四):指针、结构体


C++的数组

数组特点

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

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

一维数组

  1. 定义方式

一维数组定义:

  • 数组类型 数组名 [ 数组长度 ]
  • 数组类型 数组名 [ 数组长度 ] = { 值1,值2,.... }
  • 数组类型 数组名 = { 值1,值2,..... }
  • 数组名的命名规范与变量名命名规范一致,不要和变量重名。

数组中下标是从0开始索引。

#include <iostream>
using namespace std;

int main()
{
    //1、数组类型 数组名 [ 数组长度 ]
    int arr[5];
    //数组元素的下标是从0开始索引的
    //给数组中的元素进行赋值
    arr[0] = 10;
    arr[1] = 20;
    arr[2] = 30;
    arr[3] = 40;
    arr[4] = 50;


    //访问数据元素
    cout << arr[0] << endl;            //10
    cout << arr[1] << endl;            //20
    cout << arr[2] << endl;            //30
    cout << arr[3] << endl;            //40
    cout << arr[4] << endl;            //50

    //2、数据类型 数组名 [ 数组长度 ] = { 值1,值2,... }
    //如果在初始化数据的时候,没有完全填写完,会用0来填补剩余数据
    int arr2[5] = { 10,20,30 };

    //方式一:
    cout << arr2[0] << endl;        //10
    cout << arr2[1] << endl;        //20
    cout << arr2[2] << endl;        //30
    cout << arr2[3] << endl;        //0
    cout << arr2[4] << endl;        //0


    // 方式二:利用循环输出数组中的元素
    for (int i = 0; i < 5; i++)
    {
        cout << arr2[i] << endl;
    }

    //3、数据类型 数组名 [ ] = { 值1,值2,.... }
    int arr3[] = { 90,80,70,60,50,40,30,20,10 };  //以后自定义变量,不要 int arr3 = 100,这样避免以后调用arr3到底是调用变量还是数组产生模糊。
    for (int i = 0; i < 9; i++)
    {
        cout << arr3[i] << endl;
    }

    system("pause");

    return 0;

}
  1. 数组名

一维数组名的用途:

  • 可以统计整个数组在内存中的长度。
  • 可以获取数组在内存中的首地址。
#include <iostream>
using namespace std;

int main()
{
    //数组名用途
    //1、可以通过数组名统计整个数组占用内存大小
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    cout << "整个数组占用内存空间为:" << sizeof(arr) << endl;                        //整个数组占用内存空间为:40
    cout << "每个元素占用内存空间为:" << sizeof(arr[0]) << endl;                    //每个元素占用内存空间为:4
    cout << "数组中元素的个数为:"     << sizeof(arr)/sizeof(arr[0]) << endl;        //数组中元素的个数为:10

    //2、可以通过数组名查看数组首地址
    cout << "数组首地址为:" << (int)arr << endl;            //数组首地址为:12582108
    cout << "数组中第一个元素地址为:" << (int)&arr[0] << endl;  //int使得将十六位地址通过int转换为10位地址,&表示取址符号,取一个元素的首地址    //数组中第一个元素地址为:12582108
    cout << "数组中第二个元素地址为:" << (int)&arr[1] << endl;  //第二个元素和第一个元素差四个字节        //数组中第二个元素地址为:12582112

    //数组名是常量,值为数组首地址,不可以进行赋值操作
    //arr = 100;  不可以这样赋值修改

    system("pause");

    return 0;

}
  1. 五只小猪称体重

案例描述:在一个数组中记录了五只小猪的体重,如:int arr[5]={300,350,200,400,250},找出并打印最重的小猪体重。

#include <iostream>
using namespace std;

int main()
{
    //1、创建5只小猪体重的数组
    int arr[5] = { 300,350,200,400,250 };

    //2、从数组中找到最大值
    int max = 0; //先认定一个最大值为0
    for (int i = 0; i < 5; i++)
    {
        //cout << arr[i] << endl;
        if (arr[i] > max)
        {
            max = arr[i];
        }
    }

    //3、打印最大值
    cout << max << endl;

    system("pause");

    return 0;
}
  1. 数组元素逆置

案例描述:请声明一个5个元素的数组,并且将元素逆置。(如原数组元素为:1,3,2,5,4;逆置后输出的结果为:4,5,2,3,1)。

#include <iostream>
using namespace std;

int main()
{
    //实现数组元素逆置

    //1、创建数组
    int arr[5] = { 1,3,2,5,4 };
    cout << "数组逆置前" << endl;
    for (int i = 0; i < 5; i++)
    {
        cout << arr[i] << endl;
    }
    //2、实现逆置
    //2.1 记录起始下标位置
    //2.2 记录结束下标位置
    //2.3 起始下标与结束下标的元素互换
    //2.4 起始位置++ 结束位置--
    //2.5 循环执行2.1操作,直到起始位置 >= 结束位置
    int start = 0; //起始下标
    int end = sizeof(arr) / sizeof(arr[0]) - 1; //结束下标,先计算除法  

    while (start < end)
    {
        int temp = arr[start];
        arr[start] = arr[end];
        arr[end] = temp;

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

    //3、打印逆置后的数组
    cout << "数组逆置后" << endl;
    for (int i = 0; i < 5; i++)
    {
        cout << arr[i] << endl;
    }

    system("pause");

    return 0;
}
  1. 冒泡排序

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

  • 比较相邻的元素,如果第一个比第二个大,就交换他们两个。
  • 对每一对相邻元素做同样的go牛牛公主,执行完毕后,找到第一个最大值。
  • 重复以上的步骤,每次比较次数-1.直到不需要比较。

示例:将数组(4,2,8,0,5,7,1,3,9)进行排序。

#include <iostream>
using namespace std;

int main()
{
    int arr[9] = { 4,2,8,0,5,7,1,3,9 };
    cout << "排序前" << endl;
    for (int i = 0; i < 9; i++)
    {
        cout << arr[i] << " ";
    }
    cout << endl;

    //开始冒泡排序
    for (int i = 0; i < 9 - 1; i++)
    {
        //内层循环对比  次数=元素个数=当前轮数-1
        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;
            }
        }
    }

    //排序后结果
    cout << "排序后" << endl;
    for (int i = 0; i < 9; i++)
    {
        cout << arr[i] << " ";
    }
    cout << endl;

    system("pause");

    return 0;
}

二维数组

  1. 定义方式

二维数组就是在一维数组上,多加一个维度。

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

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

以上4种定义方式,利用第二种更加直观,提高代码的可读性。

定义二维数组的时候,如果初始化了数据,可以省略行数。

#include <iostream>
using namespace std;

int main()
{

    //1、数据类型 数组名 [ 行数 ][ 列数 ];
    int arr[2][3];
    arr[0][0] = 1;
    arr[0][1] = 2;
    arr[0][2] = 3;
    arr[1][0] = 4;
    arr[1][1] = 5;
    arr[1][2] = 6;

    //外层循环打印行数,内层循环打印列数
    for (int i = 0; i < 2; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            cout << arr[i][j] << endl;
        }
    }

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

    for (int i = 0; i<2;i++)
    {
        for (int j = 0; j < 3; j++)
        {
            cout << arr2[i][j] << " "; //打印一个元素后打印一个空格
        }
        cout << endl;  //换行语句
    }

    //3、数据类型 数组名 [ 行数 ][ 列数 ] = { 数据1,数据2,数据3,数据4 };
    int arr3[2][3] = { 1,2,3,4,5,6 };  //可以省去行数,但是列数不能再省略了
    for (int i = 0; i < 2; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            cout << arr2[i][j] << " ";
        }
        cout << endl;
    }

    //4、数据类型 数组名 [  ][ 列数 ] = { 数据1,数据2,数据3,数据4 };
    int arr4[][3] = { 1,2,3,4,5,6 };  //可以省去行数,但是列数不可以省略
    for (int i = 0; i < 2; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            cout << arr2[i][j] << " ";
        }
        cout << endl;
    }

    system("pause");

    return 0;
}
  1. 数组名

查看二维数组所占内存空间。

获取二维数组首地址。

#include <iostream>
using namespace std;

int main()
{
    //二维数组名称用途
    //1、可以查看占用内存空间大小
    int arr[2][3] =
    {
        {1,2,3},
        {4,5,6}
    };

    cout << "二维数组占用内存空间为: "  << sizeof(arr) << endl;                //二维数组占用内存空间为: 24
    cout << "二维数组第一行占用内存为:"  << sizeof(arr[0]) << endl;                //二维数组第一行占用内存为:12
    cout << "二维数组第一个元素占用内存为:" << sizeof(arr[0][0]) << endl;            //二维数组第一个元素占用内存为:4

    cout << "二维数组行数为:" << sizeof(arr)/sizeof(arr[0]) << endl;                //二维数组行数为:2
    cout << "二维数组列数为:" << sizeof(arr[0])/sizeof(arr[0][0]) << endl;            //二维数组列数为:3

    //2、可以查看二维数组的首地址
    cout << "二维数组首地址为:" << (int)arr << endl;                                //二维数组首地址为:3733652
    cout << "二维数组第一行首地址为:" << (int)arr << endl;                                //二维数组第一行首地址为:3733652
    cout << "二维数组第一行首地址为:" << (int)arr[0] << endl;                            //二维数组第一行首地址为:3733652
    cout << "二维数组第二行首地址为:" << (int)arr[1] << endl;                            //二维数组第二行首地址为:3733664

    cout << "二维数组第一个元素首地址为:" << (int)&arr[0][0] << endl;                    //二维数组第一个元素首地址为:3733652
    cout << "二维数组第二个元素首地址为:" << (int)&arr[0][1] << endl;  //每个元素地址相差4个字节    //二维数组第二个元素首地址为:3733656

    system("pause");

    return 0;
}
  1. 考试成绩

案例描述:有三名同学(张三,李四,王五),在一次考试中的成绩分别如下表,请分别输出三名同学的成绩。

姓名语文数学英语
张三100100100
李四9050100
王五607080
#include <iostream>
using namespace std;

int main()
{
    //二维数组案例-考试成绩统计
    //1、创建二维数组
    int scores[3][3] =
    {
        {100,100,100},
        {90,50,100},
        {60,70,80}
    };

    //2、统计每个人的总和分数
    for (int i = 0; i < 3; i++)
    {
        int sum = 0; //统计分数总和不变
        for (int j = 0; j < 3; j++)
        {
            sum += scores[i][j];
            //cout << scores[i][j] << " ";
        }
        cout << "第" << i + 1 << "个人的总分为:" << sum << endl;
    }

    system("pause");

    return 0;
}

函数

函数

  1. 函数概述

作用:将一段经常使用的代码封装起来,减少重复代码。

一个较大的程序,一般分为若干个程序块,每个模块实现特定的功能。

  1. 函数定义

函数的定义主要有5个部分:

  • 返回值类型:一个函数可以返回一个值。如果函数不需要返回值,声明的时候可以写void
  • 函数名:给函数起个名称。
  • 参数列表:使用该函数时,传入的数据。
  • 函数体语句:花括号内的代码,函数内需要执行的语句。
  • return表达式:和返回值类型挂钩,函数执行完后,返回相应的数据。

语法格式如下所示:

返回值类型 函数名 (参数列表)
{
     函数体语句

     return 表达式
}
#include <iostream>
using namespace std;

//函数的定义
//语法:返回值类型 函数名 (参数列表) { 函数体语句 return表达式 }

//加法函数,实现两个整型相加,并且将相加的结果进行返回
int add(int num1, int num2)
{
    int sum = num1 + num2;
    return sum;
}

int main()
{
    cout << add(10, 20) <<endl;
    system("pause");   //按任意键继续
    return 0;
}
  1. 函数调用

功能:使用定义好的函数

语法:函数名(参数)

函数定义里小括号内称为形参,函数调用时传入的参数称为实参

#include <iostream>
using namespace std;

//函数的定义
//语法:
//返回值类型 函数名 (参数列表) { 函数体语句 return表达式 }

//定义加法函数
//函数定义的时候,num1和num2并不是真实数据
//它们只是一个形式上的参数,简称形参
int add(int num1, int num2)
{
    int sum = num1 + num2;
    return sum;
}

int main()
{
    //main函数中调用add函数
    int a = 10;
    int b = 20;

    //函数调用语法:函数名称:(参数)
    //a和b称为 实际参数,简称实参
    //当调用函数的时候,实参的值会传递给形参
    int c = add(a, b);

    cout << "c = " << c << endl;        //c = 30

    system("pause");   //按任意键继续

    return 0;
}
  1. 函数值传递

所谓值传递,就是函数调用时实参将数值传入给形参。

值传递时,如果形参发生改变,并不影响实参。

在下面代码例子中,实参传进去时,新参会产生新的内存空间赋值,对num1、num2的操作并不会改变实参a、b的值。

#include <iostream>
using namespace std;

//值传递
//定义函数,实现两个数字进行交换函数

//如果函数不需要返回值,声明的时候可以写void
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;  //前面写了void,所以不需要返回值。返回值不需要的时候,也可以不写return。
}


int main()
{
    //main函数中调用add函数
    int a = 10;
    int b = 20;

    cout << "a = " << a << endl;
    cout << "b = " << b << endl;

    //当我们把值传递的时候,函数的形参发生发生改变,并不会影响实参
    swap(a, b);
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;

    system("pause");   //按任意键继续

    return 0;
}

输出:

a = 10
b = 20
交换前:
num1= 10
num2= 20
交换后:
num1= 20
num2= 10
a = 10
b = 20
  1. 函数常见样式

常见的函数样式有四种

  • 无参无返
  • 有参无返
  • 无参有返
  • 有参有返
#include <iostream>
using namespace std;

//函数常见样式
//1、无参无返
void test01()
{
    cout << "this is test01" << endl;
}

//2、有参无返
void test02(int a)
{
    cout << "this is test 02 a = " << a << endl;
}

//3、无参有返
int test03()
{
    cout << "this is test 03 " << endl;

    return 1000;
}

//4、有参有返
int test04(int a )
{
    cout << "this is test 04 a = " << a << endl;

    return a;
}

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

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

    //无参有返函数调用
    int num1 = test03();
    cout << "num1 = " << num1 << endl;

    //有参有返函数调用
    int num2 = test04(10000);
    cout << "num2 = " << num2 << endl;

    system("pause");   //按任意键继续

    return 0;

}
  1. 函数声明

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

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

#include <iostream>
using namespace std;

//函数的声明
//比较函数,实现两个整型数字进行比较,返回较大的值。

//提前告诉编译器函数的存在,可以利用函数的声明
//函数的声明
//声明可以写多次,但是定义只能有一次
int maxs(int a, int b);
int maxs(int a, int b);
int maxs(int a, int b);

int main()
{
    int a = 10;
    int b = 20;
    cout << maxs(a, b) << endl;

    system("pause");   //按任意键继续

    return 0;

}

//函数定义在main函数之后,必须要在main函数之前写函数的声明
int maxs(int a, int b)
{
    return a > b ? a : b;
}
  1. 函数分文件编写

作用:让代码结构更加清晰。

函数分文件编写一般有4个步骤:

  • 创建后缀名为.h的头文件。
  • 创建后缀名为.cpp的源文件。
  • 在头文件中写函数的声明。
  • 在源文件中写函数的定义。

7.1 swap.h头文件

//这个是swap.h头文件

#include <iostream>
using namespace std;

//函数的声明
void swap(int a, int b);

7.2 swap.cpp源文件

//这个是swap.pp源文件

#include "swap.h"

//函数的定义
void swap(int a, int b)
{
    int temp = a;
    a = b;
    b = temp;

    cout << "a = " << a << endl;
    cout << "b = " << b << endl;

}

7.3 主文件 .cpp文件

//主文件,调用函数分文件

#include <iostream>
using namespace std;
#include "swap.h"  //包含要调用的函数的头文件,双引号表示我们自己写的头文件

int main()
{
    int a = 10;
    int b = 20;
    cout << maxs(a, b) << endl;

    system("pause");   //按任意键继续

    return 0;

}
  1. 函数默认参数

在C++中,函数的形参列表中的形参是可以有默认值的。

语法:返回值类型 函数名 (参数 = 默认值) {}

#include <iostream>
using namespace std;

//函数默认参数

//如果我们自己传入数据,就用自己的数据,如果没有,那么永默认值
//语法:返回值类型 函数名(形参 = 默认值)
int func01(int a,int b,int c)
{
    return a + b + c;
}
//注意事项
//1、如果某个位置以及有了默认参数,那么从这个位置往后,从左到右都必须有默认值
int func02(int a, int b = 40, int c = 50)
{
    return a + b + c;
}

//2、如果函数声明有默认参数,函数实现就不能有默认参数
//例如,函数定义为 int func03(int a = 20, int b = 20){return a + b;},而函数声明为int func03(int a = 10, int b = 10);那么编译器不知道按照哪个默认参数来运行
//声明和实现只能有一个有默认参数
int func03(int a = 10, int b = 10);

//这个是函数的实现
int func03(int a , int b) 
{  
    return a + b;
}

int main()
{
    cout << func01(10, 20, 30) << endl;
    cout << func02(10) << endl;
    cout << func02(10, 20) << endl;
    cout << func02(10, 20,30) << endl;

    cout << func03() << endl;

    system("pause");

    return 0;

}
  1. 函数占位参数

C++中函数的形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置。

语法:返回值类型 函数名 (数据类型) {}

#include <iostream>
using namespace std;

//占位参数
//返回值类型 函数名(数据类型){}

//目前,占位参数还用不到,后面会用到
void func01(int a, int b)
{
    cout << "this is func01" <<"\t"<< a <<"\t"<< b << endl;
}

//占位参数,还可以有默认参数
void func02(int a ,int b = 10)
{
    cout << "this is func02" << "\t"<<a<<endl;
}

int main()
{
    func01(10, 20);
    func02(20);  //有默认参数,可以只输入一个参数

    system("pause");

    return 0;
}

输出:

this is func01  10      20
this is func02  20      10
请按任意键继续. . .

函数重载

  1. 函数重载条件

作用:函数名可以相同,提高复用性。

函数重载满足条件:

  • 同一个作用域下。
  • 函数名称相同。
  • 函数参数类型不同 或者 个数不同 或者 顺序不同。

函数的返回值不可以作为函数重载的条件。

#include <iostream>
using namespace std;

//函数重载
//可以让函数名相同,提高复用性

//函数重载的满足条件
//1、同一作用域下
//2、函数名称相同
//3、函数参数类型不同,或者个数不同,或者顺序不同
void func()
{
    cout << "func ()的调用" << endl;
}

void func(int a)
{
    cout << "func (int a) 的调用" << endl;
}

void func(double a)
{
    cout << "func (double a) 的调用" << endl;
}

void func(double a, int b)
{
    cout << "func (double a, int b) 的调用" << endl;
}

void func(int a, double b)
{
    cout << "func (int a, double b) 的调用" << endl;
}

/*
注意事项
函数的返回值不可以作为函数重载的条件
int func(int a, double b)
//调用func(3.14,3)时,编译器不知道是调用int func(int a, double b){}还是调用void func(int a, double b){}
{
    cout << "func (int a, double b) 的调用" << endl;
}
*/

int main()
{

    func();  // 根据传入参数的个数不同,调用不同的函数
    func(10);

    func(3.14); // 根据传入参数的类型不同,调用不同的函数

    func(3,3.14); // 根据传入参数的顺序不同,调用不同的函数
    func(3.14,3); // 根据传入参数的顺序不同,调用不同的函数
    system("pause");

    return 0;

}

输出:

func ()的调用
func (int a) 的调用
func (double a) 的调用
func (int a, double b) 的调用
func (double a, int b) 的调用
请按任意键继续. . .
  1. 函数重载注意事项

引用作为重载条件。

函数重载碰到函数默认参数。

#include <iostream>
using namespace std;

//函数重载的注意事项
//1、引用作为重载的条件
void fun(int& a)   // int &a = 10; 不合法,所以fun(10);无法调用。int& a 表示一个整数的引用。这意味着变量 a 不是一个独立的整数,而是一个对某个整数变量的引用。
{
    cout << "func(int &a)调用" << endl;
}
                        // const int &a = 10; 合法
void fun(const int& a)  //语法是可以的,const引用和普通引用属于类型不同,fun(10)可以调用
{
    cout << "func(const int &a)调用" << endl;
}

//2、函数重载碰到默认参数
void func2(int a,int b = 20)
{
    cout << "func2(int a,int b = 20) 的调用" << endl;
}

void func2(int a)
{
    cout << "func2(int a) 的调用" << endl;
}

int main()
{
    int a = 10;
    //变量可读可写,所以调用变量时,是调用可读可写的引用函数,const int a = 10的fun(a);调用func(const int &a)调用
    fun(a);
    fun(10);
               //既可以调用void func2(int a,int b = 20),也可以调用void func2(int a)
    //func2(10); //当函数重载碰到默认参数,出现二义性,报错,尽量避免这种情况

    func2(10,20);  //不会出现二义性

    system("pause");

    return 0;
}

运行结果:

func(int &a)调用
func(const int &a)调用
func2(int a,int b = 20) 的调用
请按任意键继续. . .
Theme Jasmine by Kent Liao