一、基础
基础语法
1.单行注释和多行注释
2.变量
3.常量
- 宏常量
- const修饰的变量:常量
//a. #define 宏常量:一般定义在文件的上方。
#define Day 7
//b. const修饰的变量:一般在变量定义前加关键字,修饰该变量为常量,不可修改。
const int day =7
4.标识符命名规则
1、不可以有关键字
2、只能是字母、数字、下划线,第一个子父不能是数字
3、字母区分大小写。
5.数据类型
存在的意义:给变量分配合适的内存空间
- 整型
数据类型 | 占用空间 |
---|---|
short | 2字节 |
int | 4字节 |
long | windows:4字节 Linux:4字节(32位),8字节(64位) |
long long | 8字节 |
sizeof :统计数据类型所占内存大小,sizeof(数据类型/变量)。eg: sizeof(int);; 输出就是4
- 实型(浮点型)
数据类型 | 占用空间 | 有效数字范围 |
---|---|---|
float | 4字节 | 7位有效数字 |
double | 8字节 | 15~16位有效数字 |
字符型
用于显示单个字符
char ch =‘a’;
注意:单引号;只能有一个字符
只占1个字节
字符型变量并不是把子父本身放到内存中存储,而是将对应的ASCII编码放入到存储单元转义字符
转义字符 | 含义 | ASCII码值(十进制) |
---|---|---|
\a | 警报 | 007 |
\b | 退格,将当前位置移到前一页 | 008 |
\f | 换页 | 012 |
\n | 换行 | 010 |
\r | 回车 | |
\t | 水平制表 | |
\v | 垂直制表 | |
*\ * | 反斜线| | |
\ ’ | 一个单引号 | 039 |
\ " | 双引号 | |
\ ? | 问号 | |
\0 | 数字0 | |
\ddd | 8进制转义字符,d范围0~7 | |
\xhh | 16进制转义字符 |
- 字符串类型
1、C风格字符串,延用
char 变量名[]="字符串值"
2、C++风格
string str ="hello world"
- 布尔类型
作用:代表真或假
true……1
false……0
占用1个字节
数据的输出 cout
cout<<a
- 数据的输入cin
cin>>a
6、运算符
- 算数运算符
**+ 、 -、 *、 /、 %、 ++、 – **
+:加法、正号
-:减法 、负号 - 赋值运算符
=、 /= 、+=、-=、*=、%= - 比较运算符
** >、 <、 == 、!=、<=、>= ** - 逻辑运算符
!、 &&、 ||
7.选择结构
- if switch
8.循环结构
- while、dowhile、for
do{ }while( );
for(int i=0;i<10;i++){}
9.跳转语句
- break、continue、goto
goto:可以无条件跳转语句,一般不推荐使用,因为你不知道你程序跳过去跳过来,不知道程序跳到哪里了,影响逻辑结构。不方便阅读。
语法:goto FLAG;去这个标记
如果标记的名称存在,执行到goto语句时,会跳转到标记的位置。
int main(){
cout << "a"<<endl;
goto FLAG;//执行标记,去找到标记的位置,开始执行后面的语句
cout<<"b"<<endl;
cout<<"c"<<endl;
cout<<"d"<<endl;
FLAG: //是冒号
cout<<"e"<<endl;
}
//执行结果:ae
9.一维数组
- 数据类型 数组名[长度];
int score[3];
score[0]=0;
score[1]=10;
score[2]=20;
- 数据类型 数组名[长度]={值1,值2,…};
//如果在初始化的时候,没有全部的填写,会用0来填补剩余的数字
int arr[3]={0,10};
cout<<arr[3]<<endl;//0
- 数据类型 数组名[ ]={值1,值2,…};
int arr[ ]={0,10,20,30,40};
10.二维数组
矩阵方式,一板鸡蛋
- 数据类型 数组名 [ 行数 ][列数];
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++){l
cout<<arr[i][j]<<endl
}
}
- 数据类型 数组名[ 行数][列数]={{数据1,数据2},{数据3,数据4},{数据5,数据6}};
int arr[2][3]=
{
{1,2,3},
{4,5,6}
};
- 数据类型 数组名[ 行数][列数]={数据1,数据2,数据3,数据4,数据5,数据6};
int arr[2][3]={1,2,3,4,5,6}
- 数据类型 数组名[ ][列数 ]={数据1,数据2,数据3,数据4,数据5,数据6};
int arr[][3]={1,2,3,4,5,6}
11.函数
- 语法
//语法
/*返回值 函数名(参数列表){
函数体语句
return 表达式
}
*/
//a、b形参
int sum(int a,int b){
return a+b;
}
int main(){
//1、2:实参
sum(1,2);
}
- 值传递
概念:函数调用时实参将数值传递给形参
当我们做值传递的时候,如果形参发生改变,并不会影响实参
因为形参和实参不是同一个内存空间。
void swap(int num1,int num2){
cout<<"交换前:"<<end1;
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;
}
int main(){
cout<<"交换前:"<<endl;
cout<<"num1="<<num1<<endl;
cout<<"num2="<<num2<<endl;
int a =10;
int b=20;
swap(10,20);
cout<<"a="<<a<<endl; //10
cout<<"b="<<b<<endl;//20 说明调用了函数 形参发生了改变,实参并没有发生变化。
//交换前:10,20 交换后:20,10
}
- 函数声明
提前告诉编译器函数的存在,可以利用函数的声明。因为代码时一行一行执行的,如果方法放在main()方法后面,编译器就会找不到这个函数,所以需要提前声明。
//如果不声明,该代码会报错。找不到这个函数
int max(int a,int b);
int main(){
cout<<max(1,2) <<end1
}
int max(int a ,int b){
return a>b?a:b;
}
函数的分文件编写
作用:让代码结构更加清晰
函数分文件一般有四个步骤:
- 创建后缀名为.h的头文件
- 创建后缀名为.cpp的源文件
- 在头文件中写函数的声明
- 在源文件中写函数的定义
//:swap.h
#include <iostream>
using namespace std
void swap(int a,int b);
///:~
//:swap.cpp
#include "swap.h" //跟头文件关联起来
void swap(int a,int b){
cout<<"交换前:"<<end1;
cout<<"num1="<<num1<<endl;
cout<<"num2="<<num2<<endl;
int temp =num1;
num1=num2;
num2=temp;
cout<<"交换后:"<<end1;
cout<<"num1="<<num1<<endl;
cout<<"num2="<<num2<<endl;
}
///:~
//:test.cpp
#include <iostream>
using namespace std
#include "swap.h"
int main(){
cout<<swap(10,20)<<endl;
}
///:~
指针
指针就是一个地址
基本概念:可以通过指针间接访问内存。
内存编号是从0开始记录的,一般用16进制数字表示
可以利用指针变量保存地址
1.指针变量的定义和使用
- 指针变量语法
指针就是记录这个地址的编号
int main(){
int a =10;
//1、定义一个指针 p:point
int * p;
//让指针记录变量a的地址
p=&a;
cout<<"a的地址:"<< &a<<end1; //00CFFA5C
cout<<"p:"<< p<<end1; //00CFFA5C
//2、使用指针
//可以通过解引用的方式来找到指针指向的内存
//在指针前加*代表解引用,找到指针指向内存中的地址
*p=1000;
cout<<"a="<< a<<end1; //1000
cout<<"*p:"<< *p<<end1; //1000
}
2.简单点
- int a=10;
- int * p=&a;
- *p=1000
- a的值就是1000
- 通过修改地址,改变a的值;
解释:定义a这个变量,将a的地址保存到指针变量中,找到指针p指向的地址重新修改值。
3.指针所占内存空间
问:指针也是种数据类型,那么这种数据类型占用多少内存空间呢?
32位系统占4个字节。64位系统占8个字节
int main(){
int a =10;
int * p =&a;
cout<<"sizeof(p)"<< sizeof(p)<<end1;
cout<<"sizeof(int *)"<< sizeof(int *)<<end1;
}
3.空指针和野指针
空指针:指针变量指向内存中编号位0的空间
用途:初始化指针变量
注意:空指针指向的内存是不可以访问的
野指针:指针变量指向非法的内存空间
//空指针
int * p =null;//访问的p时候就会报错
//野指针
int * p =(int *) 0x110011;//访问的p时候就会报错,非法访问。原因是这个地址并没有被分配空间
总结: 空指针和野指针都不是我们申请的空间,因此不能访问
4.const修饰指针的三种情况:
- 修饰指针 :常量指针 值不可以更改
- 修饰常量 :指针常量 指针指向不可以改
- 既修饰指针,又修饰常量 都不可以改
int main() {
int a = 10;
int b = 10;
//常量指针,指针可以改,指针指向的值不可以更改
const int * p1 = &a;
p1 = &b;
//*p1=100 报错;值不可以再次改变
//指针常量,指针指向不可以改,指针指向可以更改
int * const p2 = &a;
*p2=200;
//p2=&b; 报错;指针指向不可以改变
//都不可以改
const int * const p=&a;
}
5.指针和数组
利用指针访问数组中的元素
int main() {
int arr[10] = { 1,2,3,4,5,6,7,8,9 };
int * p = arr; //arr就是數組的首地址
cout <<"利用指指针访问第一个元素:"<< *p << endl; //1
p++; //让指针向后偏移4个字节,int占用4个字节
cout << "利用指指针访问第一个元素:" << *p << endl; //2
}
6.指针和函数
- 利用指针作为函数参数,可以修改实参的值
void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
}
//地址传递
void swap2(int * p1, int * p2) {
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
int main() {
int num1 = 10;
int num2 = 20;
swap(num1, num2);
cout << "num1=" << num1 << endl; //10
cout << "num2=" << num2 << endl; //20
swap2(&num1, &num2);
cout << "num1=" << num1 << endl; //20
cout << "num2=" << num2 << endl; //10
system("pause");
return 0;
}
结构体
结构体属于用户自定义的数据类型,允许用户存储不同的数据类型
1.结构体定义和使用
struct 结构体名 { 结构体成员列表 };
通过结构体创建变量的方式有3种:
- struct 结构体名 变量名 //可以省略struct
- struct 结构体名 变量名={成员1值,成员2值……}
- 定义结构体时顺便创建变量 //不建议使用
struct Student
{
string name;
int age;
} student;//顺便创建结构体变量
int main(){
struct Student stu; // 可以写成 Student stu
stu.name="zhangsan";
stu.age=13;
struct Student stu2={"zhangsan",33};
//不建议使用
student.name="lisi";
student.age=22;
}
总结:
- 创建结构体变量时,关键字struct可以省略,结构体变量利用操作符“.”访问成员
2.结构体数组
将自定义的结构体放入数组中方便维护
语法: struct 结构体名 数组名[元素个数]={{},{},……}
- 定义结构体
- 创建结构体数组
- 给结构体数组中的元素赋值
struct Student
{
string name;
int age;
}
int main(){
struct Student arr[3]=
{
{"zhangsan",22},
{"lisi",33},
{"wangwu",44}
}
arr[1].name="zhaoliu";
arr[1].age=30;
}
}
3.结构体指针
利用操作符 -> 可以通过结构体指针访问结构体属性
- 创建结构体变量
- 通过指针指向结构体变量
- 通过指针访问结构体变量中的数据
Student stu={"zhangsan",22};
Student * p =&stu;
cout<<p->name<<endl //要添加头文件 #include <string>
4.结构体嵌套结构体
一个老师辅导一个学生
struct Teacher{
string teacherName;
int teacherAge;
Student stu;
}
struct Student{
studentName;
studentAge;
}
5.结构体做函数参数
//值传递
void printStudent(Student stu){
stu.name="lisi";
cout<<"name="<<stu.name<<endl;
cout<<"age="<<stu.age<<endl;
}
//地址传递
void printStudent2(Student * p){
cout<<"name="<<stu->name<<endl;
cout<<"age="<<stu->age<<endl;
}
int main(){
Student student ;
student.name="zhangsan";
student.age=22;
printStudent(student);
printStudent2(&student);
}
总结:
- 如果不想修改主函数中的数据,用值传递,反之用地址传递。
个人理解: - 值传递,将实参的数据拷贝到形参,然后进行处理,非常占用内存空间。形参和实参不是同一个对象,只是他们的值时一样的。
- 地址传递,将函数中的形参改为指针,可以减少内存空间,不会赋值新的副本出来。
6.结构体中const使用场景
作用:用const来防止误操作。
比如:将函数里面的结构体进行修改了。
struct Student
{
string name;
int age;
};
//值传递
void printStudent( const Student *stu){
// stu->name="lisi"; 报错 const 修饰了结构体 不可以修改结构体。一旦有修改的操作就会报错,可以防止我们的误操作
cout<<"name="<<stu.name<<"age="<<stu.age<<endl;
}
int main(){
Student student ={"zhangsan",22};
printStudent(&student);
}
7.案例1
需求:
- 三个老师分别带5个学生,并打印学生和老师的信息
struct Student {
string stuName;
int age;
};
//案例
struct Teacher {
string teacherName;
struct Student stu[5];
};
void printTeacher(struct Teacher teacher[], int length) {
for (int i = 0; i < length; i++)
{
cout << "老师姓名" << teacher[i].teacherName << endl;
int length2 = sizeof(teacher[i].stu) / sizeof(teacher[i].stu[0]);
for (int j = 0; j < length2; j++)
{
cout << "学生姓名" << teacher[i].stu[j].stuName << endl;
}
}
}
int main() {
Teacher teacher[3] = {
{"wang",{{"wang1",11},{"wang2",12},{"wang3",13},{"wang4",14},{"wang5",15},}},
{"wang11",{{"wang1",11},{"wang2",12},{"wang3",13},{"wang4",14},{"wang5",15},}},
{"wang22",{{"wang1",11},{"wang2",12},{"wang3",13},{"wang4",14},{"wang5",15},}}
};
int length = sizeof(teacher) / sizeof(teacher[0]);
printTeacher(teacher,length);
}
7.案例2
给五个英雄进行年龄排序,打印排序后的结果
struct Hero
{
string name;
int age;
};
//冒泡排序,升序
void bubbleSort(struct Hero heroArray[], int len) {
for (int i = 0; i < len-1; i++) {
for (int j = 0; j < len - i - 1; j++) {
if (heroArray[j].age > heroArray[j + 1].age) {
struct Hero temp = heroArray[j];
heroArray[j] = heroArray[j + 1];
heroArray[j + 1] = temp;
}
}
}
}
void printHero(struct Hero heroArray[],int len) {
for (int i = 0; i < len; i++)
{
cout << "英雄姓名" << heroArray[i].name <<"年龄:"<<heroArray[i].age << endl;
}
}
int main() {
Hero heroArray[] = {
{"刘备",33},
{"关羽",22},
{"张飞",32},
{"貂蝉",27}
};
int len = sizeof(heroArray) / sizeof(heroArray[0]);
bubbleSort(heroArray, len);
printHero(heroArray, len);
}
通讯录管理系统
需求:
- 添加联系人: 最多添加1000人
- 显示联系疼:
- 删除联系人:
- 查找联系人:
- 修改联系人:
- 清空联系人:
- 退出通讯录:
struct Person {
string name;
int age;
};
struct Addressbooks {
struct Person personArray[MAX];//通讯录中保存的联系人数组;
int m_Size;//通讯录中人员个数
};
void addPerson(Addressbooks * abs) {
//判断通讯录是否已经<1000
if (abs->m_Size<MAX) {
cout << "请输入姓名:" << endl;
string name = "";
cin >> name;
cout << "请输入年龄:" << endl;
int age = 0;
cin >> age;
abs->personArray[abs->m_Size] = { name,age };
abs->m_Size++;
cout << "添加用户成功" << endl;
system("pause"); //请按任意键继续
system("cls");//清屏
}
else {
cout << "通讯录已满,不能再添加了" << endl;
}
}
void showPerson(Addressbooks * abs) {
if (abs->m_Size == 0) {
cout << "没有联系人" << endl;
}
else {
for (int i = 0; i < abs->m_Size; i++)
{
cout << "姓名:" << abs->personArray[i].name<<"\t\t年龄:"<<abs->personArray[i].age << endl;
}
}
system("pause"); //请按任意键继续
system("cls");//清屏
}
int isExist(Addressbooks * abs,string name) {
for (int i = 0; i < abs->m_Size; i++) {
if (name == abs->personArray[i].name) {
return i;
}
}
return -1;
}
void delPerson(Addressbooks * abs) {
cout << "请输入你要删除的联系人姓名:" << endl;
string name = "";
cin >> name;
int res = isExist(abs, name);
if (res == -1) {
cout << "查无此人" << endl;
}
else {
for (int i = res; i < abs->m_Size; i++) {
//数据迁移
abs->personArray[i] = abs->personArray[i + 1];
}
abs->m_Size--;
cout << "删除成功" << endl;
}
system("pause"); //请按任意键继续
system("cls");//清屏
}
void findPerson(Addressbooks * abs) {
cout << "请输入你要查找的联系人姓名:" << endl;
string name = "";
cin >> name;
int res = isExist(abs, name);
if (res == -1) {
cout << "查无此人" << endl;
}
else {
cout << "姓名:" << abs->personArray[res].name << "\t\t年龄:" << abs->personArray[res].age << endl;
}
system("pause"); //请按任意键继续
system("cls");//清屏
}
void updatePerson(Addressbooks * abs) {
cout << "请输入你要修改的联系人姓名:" << endl;
string name = "";
cin >> name;
int res = isExist(abs, name);
if (res == -1) {
cout << "查无此人" << endl;
}
else {
cout << "请输入修改的姓名:" << endl;
string name = "";
cin >> name;
cout << "请输入修改的年龄:" << endl;
int age = 0;
cin >> age;
abs->personArray[res] = { name,age };
cout << "修改成功" << endl;
}
system("pause"); //请按任意键继续
system("cls");//清屏
}
void clearPerson(Addressbooks* abs) {
abs->m_Size = 0;
cout << "通讯录已经清空了" << endl;
system("pause"); //请按任意键继续
system("cls");//清屏
}
int main() {
Addressbooks abs;
abs.m_Size = 0;
while (true) {
showMenu();
int num = 0;
cout << "请选择你的操作:";
cin >> num;
switch (num)
{
case 1: //添加联系人
addPerson(&abs);//通过地址传递 可以修改size大小。
break;
case 2://显示联系人
showPerson(&abs);
break;
case 3://删除联系人
delPerson(&abs);
break;
case 4://查找联系人
findPerson(&abs);
break;
case 5://修改联系人
updatePerson(&abs);
break;
case 6://清空联系人
clearPerson(&abs);
break;
case 0:
cout << "欢迎下次使用:" << endl;
system("pause"); //请按任意键继续
return 0;
break;
default:
break;
}
}
二、C++核心编程
C++面向对象编程
内存分区模型
代码区、全局区、栈区、堆区
意义:不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程。
代码执行前,分两个区:代码区和全局区
1.代码区
存放函数体的二进制代码,由操作系统进行管理
特点:共享、只读。exe可执行文件,只有一份代码,共享的,不可以修改。
2.全局区
存放全局变量和静态变量以及常量
由操作系统进行回收和释放;
同一个区,他们的内存地址很近
常量:
- 字符串常量 :“hello world”
- const 修饰的全局常量: const int a =10;
局部常量不存放在全局区;
总结:
- 全局区:全局变量、静态变量 、常量(字符串常量、const 修饰的全局常量)
- 不在全局区:局部变量、const修饰的局部变量(局部常量)
3.栈区
由编译器自动分配释放,存放函数的参数值,局部变量等
注意:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放。
int * func(){
int a =10;
return &a;
}
int main(){
int * p = func();
cout<<*p<<endl;//10 第一次可以打印正确的数字,是因为编译器做了保留
cout<<*p<<endl;//非10的数据,第二次这个数据就不再保留。理解为乱码。所以不能返回局部变量的地址。
}
4.堆区
由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
主要是利用new在堆区开辟内存空间
int * func(){
//new int(10); 返回的是一个地址 需要用指针来接收
//指针本质也是局部变量,放在栈上,指针保存的数据是放在堆区。
int * p=new int(10);
return p;
}
int main(){
int * p = func();
cout<<*p<<endl;
}
new操作符:
- 利用new创建的数据,会返回该数据对应类型的指针;
- 释放堆区的数据,利用关键字 delete; eg: delete p; delete[] pArray;
- 数组返回的是数组的首地址,因为数组的内存空间是连续的。eg: int * pArray=new int[2];
void func1(){
//1、new的基本语法:
double * p = new double(10);
cout<<*p<<endl;
//释放堆区的数据,利用关键字 delete
delete p;
// cout<<*p<<endl;//报错。读取访问权限冲突,解释:内存已经被释放,再次访问就是非法操作
}
void func2(){
int * pArray=new int[2]; //返回的是数组的首地址
pArray[0]=11;
pArray[1]=22;
delete[] pArray; //释放数组的时候,要添加[]
}
引用 ( 给变量取别名:int &b = a )
1.基本语法
作用:给变量取别名。
语法:数据类型 &别名 = 原名
- 引用必须初始化
- 引用一旦初始化后,就不可以更改。
//我想用b去操作a的内存
int a = 10 ;
// int &b ; //错误,必须初始化
int &b=a;
b=20;//a=20。原因:b操作的是内存。
int c =20;
b=c;//赋值操作,不是更改引用
2.引用做函数参数
作用:函数传参时,可以利用引用的技术让形参修饰实参
优点:可以简化指针修改实参
//值传递
void swap(int a,int b){
int temp =a;
a= b ;
b=temp;
}
//地址传递
void swap2(int * a,int * b){
int temp =*a;
*a= *b ;
*b=temp;
}
int main(){
int a = 10;
int b = 20;
swap(a,b);
cout << "a="<< a << endl;//10
cout << "b="<< b << endl;//20
swap2(&a,&b);
cout << "a="<< a << endl;//20
cout << "b="<< b << endl;//10
}
----- 引用传递
//引用传递
void swap3(int &a,int &b){
int temp =a;
a= b ;
b=temp;
}
int main(){
//引用传递,形参会修饰实参的
swap3(a,b); // 形参中的 &a 时 实参中的别名
cout << "a="<< a << endl;//20
cout << "b="<< b << endl;//10
}
3.引用做函数返回值
作用:引用是可以作为函数的返回值存在的
用法:函数调用作为左值
- 不要返回局部变量的引用
- 函数调用可以作为左值
//返回局部变量的引用
in& test(){
int a =10;
return a;
}
in& test2(){
static int a =10; //存放在全局区,全局区上的数据在程序结束后系统释放
return a;
}
int main(){
int &ref = test();
cout << "ref="<< ref << endl;//10 第一次结果正确,因为编译器做了保留
cout << "ref="<< ref << endl;//234553乱码了。第二次结果错误,因为a的内存已经释放。
int &ref2 = test2();
cout << "ref2 ="<< ref2 << endl;//10
cout << "ref2 ="<< ref2 << endl;//10
test2()=1000; //如果函数的返回值的引用,这个函数调用可以作为左值. 即将1000赋值给引用ref2
cout << "ref2 ="<< ref2 << endl;//1000
}
4.引用的本质
本质:引用的本质在c++内部实现时一个指针常量
引用一旦初始化后,就不可以发生该改变。
void func(int &ref){
ref=100; //ref是引用,转换为*ref=100;
}
int main(){
int a =10;
int &ref =a; //自动转换int* const ref =&a;指针常量是指针指向不可改,也说明为什么引用不可更改
ref=20; //内部发现ref是引用,自动帮我们转换成*ref=20;
cout << "a="<< a<< endl;//10
cout << "ref="<< ref << endl;//10
func(a);
return 0;
}
5.常量引用
作用:主要是用来修饰形参,防止误操作
在函数形参列表中,可以加const修饰形参,防止形参改变实参
//误操作
int a =10;
//int & ref =10 ;报错,引用必须引一块合法的内存空间
const int & ref =10;//加上const之后,编译器将代码修改 int temp =10;const int & ref =temp;
//ref = 20; //报错,加上const之后变成只读,不可以修改
//使用场景:用来修饰形参,防止误操作
void show(int &val){
val=1000;
cout << "val="<< val<< endl;
}
void show2(const int &val){ //加上const 是不可以修改 防止形参改变实参
//val=1000; 报错,不可以修改
cout << "val="<< val<< endl;
}
int mian(){
int a =100;
show(a);
show(a);
}
函数
1.默认参数
语法:返回值类型 函数名(参数=默认值){ }
- 1、如果某个位置参数有默认值,那么从这个位置往后,即从左往右,必须要有默认值
- 2、如果函数声明有默认值,函数实现的时候就不能有默认值
int func(int a,int b=10,int c=20){return a+b+c;}
//1、如果某个位置参数有默认值,那么从这个位置往后,即从左往右,必须要有默认值
//int func(int a,int b=10,int c){return a+b+c;} //报错 c必须有默认值
//2、如果函数声明有默认值,函数实现的时候就不能有默认值。两者只能有一个有默认值
int func2(int a=10,int b=10); //声明函数
int func2(int a=10,int b=10)(return a+b;)//函数实现
int mian(){
func(10);//40
func(10,20);//50
func2(10,10);//运行报错
}
2.函数的占位参数
占位参数:返回值类型 函数名 (数据类型)
void func(int a ,int){}
//占位参数可以有默认值
void func2(int a ,int=10){}
int main(){
fun(10,20);
fun2(30);
}
3.函数重载
作用:函数名可以相同,提高复用性
满足条件:
- 同一个作用域
- 函数名相同
- 函数参数类型不同或者个数不同或者顺序不同
注意:函数的返回值不可以作为函数重载的条件。
原因:函数调用的时候无法通过返回值确定调用的是哪个函数
int show();
int show(int a);
int show(int a ,string b);
int show(string a,int b);
void show(int a,int b);
4.函数重载注意事项
- 引用作为重载条件
- 函数重载碰到函数默认参数
//引用作为重载条件
void func(int &a){ } //int &a=10 ;不合法
void func(const int &a){} //const int &a=10;合法
int main(){
int a =10;
func(a);//调用的是第一个函数void func(int &a)。原因:a是一个变量
func(10);//调用的是第二个函数void func(const int &a)。
}
//函数重载碰到函数默认参数
void func2(int a){ }
void func2(int a,int b=20){ }
int main(){
// func2(10);//编译的时候报错,尽量避免重载的时候使用默认参数。
}
知识点
1、获取数组长度
int arr[] = { 1,5,9,10,9,2 };
int len = sizeof(a)/sizeof(a[0])
原理:sizeof()函数可以返回数组所占的内存,而sizeof(a[0])返回的是数组第一个元素所占的内存。
2、随机数种子
#include <ctime> //系统时间的头文件
//随机数种子:按照系统的时间进行随机。公平性
strand(unsigned int)time(NULL);
//随机数
int rand = rand()%61;//0~60
int rand2 = rand()%61+40;//40~100