C++基础入门学习(基本语法,指针,结构体,内存模型,引用,函数) (一)

一、基础

基础语法

1.单行注释和多行注释
2.变量
3.常量

  • 宏常量
  • const修饰的变量:常量
//a. #define 宏常量:一般定义在文件的上方。	
 #define  Day  7
//b. const修饰的变量:一般在变量定义前加关键字,修饰该变量为常量,不可修改。
 const  int day =7

4.标识符命名规则

1、不可以有关键字
2、只能是字母、数字、下划线,第一个子父不能是数字
3、字母区分大小写。

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

  • 整型
数据类型占用空间
short2字节
int4字节
longwindows:4字节 Linux:4字节(32位),8字节(64位)
long long8字节

sizeof :统计数据类型所占内存大小,sizeof(数据类型/变量)。eg: sizeof(int);; 输出就是4

  • 实型(浮点型)
数据类型占用空间有效数字范围
float4字节7位有效数字
double8字节15~16位有效数字
  • 字符型
    用于显示单个字符
    char ch =‘a’;
    注意:单引号;只能有一个字符
    只占1个字节
    字符型变量并不是把子父本身放到内存中存储,而是将对应的ASCII编码放入到存储单元

  • 转义字符

转义字符含义ASCII码值(十进制)
\a警报007
\b退格,将当前位置移到前一页008
\f换页012
\n换行010
\r回车
\t水平制表
\v垂直制表
*\ *反斜线|
\ ’一个单引号039
\ "双引号
\ ?问号
\0数字0
\ddd8进制转义字符,d范围0~7
\xhh16进制转义字符
  • 字符串类型
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[ ]={010203040}

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
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值