C++常量与变量:
1.常量的定义方式
格式:
#define 宏常量 值
例:
#include <iostream>
using namespace std;
#define Day 7 //常量:顾名思义,一经定义不可修改,故常常写到函数外
int main()
{
cout<<"一周里有"<<Day<<"天"<<endl;
system("pause");
return 0;
}
//输出结果:一周里有7天
格式:
const 数据类型 变量名 = 初始值
例:
#include <iostream>
using namespace std;
int main()
{
const int month=12;//const修饰的变量也称作常量,常写到函数内
cout<<"一年里有"<<month<<"个月"<<endl;
system("pause");
return 0;
}
//输出结果:一年里有12个月
2.变量
作用:给一段内存空间起名字 ,使我们方便操作这段内存
格式:
数据类型 变量名 = 初始值
每段内存都有一段16进制的地址编号,变量名就是用来代替这个难记的地址编号,从而让我们可以拿到内存里的值。
#include <iostream>
using namespace std;
int main()
{
int a=1;
cout<<"a的值为"<<a<<endl;
system("pause");
return 0;
}
//输出结果:a的值为1
C++标识符命名规则及常用关键字:
命名规则:
1.标识符不能是关键字
2.标识符只能由字母,数字,下划线组成
3.第一个字符不能为数字
4.标识符中字母区分大小写(比方说:A与a表示两个不同的量)
常用关键字:
C++数据类型:
声明:c++规定在创建一个变量或者常量时,必须要指出相应的数据类型,否则无法给变量分配内存,所以数据类型存在的意义就是根据不同的类型给变量分配合适的内存空间。
一、整型(short 、 int 、 long 、 long long)
作用:表示整数类型的数据
能表示整数的类型有如下方式,区别在于所占的内存空间不同:
整型大小比较:short<int<=long<=long long (注:2^15=32768)
二、sizeof关键字
作用:统计数据类型所占内存的大小
语法:sizeof(数据类型/变量)
例:
#include<iostream>
using namespace std;
int main()
{
int num1=4.15;
cout<<"int占用的内存空间为"<<sizeof(num1)<<endl;
system("pause");
return 0;
}
三、实型(浮点型)
作用:用于表示小数
分为两种:
1.单精度float:占用4字节表示7位有效数字
2.双精度double:占用8字节表示15--16位有效数字
(有效数字:小数点之前的数字也作数)
两者的区别在于表示的有效数字范围不同
辨析:
float f1=3.14;与float f1=3.14f;的区别:
默认情况下编译器会将读到的小数当作一个双精度,由于前边float的存在,使用时会再把它转化为单精度,这样一来就产生了赘余的一步;3.14f则使编译器直接将它识别成一个单精度。
注意:c++的默认情况下,输出一个小数,最多显示小数的六位有效数字。
科学计数法:(e就是10)
例:3e2=300
3e-2=0.03
四、字符型
作用:显示单个字母
语法:char ch = 'a' ;
注意1:单引号里只能有一个字符,不能是字符串。
注意2:c++中字符型变量只占用1个字节。
注意3:内存中存储的并不是字符本身,而是对应的ASCLL码(但输出时还是输出a)。
查看字符型变量对应的ASCLL码:在变量名前加(int)用来将字符型变量强转成一个十进制整数。
例:
#include<iostream>
using namespace std;
int main()
{
char ch = 'a';
cout << (int) ch << endl ;
system("pause");
return 0;
}
输出结果:97
常记ASCLL码:
a=97
A=65
五、转义字符
作用:用于表示一些不能显示出来的ASCLL字符
现阶段常用转义字符:\n \\ \t
\n:换行
cout<<"Hello world"<<endl;
就等同于
cout<<"Hello world\n";
\\:第一个“\”让编译器知道用户接下来要输入一个特殊字符了,第二个“\”才是“\”的本意
比如我们想输出一个“\”则需要写成:
cout<<"\\"<<endl;
\t:跳到下一个制表位再继续输出(比较整齐)
例如:
#include<iostream>
using namespace std;
int main()
{
cout<<"楠哥套马"<<endl;
cout<<"楠哥\t套马"<<endl;
system("pause");
return 0;
}
输出结果:
楠哥套马
楠哥 套马//中间隔了四个字节
六、字符串型
语法:(1)c++风格: string 变量名 = " 字符串 " ;
(2)c风格:char 字符串名 [ ] = " 字符串 " ;
注意:在使用c++风格时需要预写一个头文件#include<string>
七、布尔类型 bool
作用:代表真(1)或假(0)的值
bool类型只有两个值:
true---真(本质是1)
false---假(本质是0)
bool类型占1个字节大小,除了0代表假,其他非零值都是真
例:
#include<iostream>
using namespace std;
int main()
{
bool flag1 = true;
cout<<flag1<<endl;
bool flag2 = false;
cout<<flag2<<endl;
system("pause");
return 0;
}
输出结果:
1
0
C++运算符:
一、算术运算符
作用:用于处理四则运算
1、除法
注意:两个整型相除,结果依然是整型;两个小数相除结果可以为六位有效数字的小数
例:10/3=3
10/20=0
0.5/0.22=2.27273
2、取余
注意:c++规定两个小数不能做取余运算
3、递增递减运算符(前置与后置)
逻辑:
前置:先算再用
后置:先用再算
例:
#include<iostream>
using namespace std;
int main()
{
int a1=10;
int b1=++a1*10;
cout<<"a1="<<a2/n;
cout<<"b1="<<b1/n;
int a2=10;
int b2=a2++*10;
cout<<"a2="<<a2/n;
cout<<"b2="<<b2/n;
system("pause");
return 0;
}
输出结果:
a1=10
b1=110
a2=10
b2=100
二、赋值运算符
逻辑:先运算,再赋值
例:
int a=2
a+=2等同于a=a+2得a=4
a-=2等同于a=a-2得a=0
a*=2等同于a=a*2得a=4
a/=2等同于a=a/2得a=1
a%=2等同于a=a%2得a=0
三、比较运算符
作用:用于表达式的比较,并返回一个真值或假值
例:
#include<iostream>
using namespace std;
int main()
{
int a=10;
int b=20;
cout<<(a==b)/n;//这里的()用于提高a==b运算的优先级,先运算()内的表达式再cout
system("pause");
return 0;
}
输出结果:0
四、逻辑运算符
作用:用于根据表达式的值返回真值或假值
即:
!:取反
&&:且
||:或
C++程序流程结构:
c++最基本的三种程序运行结构:顺序结构、选择结构、循环结构
顺序结构:程序按顺序执行,不发生跳转
选择结构:依据条件是否满足,有选择地执行相应功能
循环结构:依据条件是否满足,循环多次执行某段代码
一、选择结构
1、if语句
作用:执行满足条件的语句
三种形式:
1)单行格式if语句
语法:if (条件) {满足条件后执行的语句;}
例:
#include<iostream>
using namespace std;
int main()
{
int score=0;
cout<<"请输入您的分数:/n";
cin>>score;
cout<<"您输入的分数为:"<<score/n;
if(score>=565)
{
cout<<"恭喜您被长春理工大学录取/n";
}
system("pause");
return 0;
}
输入:
请输入您的分数:750
输出结果:
您输入的分数为:750
恭喜您被长春理工大学录取
注意:"if()"后面不要加";",否则的话if会与后面的代码分离,直接执行{满足条件后执行的语句}
2)多行格式if语句
语法:
if (条件)
{满足条件执行的语句;}
else
{不满足条件执行的语句;}
例:
#include<iostream>
using namespace std;
int main()
{
int score=0;
cout<<"请输入您的分数:/n";
cin>>score;
cout<<"您输入的分数为:"<<score/n;
if(score>=565)
{
cout<<"恭喜您被长春理工大学录取/n";
}
else
{
cout<<"很遗憾您没有被长春理工大学录取/n";
}
system("pause");
return 0;
}
输入:
请输入您的分数:250
输出结果:
您输入的分数为:250
很遗憾您没有被长春理工大学录取
3)多条件的if语句
语法:if (条件1)
{满足条件 1执行的语句}
else if(条件2)
{满足条件2执行的语句}
...
else
{都不满足执行的语句}
#include<iostream>
using namespace std;
int main()
{
int score=0;
cout<<"请输入您的分数:"<<endl;
cin>>score;
cout<<"您的分数为:"<<score<<endl;
if(score>518)
{
cout<<"恭喜您过了一本线"<<endl;
}
else if(score>468)
{
cout<<"恭喜您过了二本线"<<endl;
}
else
{
cout<<"很遗憾您没有考上本科"<<endl;
}
system("pause");
return 0;
}
输入:
请输入您的分数:466
您的分数为:466
输出结果:很遗憾您没有考上本科
4)嵌套if语句
案例需求:
提示用户输入一个眼镜度数,根据度数做出如下判断:
度数大于600能看上楠哥,大于400会觉得楠哥不错,其余情况不看楠哥。
在能看上楠哥的情况中,如果度数大于1000,活不过一周;大于800,活不过一月;其余情况活不过一学期。
例:
#include<iostream>
using namespace std;
int main()
{
int curvature = 0;
cout<<"请输入您的度数:"<<endl;
cin>> curvature ;
cout<<"您的度数为:"<<curvature<<endl;
if(curvature>600)
{
cout<<"您能看上楠哥"<<endl;
cout<<"但"<<endl;
if (curvature>1000)
{
cout<<"你小子活不过一周"<<endl;
}
else if(curvature>800)
{
cout<<"你小子活不过一个月"<<endl;
}
else
{
cout<<"你小子活不过一个学期"<<endl;
}
}
else if(curvature>468)
{
cout<<"您觉得楠哥很不错"<<endl;
}
else
{
cout<<"楠哥是谁?"<<endl;
}
system("pause");
return 0;
}
输入:
请输入您的度数:700
输出结果:
您的度数为:700
您能看上楠哥
但
你小子活不过一个学期
2、三目运算符
作用:通过三目运算符实现简单的判断
语法:表达式1?表达式2:表达式3
解释:如果表达式1的值为真,执行表达式2,并返回表达式2的结果
如果表达式1的值为假,执行表达式3,并返回表达式3的结果
例:
需求:创建三个变量,将a与b作比较,并将较大值赋值给c
#include<iostream>
using namespace std;
int main()
{
int a=10;
int b=20;
int c=30;
c = (a > b ? a :b) ;
cout<< "c=" <<cendl;
system("pause");
return 0;
}
输出结果:c=20
逻辑:先判断表达式1的真假,事件为真则返回第二个表达式的值,为假则返回第三个表达式的值(三目运算符算作一个整体,最后返回的是一个变量并与外面的符号相连接)。
3、switch语句
作用:执行多条件分支语句
语法:
switch (表达式)
{
case 结果1:执行语句;break;
case 结果2:执行语句;break;
...
default : 执行语句 ; break ;
}
表达式的值与下面的情况一一匹配,匹配上就执行它后面的语句,都匹配不上则执行default的语句,但需要注意只要有一个情况匹配上,就会将这个case及其以下的case都执行直到遇到break。
例:
需求:给电影打分:
10--9分经典
8--7分非常好
6--5一般
5以下--烂片
提示用户给电影评分
根据用户输入的分数来提示用户最后的结果
#include<iostream>
using namespace std;
int main()
{
cout << "请给电影进行打分:" << endl;
int score = 0;
cin >> score;
cout << "您打的分数为:" << score << endl;
switch (score)
{
case 10: cout << "您认为是经典电影" << endl;
break;
case 9: cout << "您认为是经典电影" << endl;
break;
case 8: cout << "您认为电影非常好" << endl;
break;
case 7: cout << "您认为电影非常好" << endl;
break;
case 6: cout << "您认为电影一般" << endl;
break;
case 5: cout << "您认为电影一般" << endl;
break;
default: cout << "您认为这是烂片" << endl;
}
system("pause");
return 0;
}
输入:请给电影进行打分:2
输出结果:
您打的分数为:2
您认为这是烂片
switch较if的优劣:
switch:结构清晰,执行效率高;判断的时候只能是整型或者字符型,不可以是一个区间
二、循环结构
1、while语句
作用:满足循环条件,执行循环语句
语法:while ( 循环条件 ) { 循环语句; }
解释:当不满足循环条件时程序才跳出循环
例:
需求:
在屏幕中打印0--9十个数字
#include<iostream>
using namespace std;
int main()
{
int num = 0 ;
while ( num < 10 )
{
cout << num << endl ;
num ++ ;
}
system("pause");
return 0;
}
输出结果:
0
1
2
3
4
5
6
7
8
9
提升例题:猜数字
案例描述:系统随机生成一个1--100间的数字,玩家进行猜测,如果猜测,提示玩家数字过大或者过小,如果猜对则恭喜玩家胜利,并且退出游戏。
思路:1、系统生成随机数
2、玩家进行猜测
3、判断玩家的猜测
(1)猜对 退出游戏
(2)猜错 提示猜的结果,过大或者过小,重新返回第二步
#include<iostream>
#include<ctime> //time系统时间头文件(为了下面利用系统时间生成随机数)
using namespace std;
int main()
{
srand ( (unsigned int)time(NULL) ) ; //添加随机数种子,利用当前系统时间生成随机数,防止每次随机数都一样
int num = rand() % 100 + 1;
cout << "请输入猜测值:" << endl;
int val = 0;
while (1)
{
cin >> val;
//犯过的错误:假如这一步写到while外,则用户输入一个数之后进行该循环,因为循环内没有“再输入”这一步,所以会一直跑下去,持续输出一个结果
//判断玩家的猜测,重新返回第二步!
if (val > num)
{
cout << "猜测过大" << endl;
}
else if (val < num)
{
cout << "猜测过小" << endl;
}
else
{
cout << "恭喜您猜对了" << endl;
break; //break,可以利用该关键字来退出当前循环(只能加在循环的最后一步)
}
}
system("pause");
return 0;
}
补充知识:
1)生成伪随机数
rand()的用法:
rand()不需要参数,会返回一个从0到最大随机数的任意整数
int num = rand ()% n+a其中的a是起始值,n+a-1是终止值(计算机数数从0开始)
例:int num = rand () % 100表示产生0---99的随机数
int num = rand () % 100 + 1表示产生1---100的随机数
2)生成真随机数
原理:利用系统时间生成随机数以达到真正的“随机”
用法:
添加#include<ctime>头文件
在rand()前加随机数种子srand ( (unsigned int)time(NULL) ) ;以利用系统时间生成随机数
3)跳出一直为真的循环
在循环的最后加break;即可
while语句内嵌套if语句已犯错误:
若想在循环的某一步执行后执行什么操作,记得把该执行步骤放到循环内!(回看本题while)
2、do...while语句
语法:do{循环语句}while{循环条件};
注意:与while的区别在于do...while会先执行一次循环语句,再判断循环条件。
例:
#include<iostream>
using namespace std;
int main()
{
int num = 0 ;
do{
cout << num << endl ;
num ++ ;
}while ( num < 10 ) ;
system("pause");
return 0;
}
输出结果:
0
1
2
3
4
5
6
7
8
9
注意:do...while在while后加了;号,养成do后紧跟{,}后紧跟while的习惯,方便以后阅读。
区分while与do...while:
while相当于说:当满足...时,执行...
do...while相当于说:执行...直到不满足...时
提升例题:水仙花数
案例描述:水仙花数是指一个三位数,它的每个位上的数字的3次幂之和等于它本身,请用do...while语句求出所有3位数中的水仙花数。
例如:1^3+5^3+3^3=153
#include<iostream>
using namespace std;
int main()
{
int num = 100;
int a = 0;//个位
int b = 0;//十位
int c = 0;//百位
do{
a = num % 10;//获取个位
b = num / 10 % 10;//获取十位
c = num / 100;//获取百位
if (a*a*a+b*b*b+c*c*c==num)//是水仙花数才打印
{
cout << num << endl;
}
num++;
}while (num < 1000);
system("pause");
return 0;
}
输出结果:
153
370
371
407
补充知识:
获取数位上的数字:
个位:153%10=3
十位:153/10=15 15%10=5
百位:153/100=1
3、for语句
语法:for(起始表达式;条件表达式;末尾循环体){循环语句;}
注意:满足条件表达式之后先执行循环语句,结束后做末尾循环体的操作,判断是否满足条件再进行下一次循环。
例:利用for循环打印一行*
#include<iostream>
using namespace std;
int main()
{
for ( int num = 0; num < 10; num++ ) //完全可当作下面语句的控制语句
{
cout << "*" ;
}
system("pause");
return 0;
}
输出结果:**********
提升案例:敲七
案例描述:从1开始数到数字100,如果数字各位含有7,或者数字十位含有7,或者该数字是7的倍数,我们打印“喝”,其余的数字直接打印输出。
#include<iostream>
using namespace std;
int main()
{
for (int num = 1; num < 101; num++)
{
if (num % 7 == 0 || num % 10 == 7 || num / 10 % 10 == 7)
{
cout << "喝" << endl;
}
else
{
cout << num << endl;
}
}
system("pause");
return 0;
}
输出结果:
1
2
3
4
5
6
喝
8
9
10
11
12
13
喝
15
16
喝
18
19
20
喝
22
23
24
25
26
喝
喝
29
30
31
32
33
34
喝
36
喝
38
39
40
41
喝
43
44
45
46
喝
48
喝
50
51
52
53
54
55
喝
喝
58
59
60
61
62
喝
64
65
66
喝
68
69
喝
喝
喝
喝
喝
喝
喝
喝
喝
喝
80
81
82
83
喝
85
86
喝
88
89
90
喝
92
93
94
95
96
喝
喝
99
100
注意:num的初始值一定要赋1,赋0的话0%10=0也会打印“喝”。
4、嵌套循环
作用:在循环体中再嵌套一层循环,解决现实问题。
例:打印十行**********
#include<iostream>
using namespace std;
int main()
{
for (int num = 0; num < 10; num++) //可当作控制下面的循环执行几次
{
for (int num = 0; num < 10; num++)//内外num本应该取不一样的名字
{
cout << "*";
}
cout << endl; //打印好一行*之后换行
}
system("pause");
return 0;
}
输出结果:
**********
**********
**********
**********
**********
**********
**********
**********
**********
**********
注意:
(1)内外层循环的变量(本题是num)最好取不一样的名字。
(2)外层执行一次,内层执行一轮。
提升例题:乘法口诀表
案例描述:打印乘法口诀表
逻辑:观察到列数<=行数;口诀表每个元素乘号左边一侧都是列数,右边一侧都是行数,则:
每个元素=列数*行数=结果
#include<iostream>
using namespace std;
int main()
{
for (int a = 1; a <= 9; a++)//行数a
{
for (int b = 1; b <= a; b++)//列数b<=a时,完成构建当前元素并打印,由循环条件控制,使其构建出当前行所有元素
{
cout << b <<" * "<< a<<" = "<< a*b << " ";//最后的空格是为了让表格好看而已
}
cout << endl;
}
system("pause");
return 0;
}
5、跳转语句
作用:用于跳出循环结构或者选择结构。
break在不同语句的作用:
switch语句:终止case并跳出switch。
单个循环:跳出循环。
嵌套循环:跳出最近的内层循环语句。
单个循环break例:(对比3、嵌套循环例子)
#include<iostream>
using namespace std;
int main()
{
for (int num = 0; num < 10; num ++)
{
if (num == 5)
{
break;
}
cout << "*";
}
system("pause");
return 0;
}
输出结果:*****
嵌套循环break例:(与4、嵌套循环例子做对比)
#include<iostream>
using namespace std;
int main()
{
for (int num = 0; num < 10; num++) //可当作控制下面的循环执行几次
{
for (int num = 0; num < 10; num++)//内外num本应该取不一样的名字
{
if ( num == 5 )
{
break;
}
cout << "*";
}
cout << endl; //打印好一行*之后换行
}
system("pause");
return 0;
}
输出结果:
*****
*****
*****
*****
*****
*****
*****
*****
*****
*****
6、continue语句
作用:在循环语句中,跳过本次循环中尚未执行的语句,继续执行下一次循环
例:打印10以内所有奇数
#include<iostream>
using namespace std;
int main()
{
for (int num = 0; num < 10; num++)
{
if (num % 2 == 0)//偶数不输出,奇数输出
{
continue;
}
cout << num << endl;
}
system("pause");
return 0;
}
7、跳转语句goto
作用:无条件跳转语句
语法:goto 标记;
解释:如果标记的名称存在,执行到goto语句时,会跳转到标记的位置。
例:
#include<iostream>
using namespace std;
int main()
{
cout << "楠子我大儿1" << endl;
cout << "楠子我大儿2" << endl;
goto FLAG;
cout << "楠子我大儿3" << endl;
cout << "楠子我大儿4" << endl;
FLAG:
cout << "楠子我大儿5" << endl;
system("pause");
return 0;
}
注意:谨慎使用,飞雷神你把握不住!
C++数组:
1、概述:所谓数组,就是一个集合,里面存放了相同类型的数据元素
特点1:数组中的每个数据元素都是相同的数据类型
特点2:数组是由连续的内存位置组成的
定义方式:
1.数据类型 数组名 [ 数组长度 ];
2.数据类型 数组名 [ 数组长度 ];
3.数据类型 数组名 [ ] = { 值1, 值2... };
我们可以通过下标(从0开始索引)访问数组中的元素
方式1:创建数组并赋值
int arr [ 5 ] ;//定义一个长度为5的数组
//依次给数组中的元素赋值
arr [ 0 ] = 10;
arr [ 1 ] = 20;
arr [ 2 ] = 30;
arr [ 3 ] = 40;
arr [ 4 ] = 50;
方式2:利用循环更方便输出数组中的元素
int arr [ 5 ] = { 10,20,30,40,50 };//创建的同时已经给元素赋值
for ( int i = 0; i < 5 ; i++ )
{
cout << arr [ i ] << endl ;
}
输出结果:
10
20
30
40
50
未赋值的元素默认值为0
方式3:不必注明数组长度,但后面必须罗列所有元素
int arr [] = {90,80,70,60,50,40,30,20,10};
2、数组名的用法
用途:
1、统计整个数组在内存中的长度:sizeof(arr)
数组的内存长度除以元素的内存长度可以得到元素个数
例:
#include<iostream>
using namespace std;
int main()
{
int arr[5] = { 1,2,3,4,5 };
cout << "整个数组的内存空间为:"<<sizeof(arr) << endl;
cout << "每个元素所占的内存空间为:"<<sizeof(arr[0]) << endl;
cout << "元素个数为:" << sizeof(arr) / sizeof(arr[0]) << endl;
system("pause");
return 0;
}
输出结果:
整个数组的内存空间为:20
每个元素所占的内存空间为:4
元素个数为:5
2、获取数组在内存中的首地址:输出数组名就可输出首地址(一串16进制的数,可在数组名前加(int)强转成10进制),想查看首元素的地址时要在arr[ 0 ]前加&。
例:
#include<iostream>
using namespace std;
int main()
{
int arr [5] = { 1,2,3,4,5 };
cout << (int)arr << endl;
cout << (int) & arr[3] << endl;
system("pause");
return 0;
}
输出结果:
17824236
17824248
注意:数组名是常量,不可以进行赋值
3、冒泡排序
作用:最常用的排序算法,对数组内元素进行排序
1、比较相邻的元素,如果第一个比第二个大,就交换他们两个。
2、对每一对相邻元素做同样的工作,执行完毕后,找到第一个最大值。
3、重复以上的步骤,每次比较次数-1,直到不需要比较。
例:
#include<iostream>
using 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; j < 9 - i - 1; j++)//内层循环对比:次数=元素个数-轮数-1
{
if (arr[j] > arr[j + 1])//如果第一个数字比第二个数字大,则交换两元素
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;//temp作为一个临时变量储存arr[j]的值,避免了将arr[j+1}的值赋给arr[j]时将原值覆盖掉而丢失,再将temp的值赋给arr[j+1],实现数据交换
}
}
}
cout << "排序后:" << endl;
for (int i = 0; i < 9; i++)
{
cout << arr[i] << " ";
}
system("pause");
return 0;
}
输出结果:
排序前:
4 2 8 0 5 7 1 3 9
排序后:
0 1 2 3 4 5 7 8 9
补充知识:数据交换语句
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
注:temp作为一个临时变量储存arr[j]的值,避免了将arr[j+1}的值赋给arr[j]时将原值覆盖掉而丢失,再将temp的值赋给arr[j+1],实现数据交换。
一维数组提升应用案例:
1、五只楠子称体重
案例描述:在一个数组中记录了五只楠子的体重,如:int arr[5]={300,350,200,400,250};找出并打印最重的楠子的体重。
错误示范:
#include<iostream>
using namespace std;
int main()
{
int arr[5] = { 300,350,200,400,250 };
int i = 0;
for (int max = 0; i < 5; i++)
{
if (arr[i] > max)
{
max = arr[i];
}
}
cout << max<< endl;//程序报错,因为max只在for循环内被定义,cout找不到max是个啥
system("pause");
return 0;
}
程序报错,因为max只在for循环内被定义,cout找不到max是个啥
正确示范:
#include<iostream>
using namespace std;
int main()
{
int arr[5] = { 300,350,200,400,250 };
int max = 0;
for (int i = 0; i < 5; i++)//令下面的操作执行五圈
{
if (arr[i] > max)//找最大值的小算法
{
max = arr[i];
}
}//找到了最大值
cout << "最重的楠子体重为:"<<max<<"Kg" << endl;
system("pause");
return 0;
}
输出结果:
最重的楠子体重为:400Kg
4、二维数组定义方式
1、数据类型 数组名 [行数][列数];
2、数据类型 数组名 [行数][列数] = { {数据一,数据二} ,{数据三,数据四} };
3、数据类型 数组名 [行数][列数] = { 数据一,数据二,数据三,数据四 };
4、数据类型 数组名 [ ][列数] = { 数据一,数据二,数据三,数据四 };
建议利用第二种方式,更加直观,提高代码的可读性
法1:定义数组,给元素赋值并打印(打印使用嵌套循环以求简便)
#include<iostream>
using namespace std;
int main()
{
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] << endl;
}
}
return 0;
}
输出结果:
1
2
3
4
5
6
法2:不要忘记数组之间的“,”号
#include<iostream>
using namespace std;
int main()
{
int arr[2][3] =
{
{1,2,3},//别忘了这个逗号
{4,5,6}
};//非常直观展现出两行三列
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
cout << arr[i][j] <<" ";
}
cout << endl;
}
return 0;
}
输出结果:
1 2 3
4 5 6
法3:机器自动识别行和列
int arr[2][3] ={1,2,3,4,5,6};//机器自动识别行和列
法4:机器自动推算出行数(机器无法推算出列数因此不能空着)
int arr[][3] ={1,2,3,4,5,6};//机器自动推算出行数
5、二维数组名用途
用途:
1、查看占用内存空间大小:sizeof(arr[0])
#include<iostream>
using namespace std;
int main()
{
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;//列数=每行所占空间除以每个元素所占空间
return 0;
}
输出结果:
二维数组占用的内存空间为:24
二维数组第一行占用的内存空间为:12
二维数组第一个元素占用的内存空间为:4
二维数组行数为:2
二维数组列数为:3
2、查看二维数组的首地址:(int)&arr[0]
#include<iostream>
using namespace std;
int main()
{
int arr[2][3] =
{
{1,2,3},//别忘了这个逗号
{4,5,6}
};//非常直观展现出两行三列
cout << "二维数组的首地址为:" << arr << endl;
cout << "二维数组第一行的十进制首地址为:" << (int) arr[0] << endl;
cout << "二维数组第二行的十进制首地址为:" << (int)arr[1] << endl;//一二行之间差12个字符的空间也就是3个元素的空间
cout << "二维数组第一个元素的首地址为:" << (int)&arr[0][0] << endl;//不要忘记找元素地址要加“&”
cout << "二维数组第一个元素的首地址为:" << (int)&arr[0][1] << endl;//相邻元素差4个字符
return 0;
}
输出结果:
二维数组的首地址为:00F3F9D8
二维数组第一行的十进制首地址为:15989208
二维数组第二行的十进制首地址为:15989220
二维数组第一个元素的首地址为:15989208
二维数组第一个元素的首地址为:15989212
C++函数:
概述:将一段经常使用的代码封装起来,减少重复代码
一个较大的程序,一般分为若干个程序块,每个模块实现特定的功能。
1、函数的定义
五个步骤:
1)返回值类型
2)函数名
3)参数表列
4)函数体语句
5)return表达式
2、函数的调用
#include<iostream>
using namespace std;
int add(int sum1, int sum2)
{
int sum = sum1+sum2;
return sum;//return的就是函数值
}
int main()
{
int c;
int a=10;
int b=20;
c = add(10, 20);//这里就返回add(10,20)的函数值
cout << a << endl;
return 0;
}
注意:
其中a,b为实际参数,简称实参,函数定义时的参数并没有实际的值,所以就叫形式参数,简称形参。
注:如果函数不需要返回值,则声明的时候可以写void
3、函数类型
1)无参无返
2)有参无返
3)无参有返
4)有参有返
4、函数的声明
一个函数定义在被调用之后,则需要在调用前做声明,声明可以有多次,但函数定义只能有一次。
例:定义一个比较函数,打印元素的最大值
#include<iostream>
using namespace std;
//提前声明一个函数,声明可以写多次,但定义只能有一次
int max(int a, int b);
int main()
{
int a = 10;
int b = 20;
int c = max(a, b);
cout << "c="<<c<< endl;
return 0;
}
int max(int a, int b)//函数定义在主函数调用它之后,则调用前需要声明
{
return a > b ? a : b;//三目运算符简洁高效
}
输出结果:c=20
5、函数的分文件编写
作用:让代码结构更加清晰
编写步骤:
1)创建后缀名为.h的头文件
2)创建后缀名为.cpp的源文件
3)在头文件中写函数的声明
void swap (int a,int b);
4)在源文件中写函数的定义
void swap(int a,int b)
{
int temp = a;
a=b;
b=a;
cout<<"a="<<a<<endl;
cout<<"b="<<b<<endl;
}
注:头文件中声明过的函数,在源文件里则不需要在调用前做声明,但要记得在最前面写#include"函数名.h"
C++指针:
1、指针的基本概念
作用:通过指针间接访问内存
注:内存编号是从0开始记录的,一般用十六进制数字表示;可以利用指针变量保存地址(指针就是一个地址)
2、如何定义和使用一个指针
语法:数据类型*指针变量名;
注:p是一个地址,而*p是一个数据,这是通过解引用的方式(指针前加*号)来找到内存中的数据
例:
#include<iostream>
using namespace std;
int main()
{
int a = 10;
int* p;
p = &a;//不要忘记取址符号&
cout << "a的地址为:" << p << endl;
cout << "a的值为:" << *p << endl;
return 0;
}
输出结果:
a的地址为:00BCF920
a的值为:10
3、指针所占内存空间
在32位操作系统(x86)下,一个指针变量所占空间是4个字节;64位(x64)下占8个字节
4、空指针和野指针
空指针:指针变量指向内存中编号为0的空间
用途:初始化指针变量
注意:空指针指向的内存不可以访问(0~255之间的内存编号是系统占用的,因此不可以访问)
野指针:指针变量指向非法的(未申请的)内存空间
5、const修饰指针(帮助理解:const后面是啥,啥就被锁定了)
三种情况:
1)const修饰指针---常量指针
特点:指针的指向可以修改,但指针指向的值不可以改(不能通过指针更改内存中的值)
const int*p=&a;
*p=20;//错误
p=&b;//正确
释:const后面是int*p这个值,所以值被锁定不可更改,但地址可以更改
2)const修饰常量---指针常量
特点:指针的指向不可以改,指针指向的值可以改
int*const p=&a;//指针常量
*p=20;//正确
p=&b;//错误
释:const后面是p这个指针地址,所以地址被锁定不可更改,但值可以更改
3)const既修饰指针又修饰常量
const int*const p=&a;
*p=20;//错误
p=&b;//错误
6、指针和数组
作用:利用指针访问数组里的元素
#include<iostream>
using namespace std;
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* p = arr;//arr就是数组首地址
for (int i = 0; i < 10; i++)//让下面的语句执行十圈
{
cout << *p << " ";
p++;//令指针指向下一位
}
return 0;
}
输出结果:1 2 3 4 5 6 7 8 9 10
7、指针和函数
作用:利用指针做函数参数,可以修改实参的值
#include<iostream>
using namespace std;
void swap(int* p1, int* p2)//调用前先定义
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
int main()
{
int a = 10;
int b = 20;
swap(&a, &b);
cout << "a的值为:" <<a<< endl;
cout << "b的值为:" <<b<< endl;
return 0;
}
输出结果:
a的值为:20
b的值为:10
注:*p只有在定义时可以看作是地址(数据类型int一出现,其实就是在为*p这个值申请一段内存空间,所以将&a和&b赋给int*p是可行的)
综合提升案例:
案例描述:封装一个函数,利用冒泡排序,实现对整型数组{4,3,6,9,1,2,10,8,7,5}的升序排列
#include<iostream>
using namespace std;
void bubblesort(int* arr, int len)
{
for (int i = 0; i < len - 1; i++)
{
for (int j = 0; j < len -i-1; j++)
{
if (arr[j] > arr[j + 1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
void printArray(int* arr, int len)
{
for (int i = 0; i < len; i++)
{
cout << arr[i] << endl;
}
}
int main()
{
int arr[10] = { 4,3,6,9,1,2,10,8,7,5 };
int len = sizeof(arr) / sizeof(arr[0]);
bubblesort(arr, len);
printArray(arr, len);
return 0;
}
输出结果:
1
2
3
4
5
6
7
8
9
10
C++结构体:
概念:结构体属于用户自定义的数据类型,允许用户存储不同的数据类型
1、结构体的定义与使用
语法:struct 结构体名{结构体成员列表};
三种定义方式:
struct 结构体名 变量名
struct 结构体名 变量名={成员1值,成员2值...};
定义结构体时顺便创建变量
创建结构体:(struct关键字不可省略)
struct Student
{//成员列表
//姓名
string namel;
//年龄
int age;
//分数
int score;
};
创建变量:(struct关键字可省略)
方式一:
struct Student s1;
//通过一个“.”来访问结构体变量中的属性
s1.name = "张三";
s1.age = 18;
s1.score = 100;
cout << "姓名:" << s1.name << "年龄:" << s1.age << "分数:" << s1.score << endl;
//直接输出字符串,一般要添加“#include<string”头文件
输出结果:
姓名:张三年龄:18分数:100
方式二:(需要按照顺序)
struct Student s2 = { "李四",19,80 };
cout << "姓名:" << s2.name << "年龄:" << s2.age << "分数:" << s2.score << endl;
输出结果:
姓名:李四年龄:19分数:80
方式三:(不建议使用)
struct Student
{
//姓名
string name;
//年龄
int age;
//分数
int score;
}s3;//顺便创建变量s3
//通过定义的数据类型创建变量
int main()
{
s3.name = "张三";
s3.age = 18;
s3.score = 100;
cout << "姓名:" << s3.name << "年龄:" << s3.age << "分数:" << s3.score << endl;
输出结果:
姓名:张三年龄:18分数:100
注意:结构体变量利用操作符“.“来访问成员。
2、结构体数组
作用:将自定义的结构体放入到数组中方便维护
语法:struct 结构体名 数组名[元素个数]={ {},{},...{} }
#include<iostream>
using namespace std;
#include<string>
struct Student
{
//姓名
string name;
//年龄
int age;
//分数
int score;
};
int main()
{
struct Student stuArray[3] =
{
{"张三",18,100},
{"李四",28,99},
{"王五",38,66 }
};
for (int i = 0; i < 3; i++)
{
cout << "姓名:" << stuArray[i].name
<< "年龄:" << stuArray[i].name
<< "分数:" << stuArray[i].score << endl;
}
return 0;
}
输出结果:
姓名:张三年龄:张三分数:100
姓名:李四年龄:李四分数:99
姓名:王五年龄:王五分数:66
3、结构体指针
作用:通过指针访问结构体中的成员
利用操作符->可以通过结构体指针访问结构体中元素的值。
#include<iostream>
using namespace std;
#include<string>
struct Student
{
string name;//姓名
int age;//年龄
int score;//分数
};
int main()
{
struct Student s = { "张三",18,100 };
struct Student* p = &s;//注意前后数据类型一致
cout << "姓名:" << p->name << "年龄:" << p->age << "分数:" << p->score << endl;
return 0;
}
输出结果:
姓名:张三年龄:18分数:100
4、结构体嵌套结构体
作用:结构体中的成员可以是另一个结构体
例:
#include<iostream>
using namespace std;
#include<string>
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
<< endl;
return 0;
}
输出结果:
老师姓名:老王老师编号: 10000老师年龄:50老师辅导的学生姓名:张三学生年龄:20学生考试分数为:60
在结构体中访问子结构体属性的语法:
t.子结构体名.对应属性
5、结构体做函数参数
作用:将结构体作为参数向函数中传递
传递方式有两种:
1)值传递:形参不改变实参
2)地址传递:形参改变实参跟着改变
值传递例:
#include<iostream>
using namespace std;
#include<string>
struct student//定义结构体
{
string name;//姓名
int age;//年龄
int score;//分数
};
void printstudent(struct student stu)//定义一个打印函数
{
cout << "子函数中 姓名:" << stu.name
<< "年龄:" << stu.age
<< "分数:" << stu.score
<< endl;
}
int main()
{
struct student stu;
stu.name = "张三";
stu.age = 20;
stu.score = 100;
printstudent(stu);
cout << "在main函数中打印 姓名:" << stu.name
<< "年龄:" << stu.age
<< "分数:" << stu.score
<< endl;
return 0;
}
输出结果:
子函数中 姓名:张三年龄:20分数:100
在main函数中打印 姓名:张三年龄:20分数:100
若在printstudent函数中做stu.age=100的操作,子函数printstudent中的stu.age会发生改变,但是main函数中的stu.age=20是不受子函数影响的。其实形参中的数据是由主函数中的实参数据拷贝后再赋给子函数形参的,所以形参如何变,实参也不会受影响。
void printstudent(struct student stu)//定义一个打印函数
{
stu.age = 100;
cout << "子函数中 姓名:" << stu.name
<< "年龄:" << stu.age
<< "分数:" << stu.score
<< endl;
}
输出结果:
子函数中 姓名:张三年龄:100分数:100
在main函数中打印 姓名:张三年龄:20分数:100
即:形参(子函数中的stu.age=100)不改变实参(主函数中的stu.age=20)
地址传递例:
#include<iostream>
using namespace std;
#include<string>
struct student//定义结构体
{
string name;//姓名
int age;//年龄
int score;//分数
};
void printstudent(struct student *p)//定义一个打印函数
{
cout << "子函数中 姓名:" << p->name
<< "年龄:" << p->age
<< "分数:" << p->score
<< endl;
}
int main()
{
struct student stu;
stu.name = "张三";
stu.age = 20;
stu.score = 100;
printstudent(&stu);
cout << "在main函数中打印 姓名:" << stu.name
<< "年龄:" << stu.age
<< "分数:" << stu.score
<< endl;
return 0;
}
输出结果:
子函数中 姓名:张三年龄:20分数:100
在main函数中打印 姓名:张三年龄:20分数:100
若在printstudent函数中添加更改age的操作
void printstudent(struct student *p)//定义一个打印函数
{
p->age = 100;
cout << "子函数中 姓名:" << p->name
<< "年龄:" << p->age
<< "分数:" << p->score
<< endl;
}
则输出结果变为:
子函数中 姓名:张三年龄:100分数:100
在main函数中打印 姓名:张三年龄:100分数:100
即:实参(stu.age=20)跟着形参(p->age)改变
6、结构体中const使用场景
作用:用const来防止误操作
若用值传递需要拷贝的数据量非常大,则应该选择地址传递来减小内存的使用(一个指针才4字节),但由于地址传递有形参改变实参的特点,为了防止误操作,可以用const来锁定值(常量指针)。加入const后,一旦有修改数值的操作系统就会报错,从而防止误操作。
void printstudent(const struct student *p)
C++中内存的分区模型:
一、代码区:存放程序的二进制代码,由操作系统进行管理
二、全局区:存放全局变量和静态变量以及常量
三、堆区:由编译器自动·分配释放,存放函数的参数值,局部变量等
四、栈区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
划分区域的意义:不同区域存放的数据,赋予不同的生命周期,给予我们更大的灵活
过程:
程序编译之后,生成了exe可执行程序,未执行该程序前分为两个区域
代码区:
存放cpu的机器指令
代码区是共享的,目的在于频繁被执行的程序只存一份,节省资源
代码区是只读的,使其只读的原因是防止程序意外地修改了他的指令
全局区:
全局变量和静态变量存放在此
还包含了常量区,字符串常量和其他常量也存放在此
该区域的数据在程序结束后由操作系统释放
存放在全局区中的数据:
1、全局变量
2、静态变量-----static关键字
3、字符串常量
4、const修饰的全局变量
栈区:存放函数的参数值,局部变量等
注意:不要返回局部变量的地址,因为栈区的数据由编译器管理开辟和释放(返回地址时该内存被我们释放了,就无法恢复但此次的使用是没有问题的)
堆区:
关键字new:将数据开辟到堆区
手动开辟语法:用new创建的数据返回的是一个地址
int*p = new int(10);
注:指针p(存的是一个地址)本质上还是局部变量,放在栈上,但是数据本身存放在堆区
开辟数组语法:
int*arr = new int [10];
返回的是这个数组的首地址
手动释放语法:delete
delete p;
手动释放数组:
delete [] arr;