6 函数
可以将一段经常使用的代码封装起来,减少重复的代码
6.1 函数的定义
一般有五个步骤:
- 返回值类型
- 函数名
- 参数列表
- 函数体语句
- return表达式
语法:
返回值类型 函数名(参数列表){
函数体语句;
return表达式;
}
6.2 函数的调用
语法:
函数名称 (参数)
//定义函数时的参数为形参;在调用函数的时候的参数为实参;实参的值会传递给形参
6.3 值传递
即函数调用的时候实参将数值传递给形参
- 在值传递的时候,如果形参改变,那么实参不会被影响**(函数内部局部变量不影响外部)**
6.4 函数的常见形式
- 无参无返
- 有参无返
- 无参有返
- 有参有返
6.5 函数的声明(C++11以后可以不用声明)
告诉编译器函数名称以及如何调用函数(必须在主函数之前),函数的实际主体可以单独定义(可以在主函数之后)
- 函数可以声明多次,但是函数的定义只能有一次
语法:
返回值类型 函数名(参数列表);
6.6 函数的分文件编写
**作用:**让代码结构更加清晰
步骤:
-
创建后缀名为.h的头文件
-
创建后缀名为.cpp的源文件
-
在头文件中写函数的声明,在函数中需要引用的头文件等也需要写在这里
-
在源文件中写函数的定义,同时也要在源文件中写入
#include “函数名.h”
(引用自定义的头文件需要使用双引号而非单括号) -
在主函数的源文件引用所创建的文件
7 指针
7.1 指针变量的定义和使用
使用指针可以间接访问内存。
- 内存编号是从0开始记录的,一般用十六进制数字表示
- 可以使用指针变量保存地址
定义指针的语法:
数据类型 * 指针变量名;
指针前加的*代表解引用,可以找到指针指向的内存。
&
符号的意思是取地址,即返回一个对象在内存中的地址;
*
符号的意思是取一个指针所指向的对象,即,如果一个指针p
保存着一个内存地址,那么 * p
就是返回那个地址所存储的值。
7.2 指针与内存空间
在32位操作系统下,指针占用4个字节空间;
在64位操作系统下,指针占用8个字节空间。
7.3 空指针和野指针
7.3.1 空指针
**空指针:**指针变量指向内存中编号位0的空间
**用途:**初始化指针变量
语法:int * p = NULL;
- 空指针指向的内存是不可以访问的,这是因为0~255之间的内存是系统占用的,不可以访问
7.3.2 野指针
**野指针:**指针变量指向非法的内存空间
空指针和野指针都不是我们自己所申请的内存空间,不能随意访问
7.4 常量指针、指针常量和常指针常量
const修饰指针有三种情况:
-
const修饰指针 —常量指针(指向常量的指针。可以改地址,不能改值)
const 数据类型 * 指针变量 = 变量名; 或 数据类型 const * 指针变量 = 变量名;
特点:定义一个常量指针后,指针所指向的值就不能被改变,即不能通过指针变量直接更改指针所指向的地址的值(但是可以改变指针的指向、或者使用指针所指向的变量名直接修改值)。
const int *p = &i; *p = 26; //Error i = 26; //OK p = &j; //OK
-
const修饰常量 —指针常量(指针是常量。不能改地址,可以改值)
数据类型 * const 指针变量 = 变量名;
特点:修饰符const与指针变量紧邻,说明指针变量本身不允许修改,因此一定要在定义的时候为指针指定初始值(指向一个存在的地方)。
int * const q = &i; *q = 26; //OK q++; //Error
-
const既修饰指针,又修饰常量 —常指针常量
const 数据类型 * const 指针变量 = 变量名;
指针的指向和指针指向的值都不可以更改。
7.5 指针和数组
我们可以利用指针访问数组中的元素。
指针和数组基本等价的原因在于指针算术(pointer arithmetic)和C++内部处理数组的方式。多数情况下,C++将数组名解释为数组第一个元素的地址。
7.5.1 指针算术
将指针变量加1之后,增加的值等于指向的类型占用的字节数。还可以使用一个指针减去另一个指针,得到两个指针的差并返回一个整数(当且仅当两指针指向同一个数组时有意义),这个整数表示两个元素的间隔。
7.5.2 静态联编与动态联编
**[静态联编]**使用数组声明创建数组时使用的是静态联编,即数组长度在编译时设置。
**[动态联编]**与C语言中的malloc函数类似,在C++中我们也可以使用动态内存分配来为指针预先分配一定的内存,但是在C++中使用的是new
操作符,new
操作符返回的是未命名的内存的地址。
语法:数据类型 * 指针变量 = new 数据类型 [size]
在使用结束后需要使用delete [] 指针变量
的方式来释放内存。
7.6 指针和函数
-
值传递 --不会改变实参
函数调用时,函数外的实参传递给形参。
在函数内部运算的是形参,而实参并不会发生相应的改变
-
地址传递 --会改变实参
可以在函数体中修改实参。函数的形参应该是指针,将实参的地址作为参数传入函数中。
8 结构体
8.1 结构体的基本概念
结构体属于用户自定义的数据类型
8.2 结构体定义和使用
语法:struct 结构体名 {结构体成员列表};
通过结构体创建变量的方式有三种:
- struct 结构体名 变量名
- struct 结构体名 变量名 = {成员1值, 成员2值 …}
- 定义结构体时顺便创建变量
//结构体定义
struct Student
{
//成员列表
string name;
int age;
int score;
}
//创建结构体的三种方法
//在创建结构体的时候,关键词struct其实可以省略;但是在定义结构体时不能省略。
//1、struct 结构体名 变量名
struct Student s1;
s1.name = "张三";
s1.age = 12;
s1.score = 89;
//2、struct 结构体名 变量名 = {成员1值, 成员2值...}
struct Student s2 = {“李四”, 13, 67};
//3、定义结构体时创建结构体变量(不常用)
struct Student
{
//成员列表
string name;
int age;
int score;
}s3;
s3.name = "王五";
s3.age = 12;
s3.score = 83;
- 定义结构体变量时关键字为struct,不可省略
- 创建结构体变量时,关键字struct可以省略
- 结构体变量使用操作符"."访问成员
8.3 结构体数组
将自定义的结构体放入数组中方便维护
语法:struct 结构体名 数组名[元素个数] = { {}, {}…{}}
8.4 结构体指针
通过指针访问结构体中的成员
利用操作符->
可以通过结构体指针访问结构体属性
struct Student{
string name;
int age;
int score;
};
Student s = {"张三", 23, 67};
Student * p = & s;
//p -> name为“张三”, p -> age为23
8.5 嵌套结构体
结构体中的成员可以是另一个结构体
struct S1{
string name;
int age;
int score;
};
struct S2{
int ID;
string name;
int age;
struct S1 stu;//此处stu指代一个结构体变量S1 stu,如果有多个内容的话可以使用结构体数组代替
};
8.6 结构体中const的使用场景(常量结构体指针)
结构体可以作为参数传递到函数中去,与其他变量一样,也有值传递和地址传递两种方式
- 为了防止内存爆炸,比较大的结构体一般使用地址传递
- 如果使用地址传递的同时想防止在函数的内部改变结构体的属性,可以使用
const 结构体名 * 指针名
作为函数的形参(常量结构体指针)