从今天起开始C++的学习,为以后学习QT、OpenCV铺路。
本篇是C++教程中C部分的总集,为本专栏里所有 1.x部分的集合,嫌一篇篇看麻烦的直接看本篇好了。
开发环境搭建:Visual Studio 2019 C++开发环境搭建
推荐教程视频:https://www.bilibili.com/video/BV1et411b73Z?from=search&seid=4205594350351753444
已投币三连,非常好的视频教程,感谢up主的奉献。
一、代码的注释
代码注释常用于标注代码功能、记录作者和版本修改信息,方便阅读查看。
// 单行注释
/* ...
...
多行注释
...
...
*/
#include <iostream>
using namespace std;
/*
多行注释
main 主函数
*/
int main() {
cout << "Hello World!!" << endl; // 单行注释,打印输出Hello world!!
system("pause");
return 0;
}
cout:c out,打印输出,相当于 printf。
cin:c in,检测输入,相当于 scanf。
endl:end line,换行结束,相当于键盘敲回车。
system("pause");:让程序暂停,按任意键继续。
二、变量
变量,字面意思,可以被改变的数据。而实际是给计算机的一段内存空间起名,方便操作这段内存的数据。
变量如果需要被使用,需要先声明变量。声明变量的格式:
数据类型 变量名 = 初始值;
#include <iostream>
using namespace std;
int main() {
int i = 100;
cout << "Hello World!!" << endl;
cout << "i = " << i << endl;
system("pause");
return 0;
}
三、常量
可以被修改的数据叫做变量,不可被修改的数据叫常量。
C++定义常量有两种方法:
(1)#define宏常量:#define 常量名 常量值
通常在代码文件的上方声明。
#define 常量名 常量值
#define Year 2020
#define Name "XiaoMing"
(2)const修饰变量:const 数据类型 常量名 = 常量值
const 数据类型 常量名 = 常量值
const int year = 2020;
常量被修改,编译器会报错。
四、关键字
是C++中预先保留的单词(标识符)。
注意:给变量或者常量起名称时,不要和关键字重复,会有语法歧义。
五、标识符(变量、常量)命名规则
(1)标识符不能是关键字
(2)标识符只能由 数字、字母、下划线 组成。
(3)标识符的第一个字符必须是 字母或者下划线。
(4)标识符中字母区分大小写
可以是 inta,但不能是 int。
year2020、Status、_a、Student_66 这些都符合命名规则,但 2class、618_Day 这样以 数字开头的不行。
Age 和 age 代表的变量并不是同一个,是两个独立且互不相关的变量。
标识符命名尽量简介直观,方便自己和他人阅读。
六、数据类型
(1)整形
整型数据类型的区别,主要是占用空间的不同,从而导致取值范围不同,有大有小。
int最为常用。
数据类型 | 占用空间 | 取值范围 |
short(短整型) | 2个字节(Byte) | (-2^15 ~ 2^15-1) |
int(整形) | 四个字节 | (-2^31 ~ 2^31-1) |
long(长整型) | windows为4个字节、32位linux为4个字节、64位linux为8个字节 | (-2^31 ~ 2^31-1) |
long long(长长整型) | 8个字节 | (-2^63 ~ 2^63-1) |
(2)实型(浮点型)
表示小数。区别在于表示的有效数字范围不同。
数据类型 | 占用空间 | 有效数字范围 |
float(单精度浮点) | 4字节 | 7位有效数字 |
double(双精度浮点) | 8字节 | 15~16位有效数字 |
注意:有效数字范围,并不是指小数点后的数,而是整个浮点的数的数量。例如 3.14,有效数字为3。
默认的 cout << 输出浮点类型,会显示6位有效数字。
(3)字符型
显示单个字符。c/c++中,字符型变量只占用一个字节。
字符型变量不是将字符放入内存中,而是将对应的ASCII编码放入内存。
char ch = 'a';
ASCII 编码对照表:https://baike.baidu.com/item/ASCII/309296?fr=aladdin
(4)转义字符
表示一些不能显示出来的ASCII字符。
对照表:https://www.cnblogs.com/lsqbk/p/10259044.html
(5)字符串类型
表示一串字符。
C风格字符串:
char str1[] = "123abc";
C++风格字符串:
string str1 = "123abc"; // 需要包含头文件 #include <string>
(6)布尔类型
代表真或假的值。
bool的值只有两个:
true - 真,1
false - 假,0
(7)数据的输入
用于从键盘获取数据。
语法:cin >> 变量
(8)sizeof 统计内存大小
sizeof关键字,可以统计数据类型所占内存大小。
sizeof(数据类型/变量)
#include <iostream>
using namespace std;
int main() {
cout << "short\t\t占用空间:" << sizeof(short) << endl;
cout << "int\t\t占用空间:" << sizeof(int) << endl;
cout << "long\t\t占用空间:" << sizeof(long) << endl;
cout << "long long\t占用空间:" << sizeof(long long) << endl;
cout << "float\t\t占用空间:" << sizeof(float) << endl;
cout << "double\t\t占用空间:" << sizeof(double) << endl;
cout << "char\t\t占用空间:" << sizeof(char) << endl;
cout << "bool\t\t占用空间:" << sizeof(bool) << endl;
system("pause");
return 0;
}
---------------------------------------------------------------------------
short 占用空间:2
int 占用空间:4
long 占用空间:4
long long 占用空间:8
float 占用空间:4
double 占用空间:8
char 占用空间:1
bool 占用空间:1
请按任意键继续. . .
sizeof 和 strlen 区别:sizeof 和 strlen 区别
七、运算符
运算符用于执行代码的运算。
运算符分类:
运算符类型 | 作用 |
算术运算符 | 处理四则运算 |
赋值运算符 | 将表达式的值赋给变量 |
比较运算符 | 表达式的比较,并返回一个真值或假值 |
逻辑运算符 | 根据表达式的值返回真值或假值 |
(1)算术运算符
处理四则运算。
运算符 | 术语 | 示例 | 结果 |
+ | 正号 | +5 | 5 |
- | 负号 | -5 | 5 |
+ | 加 | 2 + 3 | 5 |
- | 减 | 5 - 3 | 2 |
* | 乘 | 2 * 3 | 6 |
/ | 除 | 6 / 3 | 2 |
% | 取模(取余) | 10 % 3 | 1 |
++ | 前置递增 | a=2; b=++a; | a = 3; b = 3; |
-- | 前置递减 | a=2; b=--a; | a = 1; b = 1; |
++ | 后置递增 | a=2; b=a++; | a = 3; b = 2; |
-- | 后置递减 | a=2; b=a--; | a = 1; b = 2; |
(2)赋值运算符
将表达式的值赋给变量。
运算符 | 术语 | 示例 | 结果 |
= | 赋值(等于) | a=2; | a=2; |
+= | 加等于 | a=2; a+=2; | a=4; |
-= | 减等于 | a=2; a-=2; | a=0; |
*= | 乘等于 | a=2; a*=3; | a=6; |
/= | 除等于 | a=6; a/=3; | a=2; |
%= | 模等于 | a=10; a%=3; | a=1; |
(3)比较运算符
表达式的比较,并返回一个真值或假值。
运算符 | 术语 | 示例 | 结果 |
== | 相等于 | 5 == 2 | 0 |
!= | 不等于 | 5 != 2 | 1 |
< | 小于 | 5 < 2 | 0 |
> | 大于 | 5 > 2 | 1 |
<= | 小于等于 | 5 <= 2 | 0 |
>= | 大于等于 | 5 >= 2 | 1 |
注意:= 和 == 的使用区别。
(4)逻辑运算符
根据表达式的值返回真值或假值
运算符 | 术语 | 示例 | 结果 |
! | 非 | !a | 如果 a为假,则 !a为真。反之则反 |
&& | 逻辑与 | a && b | a,b全为1时, a && b = 1。a,b任意一个为0, a && b = 0。 |
|| | 逻辑或 | a || b | a,b全为0时, a || b = 0。a,b任意一个为1, a || b = 1。 |
注意:& 和 &&、| 和 || 的使用区别。与 与逻辑与,或 与 逻辑或。
八、程序流程结构
c/c++支持最基本的三种程序运行结构:顺序结构、选择结构、循环结构。
顺序结构:程序按顺序执行,不发生跳转。
选择结构:依据条件是否满足,有选择的执行相应功能。
循环结构:依据条件是否满足,循环多次执行某段代码。
(1)选择结构
1. 使用 if语句,语法为:
if (条件) {
/* 满足条件后,可执行括号中内容 */
// ...
}
if (条件1) {
/* 满足条件1后,执行本括号中程序 */
// ...
/* 执行完程序后,结束整个if结构 */
}
else if (条件2) {
/* 如果条件1不满足,而条件2满足,执行本括号中程序 */
// ...
/* 执行完程序后,结束整个if结构 */
}
else if (条件3) {
/* 如果条件1、条件2均不满足,而条件3满足,执行本括号中程序 */
// ...
/* 执行完程序后,结束整个if结构 */
}
...
...
...
if (条件1) {
/* 满足条件1后,执行本括号中程序 */
// ...
/* 执行完程序后,结束整个if结构 */
}
else if (条件2) {
/* 如果条件1不满足,而条件2满足,执行本括号中程序 */
// ...
/* 执行完程序后,结束整个if结构 */
}
else if (条件3) {
/* 如果条件1、条件2均不满足,而条件3满足,执行本括号中程序 */
// ...
/* 执行完程序后,结束整个if结构 */
}
...
...
...
else {
/* 如果条件1、条件2、条件3...均不满足,则执行本括号中程序 */
// ...
/* 执行完程序后,结束整个if结构 */
}
int main() {
int a = 0;
if (a < 0) {
cout << "a小于0" << endl;
}
else if (a > 0) {
cout << "a大于0" << endl;
}
else {
cout << "a等于0" << endl;
}
system("pause");
return 0;
}
---------------------------------------------------
a等于0
请按任意键继续. . .
if支持多重嵌套。
2. 三目运算符
三目运算符可实现简单的判断。语法:
表达式1 ? 表达式2 : 表达式3
// 如果表达式1为真,则执行表达式2,并返回表达式2的结果。
// 如果表达式1为假,则执行表达式3,并返回表达式3的结果。
int main() {
int a = 10;
a > 0 ? cout << "a大于0" << endl : cout << "a小于0" << endl;
system("pause");
return 0;
}
------------------------------------------------------------------
a大于0
请按任意键继续. . .
3. switch语句。执行多条件分支语句。语法:
switch (表达式) {
case 结果1: 执行代码段; break;
case 结果2: 执行代码段; break;
case 结果3: 执行代码段; break;
...
...
...
defaule: 执行代码段; break;
}
int usr=0;
cout << "请输入1、2、3其中一个数字" << endl;
cin >> usr;
switch (usr)
{
case 1:
cout << "输入了1" << endl; break;
case 2:
cout << "输入了2" << endl; break;
case 3:
cout << "输入了3" << endl; break;
default:
cout << "不在规定范围内输入" << endl; break;
}
--------------------------------------------------------------
请输入1、2、3其中一个数字
3
输入了3
请按任意键继续. . .
注意:别少写break,少写break代码会继续向下执行。直到再次遇到break,才会结束整个switch。
(2)循环结构
1. while循环语句。语法:
while (条件) {
/* 满足条件后,执行本括号中程序 */
// ...
/* 执行完程序后,接着判断条件。如满足,继续循环执行本括号程序;如不满足,结束while循环 */
}
2. do while循环语句。语法:
do {
// 先执行一次本括号程序
// ...
/* 执行完程序后,判断条件。如满足,继续循环执行本括号程序;如不满足,结束while循环 */
}while (条件)
3. for循环语句。满足循环条件,执行循环语句。语法:
for (表达式1; 表达式2; 表达式3)
{
循环语句
}
for (初始化语句; 循环条件; 自增或自减)
{
循环语句
}
int i, j;
for (i = 0; i < 5; i++)
{
for (j = 0; j < 10; j++)
{
cout << "j ";
}
cout << "i" << endl;
}
-------------------------------------------
j j j j j j j j j j i
j j j j j j j j j j i
j j j j j j j j j j i
j j j j j j j j j j i
j j j j j j j j j j i
请按任意键继续. . .
(3)跳转语句
break语句:用于跳出选择结构或循环结构。
(注意:break只会跳出距离它最近的for、while这些循环语句,跟if没有关系)
作用:
出现在switch语句中,作用是终止case并跳出switch。
出现在循环语句中,作用是跳出当前的循环语句。
出现在嵌套循环语句中,跳出最近的内层循环语句。
int usr=0;
cout << "请输入1、2、3其中一个数字" << endl;
cin >> usr;
switch (usr)
{
case 1:
cout << "输入了1" << endl; //break;
case 2:
cout << "输入了2" << endl; //break;
case 3:
cout << "输入了3" << endl; //break;
default:
cout << "不在规定范围内输入" << endl; //break;
}
---------------------------------------------------------------
请输入1、2、3其中一个数字
2
输入了2
输入了3
不在规定范围内输入
请按任意键继续. . .
int i, j;
for (i = 0; i < 5; i++)
{
for (j = 0; j < 10; j++)
{
if (j >= 5)
break;
cout << "j ";
}
cout << "i" << endl;
}
---------------------------------------------------------
j j j j j i
j j j j j i
j j j j j i
j j j j j i
j j j j j i
请按任意键继续. . .
int i, j;
for (i = 0; i < 5; i++)
{
for (j = 0; j < 10; j++)
{
cout << "j ";
}
cout << "i" << endl;
break;
}
------------------------------------------------------
j j j j j j j j j j i
请按任意键继续. . .
continue语句:循环语句中,跳过本次循环中余下尚未执行的语句,继续执行下一次循环。
int i, j;
for (i = 0; i < 5; i++)
{
for (j = 0; j < 10; j++)
{
if (j == 5 || j == 8)
{
continue;
}
cout << j;
}
cout << "i" << endl;
}
--------------------------------------------------------
01234679i
01234679i
01234679i
01234679i
01234679i
请按任意键继续. . .
goto语句:可以无条件跳转语句。
(注意:少用,goto不利于梳理代码逻辑)
cout << "执行代码段1" << endl;
goto CODE_1;
cout << "执行代码段2" << endl;
cout << "执行代码段3" << endl;
CODE_1:
cout << "执行代码段4" << endl;
---------------------------------------------------------
执行代码段1
执行代码段4
请按任意键继续. . .
九、数组
数组:一个里面存放了相同类型数据元素的集合。
特点:每个数组中的元素都是相同的数据类型;数组是由连续的内存位置组成的。
注意:数组的下标是从0开始索引。
(1.1)一维数组
一维数组的三种定义方式:
数据类型 数组名[ 数组长度 ];
数据类型 数组名[ 数组长度 ] = { 值1, 值2 ...};
数据类型 数组名[ ] = { 值1, 值2 ...};
int str1[5];
int str1[5] = { -2, -1, 0, 1, 2};
int str1[] = { -2, -1, 0, 1, 2};
int i=0;
int str1[5];
str1[0] = -2;
str1[1] = -1;
str1[2] = 0;
str1[3] = 1;
str1[4] = 2;
for (i = 0; i <5; i++)
{
cout << str1[i] << " ";
}
cout << endl;
----------------------------------------------------------
-2 -1 0 1 2
请按任意键继续. . .
int i=0;
int str1[5] = { -2, -1, 0, 1, 2 };
for (i = 0; i <5; i++)
{
cout << str1[i] << " ";
}
cout << endl;
-----------------------------------------------------------
-2 -1 0 1 2
请按任意键继续. . .
int i=0;
int str1[] = { -2, -1, 0, 1, 2 };
for (i = 0; i <5; i++)
{
cout << str1[i] << " ";
}
cout << endl;
-------------------------------------------------------
-2 -1 0 1 2
请按任意键继续. . .
(1.2)一维数组数组名
一维数组名称的用途:
1.可以统计整个数组在内存中的长度。
2.可以获取数组在内存中的首地址。
int i=0;
int str1[5] = { -2, -1, 0, 1, 2 };
for (i = 0; i <5; i++)
{
cout << str1[i] << " ";
}
cout << endl;
cout << "str1[]整个数组占用的空间:" << sizeof(str1) << endl;
cout << "str1[0]元素占用的空间:" << sizeof(str1[0]) << endl;
cout << "str1[]数组中元素个数:" << sizeof(str1) / sizeof(str1[0]) << endl;
cout << "str1[]数组的内存首地址:" << str1 << endl;
cout << "str1[0]元素的内存首地址:" << &str1[0] << endl;
cout << "str1[1]元素的内存首地址:" << &str1[1] << endl;
----------------------------------------------------------------------------------------
-2 -1 0 1 2
str1[]整个数组占用的空间:20
str1[0]元素占用的空间:4
str1[]数组中元素个数:5
str1[]数组的内存首地址:00D8FA64
str1[0]元素的内存首地址:00D8FA64
str1[1]元素的内存首地址:00D8FA68
请按任意键继续. . .
(1.3)一维数组常用算法
寻找最大值:
int i=0;
int str1[5] = { -2, -1, 0, 1, 2 };
int start = 0;
int end = sizeof(str1) / sizeof(str1[0]);
int xtemp = 0;
for (i = 0; i < end; i++)
{
if (str1[i] > str1[xtemp])
{
xtemp = i;
}
}
for (i = 0; i < 5; i++)
{
cout << str1[i] << " ";
}
cout << endl;
cout << "str1[]数组中元素个数:" << end << endl;
cout << "str1[]数组中第几个元素为最大值:" << xtemp + 1 << endl;
cout << "最大值为:" << str1[xtemp] << endl;
--------------------------------------------------------------------------
-2 -1 0 1 2
str1[]数组中元素个数:5
str1[]数组中第几个元素为最大值:5
最大值为:2
请按任意键继续. . .
逆置(整个数组首位互换):
int str1[5] = { -2, -1, 0, 1, 2 };
int start = 0;
int end = sizeof(str1) / sizeof(str1[0]) - 1;
int xtemp = 0;
for (i = 0; i < 5; i++)
{
cout << str1[i] << " ";
}
cout << endl;
while (start < end)
{
xtemp = str1[start];
str1[start] = str1[end];
str1[end] = xtemp;
start++;
end--;
}
for (i = 0; i < 5; i++)
{
cout << str1[i] << " ";
}
cout << endl;
--------------------------------------------------------------
-2 -1 0 1 2
2 1 0 -1 -2
请按任意键继续. . .
冒泡排序:
int i=0,j=0;
int str1[5] = { 8, 2, 5, 4, 6 };
int start = 0;
int end = sizeof(str1) / sizeof(str1[0]) - 1;
int xtemp = 0;
cout << "数组原始值:";
for (i = 0; i < 5; i++)
{
cout << str1[i] << " ";
}
cout << endl;
for (i = end; i > 0; i--)
{
for (j = 0; j < i; j++)
{
if (str1[j] > str1[j + 1])
{
xtemp = str1[j];
str1[j] = str1[j + 1];
str1[j + 1] = xtemp;
}
}
}
cout << "冒泡排序后:";
for (i = 0; i < 5; i++)
{
cout << str1[i] << " ";
}
cout << endl;
----------------------------------------------------------------------
数组原始值:8 2 5 4 6
冒泡排序后:2 4 5 6 8
请按任意键继续. . .
(2.1)二维数组
二维数组的四种定义方式:
数据类型 数组名[ 行数 ][ 列数 ];
数据类型 数组名[ 行数 ][ 列数 ] = { { 值1, 值2 ...}, { 值11, 值12 ...}, ... };
数据类型 数组名[ 行数 ][ 列数 ] = { 值1, 值2, 值3, 值4 ...};
数据类型 数组名[ ][ 列数 ] = { 值1, 值2, 值3, 值4 ...};
int str1[2][3];
int str1[2][3] = { { -2, -1, 0}, { 1, 2, 3} };
int str1[2][3] = { -2, -1, 0, 1, 2, 3};
int str1[][3] = { -2, -1, 0, 1, 2, 3};
int i=0,j=0;
int str1[2][3] = { { -2, -1, 0}, { 1, 2, 3} };
//int str1[2][3] = { -2, -1, 0, 1, 2, 3 };
//int str1[][3] = { -2, -1, 0, 1, 2, 3 };
for (i = 0; i < 2; i++)
{
for (j = 0; j < 3; j++)
{
cout << str1[i][j] << " ";
}
cout << endl;
}
----------------------------------------------------------------
-2 -1 0
1 2 3
请按任意键继续. . .
(2.2)二维数组数组名
二维数组名称的用途:
1.统计二维数组所占内存空间。
2.获取二维数组在内存中的首地址。
int i = 0,j = 0;
int str1[2][3] =
{
{ -2, -1, 0},
{ 1, 2, 3}
};
for (i = 0; i < 2; i++)
{
for (j = 0; j < 3; j++)
{
cout << str1[i][j] << " ";
}
cout << endl;
}
cout << "str1[][]二维数组占用的空间:" << sizeof(str1) << endl;
cout << "str1[][]第一行占用的空间:" << sizeof(str1[0]) << endl;
cout << "str1[0][0]元素占用的空间:" << sizeof(str1[0][0]) << endl;
cout << endl;
cout << "str1[][]二维数组的行数:" << sizeof(str1) / sizeof(str1[0]) << endl;
cout << "str1[][]二维数组的列数:" << sizeof(str1[0]) / sizeof(str1[0][0]) << endl;
cout << "str1[][]二维数组中所有元素个数:" << sizeof(str1) / sizeof(str1[0][0]) << endl;
cout << endl;
cout << "str1[][]二维数组的内存首地址:" << str1 << endl;
cout << "str1[0][0]第一行行首的内存首地址:" << &str1[0][0] << endl;
cout << "str1[0][1]元素的内存首地址:" << &str1[0][1] << endl;
cout << "str1[1][0]第二行行首的内存首地址:" << &str1[1][0] << endl;
-----------------------------------------------------------------------------------------
-2 -1 0
1 2 3
str1[][]二维数组占用的空间:24
str1[][]第一行占用的空间:12
str1[0][0]元素占用的空间:4
str1[][]二维数组的行数:2
str1[][]二维数组的列数:3
str1[][]二维数组中所有元素个数:6
str1[][]二维数组的内存首地址:00CFF844
str1[0][0]第一行行首的内存首地址:00CFF844
str1[0][1]元素的内存首地址:00CFF848
str1[1][0]第二行行首的内存首地址:00CFF850
请按任意键继续. . .
(2.3)二维数组应用案例
十、函数
(1)函数的定义
作用:将一段经常使用的代码封装起来,减少重复代码。
组成:
1.返回值类型:一个函数可以返回一个值。
2.函数名:函数的名称。
3.参数列:使用函数时,传入的数据。
4.函数体语句:花括号内的代码,函数内需要执行的语句,用户代码。
5.return表达式:和返回值类型匹配。函数执行完后,返回相应数据。
语法:
返回值类型 函数名 (参数列表)
{
函数体语句
return表达式
}
int add (int num1, int num2)
{
int sum = num1 + num2;
return sum;
}
int main(){
/* 用户代码段 */
// ...
// ...
system("pause");
return 0;
}
(2)函数的调用,形参,实参
#include <iostream>
using namespace std;
// 函数定义
int add(int num1, int num2) // int num1, int num2为形式参数,简称形参
{
int sum = num1 + num2;
return sum;
}
int main() {
// a,b称为 实际参数,简称实参
int a = 11, b = 23;
// 调用add函数
int sum = add(a, b);
cout << "a + b = " << sum << endl;
system("pause");
return 0;
}
------------------------------------------------------------------------
a + b = 34
请按任意键继续. . .
(3)值传递
要点:实参传递给形参后,形参的改变不会影响到实测。
#include <iostream>
using namespace std;
// 函数定义
int test1(int num1, int num2)
{
cout << "输入的 num1 = " << num1 << endl;
cout << "输入的 num2 = " << num2 << endl;
cout << endl;
num1 += 10;
num2 += 20;
cout << "输出的 num1 = " << num1 << endl;
cout << "输出的 num2 = " << num2 << endl;
cout << endl;
return 0;
}
int main() {
// a,b称为 实际参数,简称实参
int a = 11, b = 23;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << endl;
// 调用add函数
test1(a, b);
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << endl;
system("pause");
return 0;
}
----------------------------------------------------------------------
a = 11
b = 23
输入的 num1 = 11
输入的 num2 = 23
输出的 num1 = 21
输出的 num2 = 43
a = 11
b = 23
请按任意键继续. . .
(4)函数的常见样式
常见的函数样式有4种:
1.无参无返
2.有参无返
3.无参有返
4.有参有返
(5)函数的声明
作用:告诉编译器函数名称及如何调用函数。函数的实际主体可以单独定义。
注意:函数的声明可以多次,但是函数的定义只能有一次。
#include <iostream>
using namespace std;
// 函数的声明
int test1(int num1, int num2);
int main() {
// a,b称为 实际参数,简称实参
int a = 11, b = 23;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << endl;
// 调用add函数
int max = test1(a, b);
cout << "较大值 = " << max << endl;
system("pause");
return 0;
}
// 函数定义
int test1(int num1, int num2)
{
return num1 > num2 ? num1 : num2;
}
------------------------------------------------------------------
a = 11
b = 23
较大值 = 23
请按任意键继续. . .
(6)函数的分文件编写
函数太多,不能写同一个文件中。而且功能混淆,不便于梳理、阅读、移植。
作用:让代码结构更加清晰。
函数的分文件编写一般有4个步骤:
1.创建后缀名为.h的头文件
2.创建后缀名为.cpp的源文件
3.在头文件中写函数的声明
4.在源文件中写函数的定义
将(5)的代码分文件编写:
demo.cpp
#include <iostream>
using namespace std;
#include "swap.h"
int main() {
// a,b称为 实际参数,简称实参
int a = 11, b = 23;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << endl;
// 调用add函数
int max = swap(a, b);
cout << "较大值 = " << max << endl;
system("pause");
return 0;
}
swap.cpp
#include "swap.h"
// 函数定义
int swap(int num1, int num2)
{
return num1 > num2 ? num1 : num2;
}
swap.h
#include <iostream>
using namespace std;
// 函数的声明
int swap(int num1, int num2);
十一、指针
(1)指针的定义和使用
指针的作用:可以通过指针间接访问内存。
(1)指针变量的定义和使用:
指针变量定义语法:
数据类型 * 变量名;
#include <iostream>
using namespace std;
int main() {
int a = 13;
int* p;
// 指针指向数据a的地址
p = &a;
cout << "a的内存地址为:" << &a << endl;
cout << "指针p为:" << p << endl;
cout << endl;
// 解引用
*p = 100;
cout << "a = " << a << endl;
cout << "*p = " << *p << endl;
system("pause");
return 0;
}
------------------------------------------------------------
a的内存地址为:007FF988
指针p为:007FF988
a = 100
*p = 100
请按任意键继续. . .
(2)指针所占用的空间
指针也是一种数据类型,这种数据类型占用多少内存字节呢?
#include <iostream>
using namespace std;
int main() {
int a = 13;
int* p;
// 指针指向数据a的地址
p = &a;
cout << "sizeof(int * ) = " << sizeof(int*) << endl;
cout << "sizeof(float * ) = " << sizeof(float*) << endl;
cout << "sizeof(double * ) = " << sizeof(double*) << endl;
cout << "sizeof(char * ) = " << sizeof(char*) << endl;
system("pause");
return 0;
}
Debug x86:------------------------------------------------------------------------
sizeof(int * ) = 4
sizeof(float * ) = 4
sizeof(double * ) = 4
sizeof(char * ) = 4
请按任意键继续. . .
Debug x64:------------------------------------------------------------------------
sizeof(int * ) = 8
sizeof(float * ) = 8
sizeof(double * ) = 8
sizeof(char * ) = 8
请按任意键继续. . .
指针所占用的内存空间大小,只跟操作系统有关。32位系统为4字节,64位系统为8字节。
指针前面的数据类型,只是表示这段指针对应的值的数据类型,并不是指针的类型。
修改程序运行在32位、64位操作系统环境,在这里勾选 x86、x64。
(3)空指针
空指针:指针变量指向内存中编号为0的空间。
用途:初始化指针变量。
注意:空指针指向的内存是不可以访问的。
#include <iostream>
using namespace std;
int main() {
//空指针
int* p = NULL;
//*p = 100;
cout << "指针p指向的内存地址: " << p << endl;
cout << "指针p指向的值为: " << *p << endl;
system("pause");
return 0;
}
-------------------------------------------------------
指针p指向的内存地址: 00000000
D:\VS_C++_PRJ\demo01\Debug\demo01.exe (进程 11668)已退出,代码为 -1073741819。
按任意键关闭此窗口. . .
(4)野指针
野指针:指针变量指向非法的内存空间。
注意:在程序中,尽量避免出现野指针。
#include <iostream>
using namespace std;
int main() {
//野指针
int * p = (int *)0x21003000;
//*p = 100;
cout << "指针p指向的内存地址: " << p << endl;
cout << "指针p指向的值为: " << *p << endl;
system("pause");
return 0;
}
---------------------------------------------------------------------------
指针p指向的内存地址: 21003000
D:\VS_C++_PRJ\demo01\Debug\demo01.exe (进程 7944)已退出,代码为 -1073741819。
按任意键关闭此窗口. . .
(5)const修饰指针
const修饰指针有三种情况:
1.const修饰指针 ---- 常量指针
2.const修饰指针 ---- 指针常量
3.const既修饰指针,也修饰常量
const修饰指针 ---- 常量指针:
int a = 10, b = 10;
// 常量指针
// 特点:指针的指向可以修改,但是指针指向的值不可修改
const int * p = &a;
*p = 20; // 错误,指针指向的值不可以修改
p = &b; // 正确,指针的指向可以修改
const修饰指针 ---- 指针常量:
int a = 10, b = 10;
// 指针常量
// 特点:指针的指向不可以修改,指针指向的值可以修改
int * const p = &a;
*p = 20; // 正确,指针指向的值可以修改
p = &b; // 错误,指针的指向不可以修改
const既修饰指针,也修饰常量:
int a = 10, b = 10;
// 指针常量
// 特点:指针的指向、指针指向的值,都不可以修改
const int * const p = &a;
*p = 20; // 错误,指针指向的值不可以修改
p = &b; // 错误,指针的指向不可以修改
(6)指针和数组
作用:利用指针访问数组中的元素
int main() {
int str1[10] = {11, 56, 82, 42, 85, 45, 89, 23, 41, 57};
int* p = str1;
cout << *p << endl;
cout << *p + 1 << endl;
cout << *(p + 1) << endl;
p++;
cout << *p << endl;
system("pause");
return 0;
}
-------------------------------------------------------------------
11
12
56
56
请按任意键继续. . .
(7)指针和函数(地址传递)
作用:利用指针做函数参数,可以修改实参的值。
与10.3值传递,对比着看。
要点:如果不想修改实参,就用值传递。如果想修改实参,就用地址传递。
int swap(int * num1, int * num2)
{
int xtemp = *num1;
*num1 = *num2;
*num2 = xtemp;
return 0;
}
int main() {
int a = 22;
int b = 55;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << endl;
swap(&a, &b);
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << endl;
system("pause");
return 0;
}
---------------------------------------------------------
a = 22
b = 55
a = 55
b = 22
请按任意键继续. . .
(8)指针、数组、函数,配合使用案例
十二、结构体
(1)结构体定义和使用
基本概念:结构体属于用户自定义的数据类型,允许用户存储不同的数据类型。
结构体定义和使用:
语法:
struct 结构体名 { 结构体成员列表 };
通过结构体创建变量的方式有三种:
struct 结构体名 变量名;
struct 结构体名 变量名 = { 成员1值, 成员2值... };
定义结构体时顺便创建变量;
代码:
/* ------------------ 1.struct 结构体名 变量名; 之后进行赋值操作 ------------------ */
struct Student
{
// 成员列表
string name; // 姓名
int age; // 年龄
int score; // 分数
};
int main() {
//struct Student xiaoMing;
Student xiaoMing; // struct关键字可以省略
xiaoMing.name = "小明";
xiaoMing.age = 18;
xiaoMing.score = 96;
xiaoMing = { "小明", 18, 96 };
cout << "姓名:" << xiaoMing.name << " 年龄:" << xiaoMing.age << " 分数:" << xiaoMing.score << endl;
system("pause");
return 0;
}
/* -------------- 2.struct 结构体名 变量名 = { 成员1值, 成员2值... }; -------------- */
struct Student
{
// 成员列表
string name; // 姓名
int age; // 年龄
int score; // 分数
};
int main() {
Student xiaoMing = {"小明", 18, 96};
cout << "姓名:" << xiaoMing.name << " 年龄:" << xiaoMing.age << " 分数:" << xiaoMing.score << endl;
system("pause");
return 0;
}
/* -------------------- 3.定义结构体时顺便创建变量; -------------------- */
struct Student
{
// 成员列表
string name; // 姓名
int age; // 年龄
int score; // 分数
};
int main() {
xiaoMing.name = "小明";
xiaoMing.age = 18;
xiaoMing.score = 96;
xiaoMing = { "小明", 18, 96 };
cout << "姓名:" << xiaoMing.name << " 年龄:" << xiaoMing.age << " 分数:" << xiaoMing.score << endl;
system("pause");
return 0;
}
-----------------------------------------------------------------------------------
姓名:小明 年龄:18 分数:96
请按任意键继续. . .
使用 typedef 定义 struct 结构体方法:https://blog.youkuaiyun.com/Mark_md/article/details/107656790
(2)结构体数组
作用:将自定义的结构体放入到数组中,方便维护。
语法:
struct 结构体名 数组名[ 元素个数 ] = { {}, {}, ... {} };
struct Student
{
// 成员列表
string name; // 姓名
int age; // 年龄
int score; // 分数
};
int main() {
struct Student stuArray[3] =
{
{ "小明", 18, 96 },
{ "小红", 20, 100 },
{ "小亮", 21, 98 }
};
for (int i = 0; i < 3; i++)
{
cout << "姓名:" << stuArray[i].name
<< " 年龄:" << stuArray[i].age
<< " 分数:" << stuArray[i].score << endl;
}
system("pause");
return 0;
}
----------------------------------------------------------------------------
姓名:小明 年龄:18 分数:96
姓名:小红 年龄:20 分数:100
姓名:小亮 年龄:21 分数:98
请按任意键继续. . .
(3)结构体指针
作用:通过指针访问结构体中的成员。
利用操作符 -> 可以通过结构体指针访问结构体属性。
示例:
struct Student
{
// 成员列表
string name; // 姓名
int age; // 年龄
int score; // 分数
};
int main() {
struct Student xiaoMing = { "小明", 18, 96 };
Student* p = &xiaoMing;
cout << "姓名:" << p->name
<< " 年龄:" << p->age
<< " 分数:" << p->score << endl;
system("pause");
return 0;
}
-----------------------------------------------------------------
姓名:小明 年龄:18 分数:96
请按任意键继续. . .
(4)结构体嵌套
结构体嵌套结构体:
作用:结构体中的成员可以是另一个结构体。
例如:每个老师辅导一个学员,老师的结构体中,记录学生的结构体。
示例:
struct student
{
// 成员列表
string name; // 姓名
int age; // 年龄
int score; // 分数
};
struct teacher
{
int id; // 职工编号
string name; // 教师姓名
int age; // 教师年龄
struct student stu; // 子结构体 学生
};
int main() {
teacher wang;
wang.id = 112374;
wang.name = "王芳";
wang.age = 26;
wang.stu.name = "小明";
wang.stu.age = 18;
wang.stu.score = 96;
cout << "教师姓名:" << wang.name
<< " 教师年龄:" << wang.age
<< " 教师ID号:" << wang.id << endl;
cout << "学生姓名:" << wang.stu.name
<< " 学生年龄:" << wang.stu.age
<< " 学生分数:" << wang.stu.score << endl;
system("pause");
return 0;
}
-------------------------------------------------------------------------
教师姓名:王芳 教师年龄:26 教师ID号:112374
学生姓名:小明 学生年龄:18 学生分数:96
请按任意键继续. . .
(5)结构体做函数参数
作用:将结构体作为参数向函数中传递
传递方式分两种:值传递,地址传递。
值传递示例:
struct student
{
// 成员列表
string name; // 姓名
int age; // 年龄
int score; // 分数
};
void printStudent(student stu)
{
cout << "姓名:" << stu.name
<< " 年龄:" << stu.age
<< " 分数:" << stu.score << endl;
stu.name = "无";
stu.age = 0;
stu.score = 0;
}
int main() {
student xiaoMing = { "小明", 18, 96 };
printStudent(xiaoMing);
cout << "姓名:" << xiaoMing.name
<< " 年龄:" << xiaoMing.age
<< " 分数:" << xiaoMing.score << endl;
system("pause");
return 0;
}
---------------------------------------------------------------------------
姓名:小明 年龄:18 分数:96
姓名:小明 年龄:18 分数:96
请按任意键继续. . .
地址传递示例:
struct student
{
// 成员列表
string name; // 姓名
int age; // 年龄
int score; // 分数
};
void printStudent(student * stu)
{
cout << "姓名:" << stu->name
<< " 年龄:" << stu->age
<< " 分数:" << stu->score << endl;
stu->name = "无";
stu->age = 0;
stu->score = 0;
}
int main() {
student xiaoMing = { "小明", 18, 96 };
printStudent(&xiaoMing);
cout << "姓名:" << xiaoMing.name
<< " 年龄:" << xiaoMing.age
<< " 分数:" << xiaoMing.score << endl;
system("pause");
return 0;
}
--------------------------------------------------------------------------
姓名:小明 年龄:18 分数:96
姓名:无 年龄:0 分数:0
请按任意键继续. . .
如果不想实参结构体内容,用值传递,反之用地址传递。
地址传递还可以使用数组,可实现同样功能,书写与阅读比指针更加直观。
(6)结构体中const使用场景
作用:用const来防止误操作
值传递会copy,会占内存空间,复制也会多花时间。所以如果可以用地址传递,可以提高执行效率。
而地址传递可能会对原始对象进行误修改,这时候就可以加 const。如果出现修改,编译器会报错
示例:
void printStudent(const student * stu)
{
cout << "姓名:" << stu->name
<< " 年龄:" << stu->age
<< " 分数:" << stu->score << endl;
stu->name = "无"; // 编译器会报错
stu->age = 0;
stu->score = 0;
}