教材:C++primer plus
视频:黑马程序员匠心之作——C++从0到1入门编程
作者:尘鱼好美
文章目录- C++学习笔记
- @[toc]
- 附录
- 1、Visual Studio快捷键
- 第一章、C++初识
- 1.1、第一个C++程序
- 1.2、注释
- 1.3、变量
- 1.4、常量
- 1.5、关键字
- 1.6、标识符命名规则
- 第二章、数据类型
- 2.1、整型
- 2.2、sizeof关键字
- 2.3、实型(浮点型)
- 2.4、字符型
- 2.5、转义字符
- 2.6、字符串型
- 2.7、布尔类型
- 2.8、数据的输入
- 第三章、运算符
- 3.1、算术运算符
- 3.2、赋值运算符
- 3.3、比较运算符
- 3.4、逻辑运算符
- 第四章、程序流程结构
- 4.1、选择结构
- 4.1.1、if语句
- 第五章、数组
- 5.1、概述
- 5.2、一维数组
- 5.2.1、一维数组的定义方式
- 5.2.2、一维数组数组名
- 5.2.3、练习案例1:五只小猪称体重
- 5.2.4、练习案例2:元素逆置
- 5.2.5、冒泡排序
- 5.3、二维数组
- 5.3.1、二维数组的定义方式
- 5.3.2、二维数组的数组名
- 5.3.3、二维数组应用案例
- 第六章、函数
- 6.1、概述
- 6.2、函数的定义
- 6.3、函数的调用
- 6.4、值传递
- 6.5、函数的常见形式
- 6.6、函数的声明
- 6.7、函数的分文件编写
- 第七章、指针
- 7.1、指针的基本概念
- 7.2、指针变量的定义和使用
- 7.3、指针所占内存空间
- 7.4、空指针
- 7.5、野指针
- 7.6、const修饰指针
- 7.7、指针和数组
- 7.8、指针和函数
- 7.9、指针配合数组和函数案例
- 第八章、结构体
- 8.1、结构体基本概念
- 8.2、结构体定义和使用
- 8.3、结构体数组
- 8.4、结构体指针
- 8.5、结构体嵌套结构体
- 8.6、结构体做函数参数
- 8.7、结构体中const使用场景
- 8.8、结构体案例
- 8.8.1、案例一
- 8.8.2、案例二
- 大作业:通讯录管理系统
- 第九章、C++核心编程
- 9.1、内存分区模型
- 9.1.1、程序运行前
- 9.1.2、程序运行后
- 9.1.3、new *** 作符
- 9.2、引用
- 9.2.1、引用的基本使用
- 9.2.2、引用的注意事项
- 9.2.3、引用做函数的返回值
- 9.2.4、引用的本质
- 9.2.5、常量引用
- 9.3、函数提高
- 9.3.1、函数默认参数
- 9.3.2、函数占位参数
- 9.3.3、函数重载概述
- 9.2.4、引用的本质
- 9.2.5、常量引用
- 9.3、函数提高
- 9.3.1、函数默认参数
- 9.3.2、函数占位参数
- 9.3.3、函数重载概述
一、文件相关
- 打开文件窗口:Alt + F
- 新建项目:Ctrl + Shift + N
- 新建文件:Ctrl + N
- 打开项目/解决方案:Ctrl + Shift + O
- 打开文件夹:Ctrl + Shift + Alt + O
- 打开网站:Shift + Alt + O
- 打开文件:Ctrl + O
- 保存单个文件:Ctrl + S
- 全部保存:Ctrl + Shift + S
- 打印:Ctrl + P
- 退出:Alt + F4
二、编辑相关
- 打开编辑窗口:Alt + E
- 转到行:Ctrl + G
- 转到所有:Ctrl + T
- 转到文件:Ctrl + Shift + T
- 转到最近文件:Ctrl + 1,R
- 转到类型:Ctrl + 1,Ctrl + T
- 转至成员:Alt +
- 转到符号:Ctrl + 1,Ctrl + S
- 转到文件中的下个问题:Alt + PgDn
- 转到文件中的上个问题:Alt + PgUp
- 转到上一个编辑位置:Ctrl + Shift + Backspace
- 搜索框:Ctrl + Q
- 快速查找:Ctrl + F
- 快速替换Ctrl + H
- 在文件中查找:Ctrl + Shift + F
- 在文件中替换:Ctrl + Shift + H
- 撤销:Ctrl + Z
- 重做:Ctrl + Y
- 剪切:Ctrl + X
- 复制:Ctrl + C
- 粘贴:Ctrl + V
- 显示剪贴板历史记录:Ctrl + Shift + V
- 复制一行:Ctrl + D
- 删除:Del
- 全选:Ctrl + A
- 设置文档的格式:Ctrl + K,Ctrl + D
- 设置选定内容的格式:Ctrl + K,Ctrl + F
- 转换为大写:Ctrl + Shift + U
- 转换为小写:Ctrl + U
- 将选定行上移:Alt + ↑
- 将选定行下移:Alt + ↓
- 删除水平空白:Ctrl + K,Ctrl +
- 将选定内容扩展到包含块:Shift + Alt + ]
- 展开选定内容:Shift + Alt + =
- 收缩选定内容:Shift + Alt + -
- 查看空白:Ctrl + R,Ctrl + W
- 自动换行:Ctrl + E,Ctrl + W
- 渐进式搜索:Ctrl + I
- 切换行注释:Ctrl + K,Ctrl + /
- 切换块注释:Ctrl + Shift + /
- 注释选定内容:Ctrl + K,Ctrl + C
- 取消注释选定内容 Ctrl + K,Ctrl + U
- 切换书签:Ctrl + K,Ctrl + K
- 上一个书签:Ctrl + K,Ctrl + P
- 下一个书签:Ctrl + K,Ctrl + N
- 清除书签:Ctrl + K,Ctrl + L
- 文件夹中的上一书签:Ctrl + Shift + K,Ctrl + Shift + P
- 文件夹中的下一书签:Ctrl + Shift + K,Ctrl + Shift + N
- 添加任务列表快捷方式:Ctrl + K,Ctrl + H
- 切换大纲显示展开:Ctrl + M,Ctrl + M
- 切换所有大纲显示:Ctrl + M,Ctrl + L
- 停止大纲显示:Ctrl + M,Ctrl + P
- 停止隐藏当前区域:Ctrl + M,Ctrl + U
- 折叠到定义:Ctrl + M,Ctrl + O
- 列出成员:Ctrl + J
- 参数信息:Ctrl + Shift + 空格键
- 快速信息:Ctrl + K,Ctrl + I
- 完成单词:Ctrl + 空格键
- 切换完成模式:Ctrl + Alt + 空格键
- 外侧代码:Ctrl + K,Ctrl + S
- 插入片段:Ctrl + K,Ctrl + X
- 插入下一匹配的脱字号:Shift + Alt + .
- 在所有匹配位置插入脱字号:Shift + Alt + ;
- 滚动窗口但不移动光标:Ctrl + Up/Down(方向键↑、↓)
- 转到定义:F12
- 在当前行插入空行:Ctrl + Enter
- 在当前行下方插入空行:Ctrl + Shift + Enter
- 块选择:Alt + Shift + 方向键、Shift + 方向键
- 选择矩形文本:Alt + 鼠标左键
- 匹配括号:Ctrl + }
- 选择括号、括号内的文本:Ctrl + Shift + }
- 从头到尾选择整行:Shift + End
- 从尾到头选择整行:Shift + Home
三、视图相关
- 打开视图窗口:Alt + V
- 代码:F7
- 解决方案资源管理器:Ctrl + Alt + L
- 团队资源管理器:Ctrl + ,Ctrl + M
- 服务器资源管理器:Ctrl + Alt + S
- 测试资源管理器:Ctrl + E,T
- 书签窗口:Ctrl + K,Ctrl + W
- 调用层次结构:Ctrl + Alt + K
- 类视图:Ctrl + Shift + C
- 代码定义窗口:Ctrl + ,D
- 对象浏览器:Ctrl + Alt + J
- 错误列表:Ctrl + ,E
- 输出:Ctrl + Alt + O
- 任务列表:Ctrl + ,T
- 工具箱:Ctrl + Alt + X
- 通知:Ctrl + ,Ctrl + N
- 查找符号接口:Ctrl + Alt + F12
- 命令窗口:Ctrl + Alt + A
- Web浏览器:Ctrl + Alt + R
- 任务运行程序资源管理器:Ctrl + Alt + Backspace
- 文档大纲:Ctrl + Alt + T
- 资源视图:Ctrl + Shift + E
- 全屏膜:Shift + Alt + Enter
- 所有窗口:Shift + Alt + M
- 向后导航:Ctrl + -
- 向前导航:Ctrl + Shift + -
- 属性窗口:F4
- 属性页:Shift + F4
四、项目相关
- 打开项目窗口:Alt + P
- 类向导:Ctrl + Shift + X
- 添加新项:Ctrl + Shift + A
- 添加现有项:Shift + Alt + A
五、生成相关
- 生成解决方案:Ctrl + Shift + B
- 对解决方案运行代码进行分析:Alt + F11
- 生成项目:Ctrl + B
- 编译:Ctrl + F7
六、调试相关
- 打开调试窗口:Alt + D
- 断点窗口:Ctrl + Alt + B
- 异常设置:Ctrl + Alt + E
- 显示诊断工具:Ctrl + Alt + F12
- 即时:Ctrl + Alt + I
- 启动图形调试:Alt + F5
- 开始调试:F5
- 开始执行(不调试):Ctrl + F5
- 停止调试:Shift + F5
- 重新启动调试:Ctrl + Shift + F5
- 性能探查器:Alt + F2
- 附加到进程:Ctrl + Alt + P
- 逐语句:F11
- 逐过程:F10
- 切换断点:F9
- 启动/停止断点:Ctrl + F9
- 运行到光标处:Ctrl + F10
- 函数断点:Ctrl + K,B
- 停止调试:Shift + F5
七、测试相关
- 打开测试窗口:Alt + S
- 运行所有测试:Ctrl + R,A
- 重复上次运行:Ctrl + R,L
- 调试所有测试:Ctrl + R,Ctrl + A
- 调试上次运行:Ctrl + R,D
- 测试资源管理器:Ctrl + E,T
八、分析相关
- 打开分析窗口:Alt + N
- 对文件运行代码分析:Ctrl + Shift + Alt + F7
九、工具相关
- 打开工具窗口:Alt + T
- 代码片段管理器:Ctrl + K,Ctrl + B
十、扩展相关
- 打开扩展窗口:Alt + X
十一、窗口相关
- 打开窗口:Alt + W
- 关闭:Shift + Esc
十二、帮助相关
- 打开帮助窗口:Alt + H
- 查看帮助:Ctrl + F1
简介
在C++中,我们用cout进行字符输出;用//来注释。C++对大小写敏感,所以写cout和COUT是不一样的。C++对拼写也敏感,名字该是怎么样就怎么样,不能拼写错。文件扩展名采用cpp,类比python采用py,java采用java,C采用c。
输入和输出
相比于printf(),可能很多人看到cout大吃一惊。事实上C++是可以用printf的,包括后面学到输入函数cin,实际上也是可以用scanf来替换,但是必须添加C的头文件,即stdio.h。
C++输出特性的优点
cout拥有printf两大没有的优点。
- cout可以只能辨认后面的是字符串还是整型变量,而printf不可以
- cout写起来少了两个字母。
头文件名
在下面的代码中我们会看到iostream,我们把这类文件叫做包含文件,又由于他们包含在其他文件中,所以我们叫头文件。在C语言里,头文件类如xxx.h的,其带有后缀h,而在C++中,很多h后缀转为c前缀,意为他们是从c过渡来的;例如C语言中的math.h,在C++中如果要引用他是用cmath。当然,去掉了h后还是要加上名称空间来确定他到底指的是哪个头文件的。
名称空间
如果使用iostream而不是iostream.h,则应该使用下面的名称空间编译指令来使iostream中的定义对程序可用。即using namespace std,这个叫做using编译指令,这个东西前面不细讲,后面再大为介绍,现在做一个了解。
名称空间的支持是C++的一大特性,其作用是让你编写大型程序以及将多个厂商现有的代码组合起来的程序更容易。
比如现在有两个函数,他们都叫cout,但是一个是Microsoft厂商提供的,一个是Pisc公司提供的,那他们两个做这个cout函数的时候,就可以给cout函数的定义放到一个名称空间里,比如Microsoft把cout函数放到一个叫做Microflop的名称空间中,那么记为Microflop::cout;同样的Pisc公司也可以把他们的cout函数记为Piscine::cout。
按照我们上面那么说的话,那么我们写代码的时候,cout(输出)和cin(输入)或者其他等等等都是要写成std::cout,cin::cout的。但是为了偷懒,我们既然都是用std对应的厂家做出来的工具,那么我们直接在开局声明using namespace std,然后后面不写std::cout,而是直接写cout了。
实际上偷懒的写法在大型项目是要出问题的,但是我们在学习过程中写的都是练手的代码,所以不需要写那么麻烦。
更好的做法就是开局声明如下:
using std::cout; using std::endl; using std::cin;
这样的话就可以精确到你要用的是std的某个工具,而不用使用using namespace std来让你以后用的工具全是std的。
示例:
//这是第一个程序 #includeusing namespace std; int main() { cout << "hello world" << endl; system("pause"); return 0; }
1.2、注释
作用:在代码中加一些说明和解释,方便自己或其他程序员阅读代码
两种格式
1、单行注释 //描述信息
- 通常放在一行代码的上方,或者一条语句的末尾,对该行代码进行说明
2、多行注释
- 通常放在一段代码的上方,对该段代码做整体说明
实际上是C-风格注释,在实际应用中应该尽量使用C++注释,因为这不涉及到结尾符号和起始符号的正确配对,所以他产生的问题很小。
【注1:编译器编译代码内容时,会自动忽略注释内容。】
【注2:如果想要在Visual stdio里面注释一大段可以采用快捷键crtl+k+c】
1.3、变量
作用:给一段指定的内存空间起名,方便 *** 作这段内存
语法:数据类型 变量名 = 变量初始值
int a = 10;
示例:
#includeusing namespace std; int main() { //变量创建的语法: 数据类型 变量名 = 变量初始值 int a = 10; cout << "a = " << a << endl; system("pause"); return 0; }
1.4、常量
作用:用于记录程序中不可更改的数据
C++定义常量两种方式
1、#define宏常量:#define 常量名 常量值
【通常在文件上方定义,表示一个常量】
2、const修饰的变量:const 数据类型 常量名 = 常量值
【通常在变量定义之前加关键字const,修饰该变量为常量,不可修改】
示例:
#includeusing namespace std; //常量的定义方法 //1、#define 宏定义 //2、const修饰的变量 //1、#define 宏定义 #define Day 7 int main() { //2、const修饰的变量 const int a = 7; cout << "一周总共有:" << a <<"天"<< endl; system("pause"); return 0; }
1.5、关键字
作用:关键字是C++中预先保留的单词(标识符)
【注:在定义变量或者常量时候,不要用关键字】
C++关键字如下:
【提示:在给变量或者常量起名字的时候,不要用C++关键字,否则会产生歧义】
1.6、标识符命名规则
作用:C++规定给标识符(变量、常量)命名时,有一套自己的规则
标识符不能是关键字 标识符只能由字母、数字、下划线组成 第一个字符必须为字母或下划线 标识符中字母区分大小写
【建议:给标识符命名时,争取做到见名知意的效果,方便自己和其他人阅读】
【注1:C++对于名称的长度没有限制,名称中所有的字符都有意义,但有些平台有长度限制】
【注2:以两个下划线打头或以下划线和大写字母打头的名称被保留给实现(编译器及其使用的资源)使用。以一个下划线开头的名称被保留给实现,用作全局标识符】
注1和注2和前面提到的规则有所不同,因为使用像_time_stop或 _Dount 这样的名称不会导致编译器错误,而会导致行为的不确定性。换句话说就是不知道输出的结果是什么 。不出现编译器错误的原因是,这样的名称虽然是非法的,但是要留给实现使用。
第二章、数据类型
C++规定在创建一个变量或者常量时,必须要指定相应的数据类型,否则无法给变量分配内存。
那上面这个图来举例,我们给利用int指定系统给变量开辟多大的空间,10用来往空间里面存放数据,而a作为变量名用来 *** 纵这个数据。
由此可知,数据类型存在的意义是给变量分配合适的内存空间。
2.1、整型作用:整型变量表示的是 整数类型 的数据
C++中能够表示整型的类型由以下几种方式,区别在于所占内存空间不同:
示例:
#includeusing namespace std; int main() { //1、短整型 short num1 = 10; cout << sizeof(num1) << endl; //2、整型 int num2 = 10; cout << sizeof(num2) << endl; //3、长整型 long num3 = 10; cout << sizeof(num3) << endl; //4、长长整型 long long num4 = 10; cout << sizeof(num4) << endl; system("pause"); return 0; }
2.2、sizeof关键字
作用:利用sizeof关键字可以统计数据类型所占内存大小
语法:sizeof(数据类型/变量)
示例:
#includeusing namespace std; int main() { //1、短整型 short num1 = 10; cout << sizeof(num1) << endl; //2、整型 int num2 = 10; cout << sizeof(num2) << endl; //3、长整型 long num3 = 10; cout << sizeof(num3) << endl; //4、长长整型 long long num4 = 10; cout << sizeof(num4) << endl; system("pause"); return 0; }
2.3、实型(浮点型)
作用:用于表示小数
浮点型变量分为两种:
1、单精度float
2、双精度double
两者的区别在于表示的有效数字范围不同。
实例:
#includeusing namespace std; int main() { //1、单精度 float //2、双精度 double float f1 = 3.14f; cout << "f1 = " << f1 << endl; double d1 = 3.14; cout << "d1 = " << d1 << endl; cout << "float sizeof = " << sizeof(f1) << endl; cout << "double sizeof = " << sizeof(d1) << endl; //科学计数法 float f2 = 3e2;//3*10^2 cout << "f2 = " << f2 << endl; float f3 = 3e-2;//3*0.1^2 cout << "f3 = " << f3 << endl; system("pause"); return 0; }
2.4、字符型
作用:字符型变量用于显示单个字符
语法:char ch = 'a'
【注1:在显示字符型变量时,用单引号将字符括起来,不要用双引号】
【注2:单引号内只能有一个字符,不可以是字符串】
- C和C++中字符型变量只占用一个字节
- 字符型变量并不是把字符本身放到内存中存储,而是将对应的ASCII编码放入存储单元。
实例:
#includeusing namespace std; int main() { //1、字符型变量创建方式 char ch = 'a'; cout << ch << endl; //2、字符型变量所占内存大小 cout << "char ch sizeof = " << sizeof(ch) << endl; //3、字符型变量常见错误 //char ch2 = "b";//创建字符型变量的时候,要用单引号 //char ch2 = 'abcdef'; //创建字符型变量的时候,单引号内只能有一个字符 //4、字符型变量对应ASCll编码 //a - 97 cout << (int)ch << endl; system("pause"); return 0; }
2.5、转义字符
作用:用于表示一些不能显示出来的ASCII的字符
2.6、字符串型
作用:用于表示一串字符
两种风格
1、C风格字符串:char 变量名[] = “字符串值”;
2、C++风格字符串:string 变量名 = “字符串值”
示例
#include#include //用C++风格字符串时候,要包含这个头文件 using namespace std; int main() { //1、C风格字符串 //注1: char 字符串名 [] //注2:等号后面要用双引号包含起来字符串 char str[] = "hello world"; cout << str << endl; //2、C++字符串 string str2 = "hello world"; cout << str2 << endl; system("pause"); return 0; }
2.7、布尔类型
作用:布尔数据类型代表真或假的值
bool类型只有两种值:
- true:真(本质是1)
- false:假(本质是0)
bool类型占一个字节大小
示例:
#includeusing namespace std; int main() { //1、创建bool数据类型 bool flag = true;//true代表真 cout << flag << endl; flag = false;//false代表假 cout << flag << endl; //本质上1代表真,0代表假 cout << "size of bool = " << sizeof(bool) << endl; system("pause"); return 0; }
2.8、数据的输入
作用:用于从键盘获取数据
关键字:cin
语法:cin>>变量
示例:
#include#include using namespace std; int main() { //1、整型 int a = 0; cout << "请给整型变量a赋值:" << endl; cin >> a; cout << "整型变量a = " << a << endl; //2、浮点型 float f = 3.14f; cout << "请给浮点型变量赋值:" << endl; cin >> f; cout << "浮点型变量f = " << f << endl; //3、字符型 char ch = 'a'; cout << "请给字符型变量ch赋值:" << endl; cin >> ch; cout << "字符型变量f = " << ch << endl; //4、字符串型 string str = "hello world"; cout << "请给字符串str赋值:" << endl; cin >> str; cout << "字符串str" << str << endl; //5、布尔类型 bool flag = false; cout << "请给布尔类型flag赋值" << flag << endl; cin >> flag; cout << "布尔类型flag = " << flag << endl; //只要非零的数都是真 system("pause"); return 0; }
第三章、运算符 3.1、算术运算符
作用:用于处理四则运算
算术运算符包括以下符号:
示例:加减乘除
#includeusing namespace std; int main() { //加减乘除 int a1 = 10; int b1 = 3; cout << a1 + b1 << endl; cout << a1 - b1 << endl; cout << a1 * b1 << endl; cout << a1 / b1 << endl;//两个整数相除,结果依然是整数,并且这个整数是将小数部分去除的结果 int a3 = 10; int b3 = 0; //cout << a3 / b3 << endl;//报错,除数不能为0 double a2 = 10.0; double b2 = 3.0; cout << a2 / b2 << endl; system("pause"); return 0; }
示例二:取模运算
#includeusing namespace std; int main() { int a1 = 10; int b1 = 3; cout << 10 % 3 << endl; int a2 = 10; int b2 = 20; cout << a2 % b2 << endl; int a3 = 10; int b3 = 0; cout << a3 % b3 << endl;//取值运算时,除数也不能为0 //两个小数不可以取模 double d1 = 3.14; double d2 = 1.1; //cout << d1 % d2 << endl; }
示例三:前置递增和后置递增
#includeusing namespace std; int main() { //1、前置递增 int a = 10; ++a;//让变量+1 cout << "a = " << a << endl; //2、后置递增 int b = 10; b++; cout << "b = " << b << endl; //3、前置后置的区别 //前置递增 先让变量+1然后进行表达式运算 int a2 = 10; int b2 = ++a2 * 10; cout << "a2 = " << a2 << endl; cout << "b2 = " << b2 << endl; //后置递增 先进行表达式运算,然后让变量+1 int a3 = 10; int b3 = a3++ * 10; cout << "a3 = " << a3 << endl; cout << "b3 = " << b3 << endl; system("pause"); return 0; }
3.2、赋值运算符
作用:用于将表达式的值赋给变量
赋值运算符包括以下几个符号:
示例:
3.3、比较运算符
作用:用于表达式的比较,并返回一个真值或假值。
比较运算符有以下符号:
示例:
3.4、逻辑运算符
作用:用于根据表达式的值返回真值或假值
逻辑运算符有以下符号:
示例1:逻辑非
#includeusing namespace std; int main() { //逻辑运算符 非! int a = 10; //在C++中,除了0都为真 cout << !a << endl; system("pause"); return 0; }
【总结:真变假,假变真】
第四章、程序流程结构
C/C++支持最基本的三种程序运行结构:顺序结构、选择结构、循环结构
- 顺序结构:程序按顺序执行,不发生跳转
- 选择结构:依据条件是否满足,有选择的执行相应功能
- 循环结构:依据条件是否满足,循环多次执行某段代码
4.1、选择结构 4.1.1、if语句
作用:执行满足条件的语句
if语句的三种形式
- 单行格式if语句
- 多行格式if语句
- 多条件的if语句
1、单行格式if语句:if(条件){条件满足执行的语句}
示例1:单行格式if语句
#includeusing namespace std; int main() { //选择结构 单行if语句 //用户输入分数,如果分数大于600,视为考上一本大学,在屏幕上输出 //1、用户输入分数 int score = 0; cout << "请输入一个分数:" << endl; cin >> score; //2、打印用户输入的分数 cout << "请输入的分数为" << score << endl; //3、判断分数是否大于600,如果大于,输出 if (score > 600) { cout << "恭喜你考上了一本大学" << endl; } system("pause"); return 0; }
2、多行格式if语句:if(条件){条件满足执行的语句}else{条件不满足执行的语句}
示例2:多行格式if语句
3、多条件if语句:if(条件1){条件1满足执行的语句}else if(条件2){条件2满足执行的语句}...else{都不满足}
示例3:多条件if语句
4、嵌套if语句:在if语句中,可以嵌套使用if语句,达到更精确的条件判断
案例需求:
- 提示用户输入一个高考考试分数,根据分数做出如下判断
- 分数如果大于600分视为考上一本,大于500分考上二本,大于400考上三本,其余视为未考上本科
- 在一本分数中,如果大于700分,考入北大;大于650,考入清华;大于600考入人大
第五章、数组 5.1、概述
所谓数组,就是一个集合,里面存放了相同类型的数据元素。
特点1:数组中的每个数据元素都是相同的数据类型
特点2:数组是由连续的内存位置组成的
5.2、一维数组 5.2.1、一维数组的定义方式
要创建数组,可使用声明语句。数组声明应指出以下三点:
- 存储在每个元素中的值的类型
- 数组名
- 数组中的元素数
一维数组定义的三种方式:
1、数据类型 数组名 [数组长度];
2、数据类型 数组名 [数组长度] = {值1,值2...};
3、数据类型 数组名[] = {值1,值2...};
【注:让编译器去做;通常,像第三种定义方式那样,让编译器计算元素个数是一种很糟糕的做法,因为其计数可能和我们自己想的不太一样。】
数组的特点:
- 放在一块连续的内存空间中
- 数组中每个元素都是相同的数据类型
数组的索引:
数组的用途都是基于这样一个事实:可以单独访问数组元素。方法是使用下标或索引来对元素进行编号。C++的数组从0开始编号,这没有商量的余地。即arr[0]。
有效下标值的重要性:
编译器不会检查使用的下标是否有效。例如,如果将一个值赋给不存在的元素,如
int arr[10] = {1,2,3,4,5,6,7,8,9,10} cout<
那么编译器是不会指出错误的。
但是在程序运行后,这种赋值可能引发问题,它可能破坏数据或代码,也可能导致程序异常终止,所以必须确保程序只使用有效的下标值。
示例:
#includeusing namespace std; int main() { //1、数据类型 数组名[数组长度] //int arr[5]; //给数组中的元素进行赋值 //数组元素的下标是从0开始索引的 //访问数据元素 //2、数据类型 数组名[数组长度] = {值1,值2...} //如果在初始化数据的时候,没有把数据全部初始化,那么没有初始化的值初始值为0 int arr2[5] = { 10,20,30,40,50 }; for (int i = 0; i < 5; i++) { cout << arr2[i] << endl; } //3、数据类型 数组名[] = { 值1,值2... }; int arr3[] = { 100,90,80,70,60,50,40,30,20,10 }; for (int i = 0; i < 10; i++) { cout << arr3[i] << endl; } system("pause"); return 0; }
【总结1:数组名的命名规范与变量名命名规范一致,不要和变量重名】
【总结2:数组中下标是从0开始索引】
5.2.2、一维数组数组名
一维数组名称的用途:
- 可以统计整个数组在内存中的长度sizeof(arr)
- 可以获取数组在内存中的首地址cout<
示例:
#includeusing namespace std; int main() { //数组名用途 //1、可以通过数组名统计整个数组占有的内存大小 int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; cout << "整个数组名的占用空间为:" << sizeof(arr) << endl; cout << "每个元素占用内存空间为:" << sizeof(arr[0]) << endl; cout << "数组中元素的个数为:" << sizeof(arr) / sizeof(arr[0]) << endl; //2、可以通过数组名查看数组首地址 cout << "数组首地址为:" << (int)arr << endl; cout << "数组中第一个元素地址为:" << (int)&arr[0] << endl; cout << "数组中第二个元素地址为:" << (int)&arr[1] << endl; //数组名是常量不可以进行赋值操作 //arr = 10; system("pause"); return 0; }
【注:其实arr一般说的就是&arr[0],即你指一个数组,一般就是指数组的头元素的地址】
5.2.3、练习案例1:五只小猪称体重
案例描述:
在一个数组中记录了五只小猪的体重,如int arr[5] = {300,350,200,400,250},找出并打印最重的小猪体重。
核心思想:
示例:
#includeusing namespace std; int main() { int arr[5] = { 300,350,200,400,250 }; int max = 0; int test = 0; for (int i = 0; i < 5; i++) { test = arr[i]; if (max < test) { max = test; } } cout << "五只小猪里最重的小猪体重为:" << max << endl; system("pause"); return 0; }
5.2.4、练习案例2:元素逆置
案例描述:
请声明一个5元素的数组,并且将元素逆置。(如原数组元素为:1,3,2,5,4;逆置后输出结果为:4,5,2,3,1)
核心思想:
示例:
#includeusing namespace std; int main() { //1、创建数组前 int arr[5] = { 1,3,2,5,4 }; int start = 0; int end = sizeof(arr) / sizeof(arr[0]) - 1; cout << "逆置前的数组为:" << endl; for (int i = 0; i < 5; i++) { cout << arr[i] << endl; } //创建中间变量放元素 int temp = 0; //实现逆置 while (start
5.2.5、冒泡排序作用:最常用的排序算法,对数组内元素进行排序
- 比较相邻的元素,如果第一个比第二个大,就交换他们两个
- 对每一对相邻元素做同样的工作,执行完毕后,找到一个最大值
- 重复以上的步骤,每次比较次数-1,直到不需要比较
核心思想:
示例:将数组{4,2,8,0,5,7,1,3,9}进行升序排序
#includeusing 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; //开始冒泡排序 //总共排序轮数为 元素个数-1 for (int i = 0; i < 9 - 1; i++) { //内层循环对比 for (int j = 0; i < 9 - i - 1; 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; }
5.3、二维数组二维数组就是在一维数组上,添加一个维度。
5.3.1、二维数组的定义方式二维数组定义的四种方式:
- 数据类型 数组名[行数][列数];
- 数据类型 数组名[行数][列数] = {数据1,数据2},{数据3,数据4};
- 数据类型 数组名[行数][列数] = {数据1,数据2,数据3,数据4};
- 数据类型 数组名[][列数] = {数据1,数据2,数据3,数据4}
【建议:以上4种定义方式,利用第二种更加直观,提高代码的可读性。】
示例:
#includeusing 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] << " "; } cout << 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 << arr3[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 << arr4[i][j] << " "; } cout << endl; } system("pause"); return 0; }
5.3.2、二维数组的数组名
- 查看二维数组所占内存的空间
- 获取二维数组的首地址
示例:
#includeusing namespace std; int main() { //1、查看占用内存空间大小 int arr[2][3] = { {1,2,3} ,{4,5,6} }; cout << "二维数组占用的内存空间为:" << sizeof(arr) << endl; cout << "二维数组第一行占用空间为:" << sizeof(arr[0]) << endl; cout << "二维数组第一个元素占用内存为:" << sizeof(arr[0][0]) << endl; //通过上面几条代码可以统计二维数组的行数和列数 cout << "二维数组的行数为:" << sizeof(arr) / sizeof(arr[0]) << endl; cout << "二维数组的列数为:" << sizeof(arr[0]) / sizeof(arr[0][0]) << endl; //2、获取二维数组的首地址 cout << "二维数组的首地址:" << (int)arr << endl; cout << "二维数组第一行首地址为:" << (int)arr[0] << endl; cout << "二维数组第二行首地址为:" << (int)arr[1] << endl; cout << "二维数组第一个元素的首地址为:" << (int)&arr[0][0] << endl; cout << "二维数组第二个元素的首地址为:" << (int)&arr[0][1] << endl; system("pause"); return 0; }
5.3.3、二维数组应用案例考试成绩统计
案例描述:有三名同学(张三,李四,王五),在一次考试中的成绩分别如下表,请分别输出三名同学的总成绩。
张三100100100 李四9050100 王五607080 示例:
#include#include using namespace std; int main() { //二维数组案例-考试成绩案例 //1、创建二维数组 int scores[3][3] = { {100,100,100}, {90,50,100}, {60,70,80} }; string students[3] = { "张三","李四","王五" }; //2、统计每个人的总和分数 for (int i = 0; i < 3; i++) { int sum = 0;//统计每个人的分数总和 for (int j = 0; j < 3; j++) { sum += scores[i][j]; } cout << students[i]<<"的总分为:"<
第六章、函数 6.1、概述作用:将一段经常使用的代码封装起来,减少重复代码。
一个较大的程序,一般分为若干个程序块,每个模块实现特定的功能。
乐趣
C++自带了一个包含函数的大型库(标准的ANSI库加上多个C++类),但真正的乐趣在于编写自己的函数,另外,如果要提升效率,可更深入学习STL和BOOST C++提供的功能。
6.2、函数的定义函数的定义一般主要有5个步骤:
- 返回值类型:一个函数可以返回一个值
- 函数名:给函数起个名称
- 参数表列:使用该函数时,传入的数据
- 函数体语句:花括号内的代码,函数内需要执行的语句
- return表达式:和返回值类型挂钩,函数执行完后,返回相应的数据
语法:
返回值类型 函数名 () { 函数体语句 return 表达式 }例如加法函数:
关于return
对于有返回值的函数,必须使用return语句,以便将值返回给调用函数。值本身可以是常量、变量,也可以是表达式,只是其结果必须为typeName类型或可以被转换为typeName(例如:在声明的时候就说返回double,结果最后return的是一个int,那么这个int将会被强转为double)。然后函数就会把值返回给调用函数。
C++对返回值的类型有一定的限制,不能是数组,但是可以是其他任何类型,比如整数浮点数甚至是结构和对象。
示例:定义一个加法函数,实现两个数相加
#includeusing namespace std; int add(int x,int y) { int c = x + y; return c; } int main() { int a = 1; int b = 2; int result = add(a, b); cout << "a和b加起来为:" << result << endl; system("pause"); return 0; }
6.3、函数的调用功能:使用定义好的函数
语法:函数名 (参数)
示例:
#includeusing namespace std; //函数定义 int add(int num1, int num2)//定义中的num1,num2称为形式参数,简称形参 { int sum = num1 + num2; return sum; } int main() { int a = 10; int b = 10; //调用add函数 //a和b称为实际参数,简称实参 int sum = add(a, b); cout << "sum = " << sum << endl; int sum2 = add(100, 500); cout << "sum2 = " << sum2 << endl; system("pause"); return 0; }
6.4、值传递所谓值传递,就是函数调用时实参将数值传入给形参
值传递时,如果形参发生改变,并不会影响实参。
示例:
#includeusing 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; 返回值不需要的时候,可以不写return } int main() { 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; }
值传递的原理:
【总结:值传递时,形参是修饰不了实参的。】
6.5、函数的常见形式常见的函数样式有4种
- 无参无反
- 有参无反
- 无参有反
- 有参有反
示例:
#includeusing namespace std; //函数常见形式 //1、无参无反 void test01() { cout << "this is test01" << endl; } //2、有参无返 void test02(int a) { cout << "this is test02 a = " << a << endl; } //3、无参有反 int test03() { cout << "this is test03" << endl; return 1000; } //4、有参有反 int test04(int a) { cout << "this is test04 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; }
6.6、函数的声明作用:告诉编译器函数名称以及如何调用函数,函数的实际主体可以单独定义。
- 函数的声明可以多次,但是函数的定义只能有一次
示例:
#includeusing namespace std; //函数的声明 //比较函数,实现两个整型数字进行比较,返回较大的值 //提前告诉编译器函数的存在,可以利用函数的声明 //函数的声明 //声明可以写多次,但是定义只能写一次 int max(int a, int b); int main() { int a = 10; int b = 20; cout << max(a, b) << endl; system("pause"); return 0; } //定义 int max(int a, int b) { return a > b ? a : b; }
6.7、函数的分文件编写作用:让代码结构更加清晰
函数分文件编写一般有4个步骤
- 创建后缀名为.h的头文件
- 创建后缀名为.cpp的源文件
- 在头文件中写函数的声明
- 在源文件中写函数的定义
示例:
#include "swapfunc.h" using namespace std; //函数的定义 void swapfunc(int a, int b) { int temp = a; a = b; b = temp; cout << "a = " << a << endl; cout << "b = " << b << endl; }#pragma once #includevoid swapfunc(int a, int b); #include#include "swapfunc.h" using namespace std; int main() { int a = 10; int b = 20; swapfunc(a, b); system("pause"); return 0; }
第七章、指针 7.1、指针的基本概念指针的作用:可以通过指针间接访问内存
- 内存编号是0开始记录的,一般用十六进制数字表示
- 可以利用指针变量保存地址
7.2、指针变量的定义和使用指针变量定义语法:数据类型 * 变量名;
示例:
#includeusing namespace std; int main() { //1、定义指针 int a = 10; //指针定义的语法:数据类型*指针变量名 int* p = &a; cout << "a的地址为:" << &a << endl; cout << "指针p为:" << p << endl; //2、使用指针 //可以通过解引用的方式来找到指针指向的内存 //指针前面加*代表解引用,找到指针指向的内存中的数据 *p = 1000; cout << "a = " << a << endl; cout << "*p = " << *p << endl; system("pause"); return 0; }
7.3、指针所占内存空间指针也是数据类型,那么这种数据类型占用多少内存呢?
示例:
#includeusing namespace std; int main() { //指针所占内存空间 int a = 10; int* p = &a; //在32位 *** 作系统下,指针是占4个字节空间大小,不管是什么数据类型 //在64位 *** 作系统下,指针是占8个字节空间大小 cout << "sizeof(int *) = " << sizeof(int*) << endl; system("pause"); return 0; }
7.4、空指针空指针:指针变量指向内存中编号为0的空间
用途:初始化指针变量
注意:空指针指向的内存是不可以访问的
示例:
#includeusing namespace std; int main() { //空指针 //1、控制怎用于给指针变量进行初始化 int* p = NULL; //2、空指针是不可以进行访问的 //0~255之间的内存编号是系统占用的,不可以进行访问 //*p = 100; system("pause"); return 0; }
7.5、野指针野指针:指针变量指向非法的内存空间
示例:野指针
#includeusing namespace std; int main() { //野指针 int* p = (int*)0x1100; cout << *p << endl; system("pause"); return 0; } 【总结:空指针和野指针都不是我们申请的空间,因此不要访问。】
7.6、const修饰指针const修饰指针有三种情况:
- const修饰指针——常量指针
- const修饰常量——指针常量
- const既修饰指针又修饰常量
上面显有点绕,我来总结一下。
如果是const int * p,我们假设const int * p = a,我们可以改写成int * p = const a(这是说明逻辑而已,实际上不能这么改写),那么说明整个指针值都被const修饰了,所以整个指针值都是常量,我们叫做常量指针,在这种情况下,指针只能是常量,也就是说,指针的性质被保留了,还是可以随便指,那是指的内容他必须保证是一个常量,不能随便修改。
而如果是int * const p,那么说明只有变量名被const修饰了,所以只有这个变量变成了常量,也就是说这个指针变量变成指针常量了,那么指针就不能随便改了,而内容可以随便改因为没有限制。
如果综上所述,那么const int * const p就是即修饰指针又修饰常量,那么指针的指向不能该,指针指的内容也不能改了。
示例:
#includeusing namespace std; int main() { //1、常量指针 int a = 10; int b = 10; const int* p = &a; //指针指向的值不可以改,但是指向可以改 //*p = 20;错误 p = &b;//正确 //2、const修饰常量 int* const p2 = &a; *p2 = 100; //p2 = &b;错误,指针的指向不可以改 //3、const修饰指针和常量 const int* const p3 = &a; //p3 = &b;错误 //*p3 = 100;错误 system("pause"); return 0; }
7.7、指针和数组作用:利用指针访问数组中元素
示例:
#includeusing namespace std; int main() { //指针和数组 //利用指针访问数组中的元素 int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; cout << "第一个元素为:" << arr[0] << endl; int* p = arr;//arr就是数组的首地址 cout << "利用指针访问第一个元素:" << *p << endl; p++;//让指针向后偏移4个字节 cout << "利用指针访问第二个元素:" << *p << endl; system("pause"); return 0; }
7.8、指针和函数作用:利用指针作为函数参数,可以修改实参的值
原理:
示例:
#includeusing namespace std; //值传递交换函数 void swap01(int a, int b) { int temp = a; a = b; b = temp; cout << "swap01 a = " << a << endl; cout << "swap01 b = " << b << endl; } void swappoint(int *p1, int *p2) { int temp1 = *p1; *p1 = *p2; *p2 = temp1; cout << "swappoint *p1= " << *p1 << endl; cout << "swappoint *p2= " << *p2 << endl; } int main() { //指针和函数 //1、值传递 int a = 10; int b = 20; swap01(a, b); cout << "a = " << a << endl; cout << "b = " << b << endl; //分界线 cout << "------------" << endl; //2、地址传递 int* p1 = &a; int* p2 = &b; swappoint(&a, &b); cout << "a = " << a << endl; cout << "b = " << b << endl; system("pause"); return 0; }
7.9、指针配合数组和函数案例案例描述:封装一个函数,利用冒泡排序,实现对整型数组的升序排序
例如数组:int arr[10] = {4,3,6,9,1,2,10,8,7,5}
示例:
第八章、结构体 8.1、结构体基本概念结构体属于用户自定义的数据类型,他允许用户存储不同的数据类型
8.2、结构体定义和使用语法:struct 结构体名 {结构体成员列表}
通过结构体创建变量的方式有三种:
- struct 结构体名 变量名
- struct 结构体名 变量名 = {成员1,成员2...}
- 定义结构体时顺便创建变量
示例:
#includeusing namespace std; #include //1、创建学生数据类型:学生包括(姓名,年龄,分数) //自定义数据类型,一些类型集合组成的一个类型 struct Student { //成员列表 string name; int age; int score; }s3; //2、通过学生类型创建具体学生 int main() { //2.1 struct Student s1 //定义不可以省略struct,但是声明可以省略 struct Student s1; //给s1属性赋值,通过.访问结构体变量中的属性 s1.name = "张三"; s1.age = 18; s1.score = 100; cout << "姓名:" << s1.name << "年龄:" << s1.age << "分数:" << s1.score << endl; //2.2 struct Student s2 = {...} struct Student s2 = { "李四",25,99 }; cout << "姓名:" << s2.name << "年龄:" << s2.age << "分数:" << s2.score << endl; //2.3 在定义结构体时顺便创建结构体变量 s3.name = "王五"; s3.age = 19; s3.score = 97; cout << "姓名:" << s3.name << "年龄:" << s3.age << "分数:" << s3.score << endl; }
8.3、结构体数组作用:将自定义的结构放入数组中方便维护
语法:struct 结构体名 数组名[元素个数] = {{},{}...}
示例:
#include#include using namespace std; //结构体数组 //1、定义结构体 struct Student { //姓名 string name; //年龄 int age; //分数 int score; }; int main() { //2、创建结构体数组 struct Student stuArray[8] = { {"张三",18,100}, {"李四",28,99}, {"王五",38,66} }; //3、给结构体数组中的元素赋值 stuArray[2].name = "赵六"; stuArray[2].age = 80; stuArray[2].score = 60; //4、遍历结构体数组 for (int i = 0; i < 3;i++) { cout << "姓名: " << stuArray[i].name << "年龄:" << stuArray[i].age << "分数: " << stuArray[i].score << endl; } }
8.4、结构体指针作用:通过指针访问结构体中的成员
- 利用 *** 作符->可以通过结构体指针访问结构体属性
示例:
#include#include using namespace std; //结构体指针 struct student { string name;//姓名 int age;//年龄 int score;//学生 }; int main() { //1、创建学生的结构体变量 student s = { "张三",18,100 }; //2、通过指针指向结构体变量 student* p = &s; //3、通过指针访问结构体变量中的数据 //通过结构体指针 访问结构体中的属性,需要利用'->' cout << "姓名:" << p->name << "年龄:" << p->age << "分数:" << p->score << endl; system("pause"); return 0; }
8.5、结构体嵌套结构体作用:结构体中的成员可以是另一个结构体
例如:每个老师辅导一个学员,一个老师的结构体中,记录一个学生的结构体
原理:
示例:
#includeusing namespace std; #include //定义学生结构体 struct student { string name; int age; int score; }; //定义老师结构体 struct teacher { int id; string name; int age; struct student stu; }; int main() { //结构体嵌套结构体 //创建老师 teacher t; t.id = 10000; t.name = "老王"; t.age = 50; t.stu.name = "小王"; t.stu.age = 20; t.stu.score = 60; cout << "老师姓名:" << t.name << "老师编号:" << t.id << "老师年龄:" << t.age << "老师辅导的学生姓名:" << t.stu.name << "学生年龄:" << t.stu.age << "学生分数:" << t.stu.score<
8.6、结构体做函数参数作用:将结构体作为参数像函数中传递
传递方式有两种:
- 值传递
- 地址传递
示例:
#includeusing namespace std; //定义学生结构体 struct student { string name; int age; int score; }; //打印学生信息函数 //1、值传递 void printStudent1(struct student s) { s.age = 10; s.score = 0; cout << "子函数中 姓名:" << s.name << "年龄:" << s.age << "分数:" << s.score << endl; } void printStudent2(struct student *p) { p->age = 10; p->score = 0; cout << "子函数2中 姓名:" << p->name << "年龄:" << p->age << "分数:" << p->score << endl; } int main() { //结构体做函数参数 //将学生传入到一个参数中,打印学生身上的所有信息 //创建结构体变量 struct student s; s.name = "张三"; s.age = 20; s.score = 85; printStudent1(s); cout << "实参name:" << s.name << endl; cout << "实参age:" << s.age << endl; cout << "实参score:" << s.score << endl; cout << "--------------" << endl; printStudent2(&s); cout << "实参name:" << s.name << endl; cout << "实参age:" << s.age << endl; cout << "实参score:" << s.score << endl; } 【总结:如果不想修改主函数中的数据,用值传递,反之用地址传递。】
8.7、结构体中const使用场景作用:用const来防止误 *** 作
示例:
#include#include using namespace std; //const的使用场景 struct student { string name; int age; int score; }; //将函数中的形参改为指针,可以减少内存空间,而且不会赋值新的副本出来 void printStudents(const student *s) { //s->age = 150;假如const之后,一旦有修改的 *** 作就会报错,可以防止我们的误 *** 作,其作用相当于java的final cout << "姓名:" << s->name << "年龄:" << s->age << "分数:" << s->score << endl; } int main() { //创建结构体变量 struct student s = { "张三",15,70 }; //通过函数打印结构体变量信息 printStudents(&s); }
8.8、结构体案例 8.8.1、案例一案例描述:
学校正在做毕设项目,每名老师带领5个学生,总共有三名老师,需求如下:
设计学生和老师的结构体,其中在老师的结构体中,有老师姓名和一个存放5名学生的数组作为成员
学生的成员有姓名、考试分数,创建数组存放三名老师,通过函数给每个老师及所带的学生赋值
最终打印出老师数据以及老师所带的学生数据。
示例:
8.8.2、案例二案例描述:设计一个英雄的结构体,包括成员姓名,年龄,性别:创建结构体数组,数组中存放5名英雄。通过冒泡排序的算法,将数组中的英雄按照年龄进行升序排序,最终打印排序后的结果。
示例:
大作业:通讯录管理系统
第九章、C++核心编程本阶段主要针对C++面向对象编程技术做详细讲解,探讨C++中的核心和精髓。
9.1、内存分区模型C++程序在执行时,将内存大方向划分为4个区域
代码区:存放函数体的二进制代码,由 *** 作系统进行管理的
全局区:存放全局变量和静态变量以及常量
栈区:由编译器自动分配释放,存放函数的参数值,局部变量等
堆区:由程序员分配和释放,若程序员不释放,程序结束时由 *** 作系统回收
内存四区意义:
不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程。
9.1.1、程序运行前在程序编译前,生成了exe可执行程序,未执行该程序前分为两个区域
代码区:
- 存放CPU执行的机器指令
- 代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可
- 代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令
全局区:
- 全局变量和静态变量存放在此
- 全局区还包含了常量区,字符串常量和其他常量也存放于此
- 该区域的数据在程序结束后由 *** 作系统释放
示例:
#includeusing namespace std; //全局变量 int g_a = 10; int g_b = 20; const int c_g_a = 10; const int c_g_b = 20; int main() { //创建局部变量 int a = 10; int b = 10; cout << "局部变量a的地址为:" << (int)&a << endl; cout << "局部变量b的地址为:" << (int)&b << endl; cout << "全局变量g_a的地址为:" << (int)&g_a << endl; cout << "全局变量g_a的地址为:" << (int)&g_a << endl; //静态变量 static int s_a = 10; static int s_b = 20; cout << "静态变量s_a的地址为:" << (int)&a << endl; cout << "静态变量s_b的地址为:" << (int)&b << endl; //常量 //字符串常量 cout << "字符串常量的地址为:" << (int)&"hello world" << endl; //const修饰的变量 //const修饰的全局变量,const修饰的局部变量 cout << "全局常量c_g_a的地址为:" << (int)&c_g_a << endl; cout << "全局常量c_g_b的地址为:" << (int)&c_g_b << endl; const int c_l_a = 10; const int c_l_b = 10; cout << "全局常量c_l_a的地址为:" << (int)&c_l_a << endl; cout << "全局常量c_l_b的地址为:" << (int)&c_l_b << endl; system("pause"); return 0; }
9.1.2、程序运行后栈区:
由编译器自动分配释放,存放函数的参数值,局部变量等
【注:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放】
示例:
#includeusing namespace std; int* func(int b)//形参数据也会放在栈区 { b = 100; int a = 10;//局部变量 存放在栈区,栈区的数据在函数执行完后自动释放 return &a; //返回局部变量的地址 } int main() { //接受func函数的返回值 int* p = func(1); cout << *p << endl;//第一次可以打印正确的数据,是因为编译器做了保留 cout << *p << endl;//第二次乱码 system("pause"); return 0; }
堆区:
由程序员分配释放,若程序员不释放,程序结束时由 *** 作系统回收
在C++中利用new在堆区开辟内存
#includeusing namespace std; int* func() { //利用new关键字 可以将数据开辟到堆区 //指针 本质也是局部变量,放在栈上,指针保存的数据是放在堆区 int* p = new int(10); return p; } int main() { //在堆区开辟数据 int* p = func(); cout << *p << endl; system("pause"); return 0; } 总结:
堆区数据由程序员管理开辟和释放
堆区数据利用new关键字进行开辟内存
9.1.3、new *** 作符C++中利用new *** 作符在堆区开辟数据
堆区开辟的数据,由程序员手动开辟,手动释放,释放利用 *** 作符delete
语法:new 数据类型
利用new创建的数据,会返回该数据对应的类型的指针
示例1:基本语法
#includeusing namespace std; //1、new的基本语法 int* func() { //在堆区创建整型数据 //new 返回的是该数据类型的指针 int * p = new int(10); return p; } void test01() { int* p = func(); cout << *p << endl; //堆区的数据 有程序员管理开辟,程序员管理释放 //如果想要释放,利用关键字delete delete p; cout << *p << endl;//内存已经被释放,再次访问就是非法操作,会报错 } //2、在堆区利用new开辟数组 void test02() { //创建10整型数据的数组,在堆区 int * arr = new int[10];//代表数组有十个元素 for (int i = 0; i < 10; i++) { arr[i] = i + 100;//给10个元素赋值 } for (int i = 0; i < 10; i++) { cout << arr[i] << endl; } //释放堆区数组 //释放数组的时候 要加[]才可以 delete[] arr; } int main() { test01(); }
9.2、引用 9.2.1、引用的基本使用作用:给变量起别名
语法:数据类型 &别名 = 原名
原理:示例:
#includeusing namespace std; int main() { //引用基本语法 //数据类型 &别名 = 原名 int a = 10; int& b = a; cout << "a = " << a << endl; cout << "b = " << b << endl; b = 100; cout << "a = " << a << endl; cout << "b = " << b << endl; system("pause"); return 0; }
9.2.2、引用的注意事项
- 引用必须初始化
- 引用在初始化后,不可以改变
示例:
#includeusing namespace std; int main() { int a = 10; //1、引用必须初始化 //int &b;//错误,必须要初始化 int& b = a; //2、引用在初始化后,不可以改变 int c = 20; b = c;//赋值 *** 作,而不是更改引用 cout << "a = " << a << endl; cout << "b = " << b << endl; cout << "c = " << c << endl; system("pause"); return 0; }
9.2.3、引用做函数的返回值作用:引用是可以作为函数的返回值存在的
注意:不要返回局部变量引用
用法:函数调用作为左值
示例:
#includeusing namespace std; //引用做函数的返回值 //1、不要返回局部变量的引用 int& test01() { int a = 10; return a; } //2、函数的调用可以作为左值 int& test02() { static int a = 10;//静态变量,存放在全局区,全局区上的数据在程序结束后系统释放 return a; } int main() { int& ref = test01(); cout << "ref = " << ref << endl;//第一次结果正确,是因为编译器做了保留 cout << "ref = " << ref << endl; test02() = 1000;//如果函数的返回值是引用,这个函数的调用可以作为左值 int& ref2 = test02(); cout << "ref2 = " << ref2 << endl; cout << "ref2 = " << ref2 << endl; system("pause"); return 0; }
9.2.4、引用的本质本质:引用的本质是C++内部实现一个指针常量
示例:
//发现是引用,转换为int* const ref = &a; void func(int& ref){ ref = 100;//ref是引用,转换为*ref = 100 } int main() { int a = 10; //自动转换为int* const ref = &a;指针常量时指针指向不可改,也说明为什么引用不可改 int& ref = a; ref = 20;//内部发现ref是引用,自动帮我们转换为:*ref =20; cout<<"a: "<< a <【结论:C++推荐引用技术,因为语法方便,引用本质是指针常量,但是所有的指针 *** 作编译器都帮我们做了。】
9.2.5、常量引用作用:常量引用主要用来修饰对象,防止误 *** 作
在函数形参列表中,可以加const修饰形参,防止形参改变实参
示例:
#includeusing namespace std; //打印数据函数 void showValue(const int& val) { //val = 1000; cout << "val = " << val << endl; } int main() { //常量引用 //使用场景:用来修饰形参,防止误操作(即改动形参数据) //int a = 10; //加上const之后,编译器将代码修改 int temp = 10;const int & ref = temp; //const int & ref = 10;//引用必须引一块合法的内存空间 //ref = 20;//假如const之后变为可读,不可以修改 int a = 100; showValue(a); }
9.3、函数提高 9.3.1、函数默认参数在C++中,函数的形参列表中的形参是可以有默认值的。
语法:返回值类型 函数名 (参数 = 默认值){}
示例:
#includeusing namespace std; //函数默认参数 int func(int a, int b = 20, int c = 30) { return a + b + c; } //注意事项 //1、如果某个位置已经有了默认参数,那么从这个位置往后,从左到右都需要有默认值 int func2(int a, int b, int c, int d = 10) { return a + b + c + d; } //2、如果函数声明有默认参数,函数实现就不能有默认参数 int func(int a = 10, int b = 10); //如果在函数声明设置默认值,又在定义设置了默认值,就会造成代码二义性 int func3(int a = 10, int b = 10) { return a + b; } int main() { //如果我传值了,他就用我的,如果我没传,他就用默认的 cout << func(10,30) << endl; system("pause"); return 0; }
9.3.2、函数占位参数C++中函数的形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置
语法:返回值类型 函数名 (数据类型){}
在现阶段函数的占位参数存在意义不大,但是在后面的课程中会用到该技术
示例:
#includeusing namespace std; //占位参数 //占位参数 还可以有默认参数 void func(int a, int = 10) { cout << "this is func" << endl; } int main() { func(10, 10); system("pause"); return 0; }
9.3.3、函数重载概述作用:函数名可以相同,提高复用性
函数重载满足条件:
- 同一个作用域下
- 函数名称相同
- 函数参数类型不同或者个数不同或者顺序不同
注意:函数的返回值不可以作为函数重载的条件
示例:
//2、引用在初始化后,不可以改变 int c = 20; b = c;//赋值 *** 作,而不是更改引用 cout << "a = " << a << endl; cout << "b = " << b << endl; cout << "c = " << c << endl; system("pause"); return 0;}
--- #### 9.2.3、引用做函数的返回值 **作用**:引用是可以作为函数的返回值存在的 **注意**:不要返回局部变量引用 **用法**:函数调用作为左值 **示例**: ```c++ #includeusing namespace std; //引用做函数的返回值 //1、不要返回局部变量的引用 int& test01() { int a = 10; return a; } //2、函数的调用可以作为左值 int& test02() { static int a = 10;//静态变量,存放在全局区,全局区上的数据在程序结束后系统释放 return a; } int main() { int& ref = test01(); cout << "ref = " << ref << endl;//第一次结果正确,是因为编译器做了保留 cout << "ref = " << ref << endl; test02() = 1000;//如果函数的返回值是引用,这个函数的调用可以作为左值 int& ref2 = test02(); cout << "ref2 = " << ref2 << endl; cout << "ref2 = " << ref2 << endl; system("pause"); return 0; }
9.2.4、引用的本质本质:引用的本质是C++内部实现一个指针常量
示例:
//发现是引用,转换为int* const ref = &a; void func(int& ref){ ref = 100;//ref是引用,转换为*ref = 100 } int main() { int a = 10; //自动转换为int* const ref = &a;指针常量时指针指向不可改,也说明为什么引用不可改 int& ref = a; ref = 20;//内部发现ref是引用,自动帮我们转换为:*ref =20; cout<<"a: "<< a <【结论:C++推荐引用技术,因为语法方便,引用本质是指针常量,但是所有的指针 *** 作编译器都帮我们做了。】
9.2.5、常量引用作用:常量引用主要用来修饰对象,防止误 *** 作
在函数形参列表中,可以加const修饰形参,防止形参改变实参
示例:
#includeusing namespace std; //打印数据函数 void showValue(const int& val) { //val = 1000; cout << "val = " << val << endl; } int main() { //常量引用 //使用场景:用来修饰形参,防止误操作(即改动形参数据) //int a = 10; //加上const之后,编译器将代码修改 int temp = 10;const int & ref = temp; //const int & ref = 10;//引用必须引一块合法的内存空间 //ref = 20;//假如const之后变为可读,不可以修改 int a = 100; showValue(a); }
9.3、函数提高 9.3.1、函数默认参数在C++中,函数的形参列表中的形参是可以有默认值的。
语法:返回值类型 函数名 (参数 = 默认值){}
示例:
#includeusing namespace std; //函数默认参数 int func(int a, int b = 20, int c = 30) { return a + b + c; } //注意事项 //1、如果某个位置已经有了默认参数,那么从这个位置往后,从左到右都需要有默认值 int func2(int a, int b, int c, int d = 10) { return a + b + c + d; } //2、如果函数声明有默认参数,函数实现就不能有默认参数 int func(int a = 10, int b = 10); //如果在函数声明设置默认值,又在定义设置了默认值,就会造成代码二义性 int func3(int a = 10, int b = 10) { return a + b; } int main() { //如果我传值了,他就用我的,如果我没传,他就用默认的 cout << func(10,30) << endl; system("pause"); return 0; }
9.3.2、函数占位参数C++中函数的形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置
语法:返回值类型 函数名 (数据类型){}
在现阶段函数的占位参数存在意义不大,但是在后面的课程中会用到该技术
示例:
#includeusing namespace std; //占位参数 //占位参数 还可以有默认参数 void func(int a, int = 10) { cout << "this is func" << endl; } int main() { func(10, 10); system("pause"); return 0; }
9.3.3、函数重载概述作用:函数名可以相同,提高复用性
函数重载满足条件:
- 同一个作用域下
- 函数名称相同
- 函数参数类型不同或者个数不同或者顺序不同
注意:函数的返回值不可以作为函数重载的条件
示例:
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)