进阶内容
1.1程序流程结构
单行if语句
语法:if (条件表达式) {达成条件时执行的代码;}
例:if (1 = 1) {cout << "true";}
输出:true
多行if语句
语法:if (条件表达式)
{
达成条件时执行的代码;
}
else
{
未达成条件时执行的代码;
}
例:
if (1 != 1)
{
cout << "true";
}
else
{
cout << "false";
}
输出:false
多条件if语句
语法:if (条件表达式)
{
达成条件时执行的代码;
}
else if (条件表达式)
{
达成条件时执行的代码;
}
....
else
{
未达成条件时执行的代码;
}
例:
int a = 3;
if ( a = 1 )
{
cout << "a=1";
}
else if ( a = 2 )
{
cout << "a=2";
}
else if ( a = 3 )
{
cout << "a=3";
}
else
{
cout << "Unkown";
}
输出:a=3
switch语句
语法:
switch (表达式)
{
case 结果1:
要执行的语句;
break;
case 结果2:
要执行的语句;
break;
....
default:
要执行的语句;
break;
}
例:
cout << "请输入分数:";
int tz;
cin >> tz;
switch (tz)
{
case 10:
cout << "经典";
break;
case 7:
cout << "好";
break;
case 5:
cout << "很蓝的啦";
break;
default:
cout << "unkown";
break;
}
输入10会输出经典,以此类推
while语句
语法:while (循环条件) {循环语句}
说明:满足条件,开始循环
示例:
int a = 10;
while (a > 0)
{
cout << a-- << endl;
}
循环输出10到0的数字
课后练习:猜数字
题目要求:
案例描述:系统随机生成一个1到100之间的数字,玩家进行猜测,如果猜错,提示玩家数字过大或过小,如果猜对恭喜玩家胜利,并且退出游戏。
提示:
- rand() % 最大数字 + 1;可生成1-最大数字范围内的整数
- 在rand()生成随机数前加入 srand((unsigned int)time(NULL)); 可以利用时间戳防止每次生成都是一样的数值
- 需要包含ctime头文件
答案:↓
srand((unsigned int)time(NULL));
int num = rand() % 100 + 1;
num = rand() % 100 + 1;
cout << num << endl;
//cout << time(NULL) << endl; 时间戳
cout << "请输入一个1~100的值进行猜测";
int value = 0;
cin >> value;
while (true)
{
if (value > num)
{
cout << "值太大,请重新输入:";
cin >> value;
}
else if (value < num)
{
cout << "值太小,请重新输入:";
cin >> value;
}
else if (value = num)
{
cout << "恭喜你答对了!";
break;
}
}
do{...} while(...)
语法:do{循环语句} while(循环条件);
说明:满足循环条件,执行循环语句语法:do{循环语句} while(循环条件);
注意:与while的区别在于do...while会先执行一次循环语句,再判断循环条件
示例:
bool tj = false;
do
{
if (tj == true)
{
cout << "条件达成" << endl;
break;
}
else
{
cout << "条件未达成,反转参数" << endl;
tj = !tj;
}
} while (tj == true);
该程序会输出:
条件未达成,反转参数
条件达成
课后练习:水仙花数
- tips:水仙花数指一个三位数,他每个数位上的数字三次幂之和等于其本身,如:153,个位:3,十位:5,百位:1,3 ^ 3 + 5 ^ 3 + 1 ^ 3 = 153
- c++中整数相除只能得到整数
- 次幂使用pow()函数进行计算,例:10的5次幂 == pow(10,5);
- 如何获取数字的各个数位?
获取个位:数字 % 10
获取十位:数字 / 10
获取百位:数字 / 100
答案:↓
int num = 100;
int bai;
int shi;
int ge;
do
{
bai = num / 100;
shi = num / 10 % 10;
ge = num % 10;
bai = pow(bai, 3);
shi = pow(shi, 3);
ge = pow(ge, 3);
;
if (bai + shi + ge == num)
{
cout << num << endl;
}
num++;
} while (num < 1000);
cout << "运算完成."<<endl;
for语句
语法:for(起始表达式;条件表达式;末尾循环体){循环语句;}
说明:只有在条件表达式成立的时候才会执行末尾循环体和循环语句
示例:倒叙输出输出1-10
for (int i = 10; i > 0 ; i--)
{
cout << i << endl;
}
教学案例:从1开始数到数字100,如果数字个位含有7,或者数字十位含有7,或者该数字是7的倍数,我们打印敲桌子,其余数字直接打印输出。
答案:↓
for (int i = 1; i <= 100; i++)
{
if ( i % 10 == 7 ||i / 10 % 10 == 7 || i % 7 == 0)
{
cout << "敲桌子:" << i << endl;
}
else
{
cout <<i << endl;
}
}
课后练习:打印星图
说明:使用任意一种循环,在屏幕上打印一个星号矩阵
for (int a = 0; a <= 10; a++)
{
for (int i = 0; i <= 20; i++)
{
if (i != 20)
{
cout << "*";
}
else
{
cout << "*" << endl;
}
}
}
效果:
*********************
*********************
*********************
*********************
*********************
*********************
*********************
*********************
*********************
*********************
*********************
课后练习:打印乘法口诀表
说明:按照乘法口诀表的格式打印乘法口诀表
答案:↓
for (int j = 1; j <= 9; j++)
{
for (int x = 1; x <= j; x++)
{
if (j == x)
{
printf("%d * %d = % d \n", x, j, j* x);
}
else
{
printf("%d * %d = % d \t", x, j, j* x);
}
}
}
break语句
说明:break用于退出循环语句和switch语句,如:do...while,while,for,switch
例:
cout << "请输入一个1~100的值进行猜测";
int value = 0;
cin >> value;
while (true)
{
if (value > num1)
{
cout << "值太大,请重新输入:";
cin >> value;
}
else if (value < num1)
{
cout << "值太小,请重新输入:";
cin >> value;
}
else if (value = num1)
{
cout << "恭喜你答对了!";
break;
}
}
continue语句
说明:当在循环语句中出现continue时,程序立刻终止本次循环不在向下执行
注意:该语句只能在循环中使用!!!
例:
for (int i = 0; i < 10; i++)
{
printf("a %d\n",i);
if (i == 5)
{
continue;
}
printf("b %d\n",i);
}
当i=5的时候for循环将会输出一个数字5,然后停止本次循环进行下一次循环
程序输出:
a 0
b 0
a 1
b 1
a 2
b 2
a 3
b 3
a 4
b 4
a 5 //注意这里只有一个5
a 6
b 6
a 7
b 7
a 8
b 8
a 9
b 9
goto语句
说明:直接无条件跳转到标记处
注意:必须在同一个函数内使用才能生效!标签由一个标识符和冒号组成,不需要分号结尾
例:
goto b;
a:
printf("aaa\n");
b:
printf("bbb\n");
正常情况下会按顺序执行,但是遇到goto后就会在goto行直接跳转到标签b
1.2.1 一维数组的定义与使用
定义方式
- 数据类型 数组名[数组长度];
- 数据类型 数组名[数组长度] = { 值1,值2 ...};
- 数据类型 数组名[] = { 值1,值2 ...};
注意事项
- C++的数组下标从0开始
- 数据类型必须相同
- 如果在初始化数组的时候没有全部填写完未赋值部分将会用0代替
- 不定长数组在初始化的时候必须赋初值
数组名的作用
可以统计整个数组在内存中的长度
可以获取数组在内存中的首地址
- 使用数组总大小除以数组的单个元素大小可以获取到数组中元素个数:int arr[] = {1,1,1,1,1};int arrsize = sizeof(arr) / sizeof(arr[1]);
- 直接输出地址名可以得到数组在内存中的首地址
- 取数组元素在内存中的首地址:&数组名[下标]
- 数组的内存首地址和数组内元素0的首地址是重叠的
注意:数组的名字是常量不能进行赋值
代码:
int test[10];
for (int i = 0; i < 10; i++)
{
test[i] = i;
}
cout << "数组的长度为:" << sizeof(test[1]) << endl;
cout << "数组的元素个数:" << sizeof(test) / sizeof(test[1]) << endl;
cout << "数组的首地址为:0x" << test << endl;
cout << "数组元素1的首地址为:0x" << &test[0] << endl;
输出:
数组的长度为:4
数组的元素个数:10
数组的首地址为:0x0113F88C
数组元素1的首地址为:0x0113F88C
课后练习:五只小猪比体重
要求:在一个数组中记录了五只小猪的体重,如: int arr[5] = {300,350,200,400,250};找出并打印最重的小猪体重。
思路:可以设置一个最大值,然后使用for循环逐一比对找出最大的元素
答案:↓
int pig[5] = {200,500,350,710,110};
int max = 0;
for (int j = 0; j <= 5; j++)
{
if (pig[j] > max)
{
max = pig[j];
}
}
cout << "最重的小猪是:" << max << endl;
课后练习:数组元素倒置
要求:请声明一个5个元素的数组,并且将元素逆置.(如原数组元素为:1,3,2,5,4;逆置后输出结果为:4,5,2,3,1);
解题技巧:我们可以先创建一个临时数组,然后使用for对数组进行倒叙输出并赋给临时数组,最后再用for将临时数据正式赋值给原数组
答案:↓
//数组元素倒置
int data[] = {1,2,3,4,5};
int j = 0;
const int num = sizeof(data) / sizeof(data[1]);
int tmp[num];
for (int i = 0; i <= (num - 1); i++)
{
printf("现行数组元素%d的值为%d\n",i,data[i]);
}
for (int i = (num - 1); i >= 0 ; i--)
{
tmp[j] = data[i];
j++;
}
for (int i = 0; i <= (num - 1); i++)
{
data[i] = tmp[i];
}
for (int i = 0; i <= (num - 1); i++)
{
printf("现行数组元素%d的值为%d\n", i, data[i]);
}
课后练习:一维数组:冒泡排序算法
简述:对数组中的数字进行大小排序
要求:随便写一个包含九个不重复整数元素的数组,然后对其进行从小到大排序
解题技巧:我们可以创建一个临时变量,在循环过程中保存下一个数组元素以用于数组的元素交换
答案:↓
//冒泡排序
int numa[] = { 5,7,2,6,9,8,1,3,4,10 };
const int numz = sizeof(numa) / sizeof(numa[1]);
int tmpb = 0;
for (int j = 0; j <= numz; j++)
{
for (int i = 0; i <= numz - 2; i++)
{
if (numa[i] > numa[i + 1])
{
tmpb = numa[i];
numa[i] = numa[i + 1];
numa[i + 1] = tmpb;
}
}
}
//输出数组元素以便观察
for (int i = 0; i <= numz - 1; i++)
{
printf("numa数组元素%d的值为%d\n", i, numa[i]);
}
1.2.2 二维数组的定义与使用
概述
二维数组就是在一维数组上,多加一个维度。
二维数组定义方式
- 数据类型 数组名[行数] [列数];
- 数据类型 数组名[行数] [列数] = {{数据1,数据2},{数据3,数据4 }};
- 数据类型 数组名[行数] [列数] = {数据1,数据2,数据3,数据4};
- 数据类型 数组名[ ] [列数] = {数据1,数据2,数据3,数据4};
注意:二维数组下标仍然为0
示例:
int arr1[2][2];
int arr2[2][2] = { {1,2},{3,4} };
int arr3[2][2] = { 1,2,3,4 };
//使用该方法计算机会按顺序自动分配数据
int arr4[][4] = { 1,2,3,4 };
//使用该方法计算机会自动识别行数
二维数组的输出:
int arr2[4][4] =
{
{1,2,1,2},
{3,4,3,4},
{5,6,5,6},
{7,8,7,8}
}; //推荐使用该数组形式
for (int i = 0; i < 4; i++)
{
//外层打印行数
for (int j = 0; j < 4; j++)
{
//内层打印列数
printf("%d\t", arr2[i][j]);
}
cout << "\n";
}
输出结果:
1 2 1 2
3 4 3 4
5 6 5 6
7 8 7 8
二维数组名
示例:
int arr2[4][4] =
{
{1,2,1,2},
{3,4,3,4},
{5,6,5,6},
{7,8,7,8}
};
cout << "二维数组占用的空间为:" << sizeof(arr2) << endl;
cout << "二维数组的首地址为:" << arr2 << endl;
cout << "二维数组的首列地址为:" << arr2[0] << endl;
cout << "二维数组的首行地址为:" << &arr2[0][0] << endl;
cout << "二维数组第一行占用的空间为:" << sizeof(arr2[0]) << endl;
cout << "二维数组第一个元素占用的空间为:" << sizeof(arr2[0][0]) << endl;
cout << "二维数组共有元素:" << sizeof(arr2) / sizeof(arr2[0][0]) << endl;
输出结果:
二维数组占用的空间为:64
二维数组的首地址为:012FF758
二维数组的首列地址为:012FF758
二维数组的首行地址为:012FF758
二维数组第一行占用的空间为:16
二维数组第一个元素占用的空间为:4
二维数组共有元素:16
tips:可以通过使用第一行的内存空间大小除以单个元素的空间大小获取总列数
课后练习:考试成绩统计
要求:
现有张三、李四、王五三人,三人成绩分别为:
张三:100,100,100
李四:90,50,100
王五:60,70,80
请使用二维数组储存三人成绩并计算每个人的总成绩并打印
答案:↓
int cj[3][3] =
{
{100,100,100},
{90,50,100},
{60,70,80}
};
string names[3] = {"张三","李四","王五"};
int tmp = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
tmp += cj[i][j];
}
cout << names[i] << ":" << tmp << endl;
tmp = 0;
}
2.1 函数
2.1.1 概述
将一段经常使用的代码封装起来,减少重复代码,一个较大的程序,一般分为若干个程序块,每个模块实现特定的功能。
2.2.1 函数的定义
函数的定义一般主要有5个步骤:
- 返回值类型
- 函数名
- 参数表列
- 函数体语句
- return表达式
注意:函数要写在程序如入口函数(main)的上方
语法:
返回值类型 函数名(参数列表)
{
函数体语句;
return 表达式;
}
例:
int function1(int a,int b)
{
cout << a << b <<endl;
return 0;
}
2.2.2 值传递
定义:
- 形参:在函数创建时时用的参数
- 实参:在函数被调用时实际传入的值
- 所谓值传递,就是函数调用时实参将数值传入给形参
注意:
2.3.1 函数的常见形式
常见的函数形式有4种:
示例:
//有参有返
int js(int a, int b)
{
return a + b;
}
//有参无返
void jh(int a,int b)
{
swap(a,b);
}
//无参有返
int ab()
{
return time(NULL);
}
//无参无返
void ad()
{
if (time(NULL) % 2 == 0)
{
cout << "OK" << endl;
}
}
2.3.2 函数的定义
作用:告诉编译器函数名称及如何调用函数。函数的实际主体可以单独定义。
例:
//声明
int ab(int c, int a);
//无参有返
int ab(int a,int b)
{
int tmp = a + b;
return tmp;
}
2.4.1 函数的分文件编写
作用:让代码结构更加清晰函数分文件编写一般有4个步骤
- 创建后缀名为.h的头文件
- 创建后缀名为.cpp的源文件
- 在头文件中写函数的声明
- 在源文件中写函数的定义
注意:函数需要的相关头文件只需要在包含在自定义的头文件中即可
例:
源文件:
#include <iostream>
#include "swap.h"
using namespace std;
int main()
{
int c = 1;
int d = 2;
swapa(c,d);
return 0;
}
新添加的cpp文件:
#include "swap.h"
void swapa(int a,int b)
{
int tmp;
tmp = a;
a = b;
b = tmp;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
头文件:
#include <iostream>
using namespace std;
//声明函数swapa
void swapa(int a, int b);
执行结果:
a = 2
b = 1
3.1.1 指针
3.1.2 指针的基本概念
指针的作用:可以通过指针间接访问内存
- 内存编号是从0开始记录的,一般用十六进制数字表示
- 可以利用指针变量保存地址
3.2.1 指针的定义与使用
指针定义语法:数据类型 * 指针变量名;
示例:
#include <iostream>
using namespace std;
int main()
{
int a = 10;
int* p;
//让指针记录变量a的地址
p = &a;
cout << "变量a的内存地址:" << &a << endl;
cout << "指针记录的地址:" << p << endl;
//使用指针
//可以通过解引用的方式找到指针指向的内存
//指针前加 * 代表解引用,找到指针指向的内存
*p = 1500;
cout << "变量a:" << a << endl;
cout << "指针:" << *p << endl;
}
程序输出:
变量a的内存地址:001AF8A0
指针记录的地址:001AF8A0
变量a:1500
指针:1500
3.2.2 指针所占内存空间
- 在32位程序下指针占4字节内存
- 在64位程序下指针占8字节内存
- 指针大小不分指针数据类型
示例:
cout << "指针大小: " << sizeof(int*) << endl;
3.2.3 空指针
空指针:指针变量指向内存中编号为0的空间
用途:初始化指针变量
注意:空指针指向的内存是不可以访问的
示例:
int* p = NULL;
3.2.4 野指针
野指针:指针变量指向非法的内存空间
例:
int* b = (int*)0x0000004E31CFF644;
cout << *b << endl;
//使用会报错
注意:野指针不可被使用,在实际应用中要避免野指针的出现和使用
3.2.5 const修饰指针
常量指针:
特点:指针的指向可以更改但是指针指向的值不可修改
使用const修饰指针相当于把解引用的指针值作为一个常量,其解引用的值不可更改,但是实际变量的值仍可通过原变量修改,但不能通过指针解引用更改
人话:你可以换名,但是你人的本质不能改
const int * b;
int c = 100;
b = &c;
c = 200;
*b = 300;
//这句代码会报错,因为指针b已经被const修饰过了,其指向的值不可更改
指针常量:
声明方法:int * const 指针常量名 = 常量值;
特点:指针的指向不可以改,但是指针指向的值能改
例:
int c = 100;
int* const j = &c;
int a = 200;
c = 100;
*j = 1200;
j = &a;
//这句代码会报错,因为指针j已经被声明为常量,其指向不可修改
tips:看const右侧紧跟着的是指针还是常量,是指针就是常量指针,是常量就是指针常量
3.2.6 指针和数组
例:
int arr[10] = {0,1,2,3,4,5,6,7,8,9};
int* ar = arr;
cout << "数组的第一个元素为:" << *ar << endl;
ar++; //将指针向后偏移4个字节
cout << "数组的第二个元素为:" << *ar << endl;
使用for循环和指针遍历数组:
int arr[10] = {0,1,2,3,4,5,6,7,8,9};
int* ar = arr;
for (int i = 0; i < 10; i++)
{
cout << "数组中的第" << i + 1 << "个数据为:" << *ar << endl;
ar++;
}
3.2.7 函数和指针
例:
void swap01(int* a, int* b)//直接进行地址传递,地址传递可以修饰实参
{
int tmp = *b;
*b = *a;
*a = tmp;
}
int main()
{
int k = 10;
int r = 20;
swap01(&k, &r);
cout << "k:" << k << endl;
cout << "r:" << r << endl;
return 0;
}
程序输出:
k:20
r:10
课后练习:封装一个函数,利用冒泡排序,实现对整型数组的升序排序
答案:↓
#include <iostream>
using namespace std;
void px(int * arr,int len)
{
int tmp = 0;
for (int j = 0; j < len; j++)
{
for (int i = 0; i < len - 1 ; i++)
//需要-2,因为不减会下标出界
//i = 0所以len - 1循环了4次
{
if (arr[i] > arr[i + 1])
{
tmp = arr[i + 1];
arr[i + 1] = arr[i];
arr[i] = tmp;
}
}
}
}
int main()
{
int arra[] = { 8,1,5,10,6 };
int len = sizeof(arra) / sizeof(arra[0]);
px(arra,len);
for (int i = 0; i < len; i++)
{
cout << arra[i] << endl;
}
return 0;
}