c++基础部分
黑马程序员课程学习笔记
visual studio环境搭建
安装
- 下载community版本
- 勾选c++桌面开发
- 完成安装,界面如下

快捷键
运行:F5
调试:F10
新建项:CTRL +shift+ A
注释:Ctrl+K,再按CTRL+/
不习惯可以自己在设置》选项》键盘里面修改,搜索“注释”,选择文本编辑器,按下想要的键位,最后记得点击分配,才能生效
hello world
案例中的system(pause)还是需要的,如果2019在调试后自动关闭控制台,就必须加上这个
- 创建一个新项目》空项目
- 右击源文件,添加新建项,快捷键CTRL+shift+A

- hello world
#include <iostream>
using namespace std;
int main() {
cout << "hello world" << endl;
//system("pause");//19版本好像不需要这个
return 0;
}
- 快捷键F5开始运行
常量
两种定义方式,const优先
#include <iostream>
using namespace std;
/*定义常量的作用:防止变量值被修改
定义方式:
1.宏定义
2.定义变量时前缀const
const优先*/
#define week 7
const int month = 30;
int main() {
cout << "一周" << week << "天" << endl;
cout << "一月" << month << "天" << endl;
return 0;
}

小数
- 默认情况下,都只显示小数点后6位。
- 科学计数法,使用较少
double a = 5e2;//5*10^2
cout << "a=" << a <<endl;
double b = 5e-2;//5*10-2
cout << "b=" << b << endl;
字符型
char ch = 'a';
cout << "ch = " <<ch<< endl;
cout << "ch的ascll码为" << (int)ch << endl;//强转换查看对应的ASCLL码
字符串 string转换int
- C语言风格
atoi(string.c_str())=int
即string类型的字符串,调用.str()变成C语言分割字符串,再利用atoi变成int类型,实现string到int的转换`
- C++
注意时双引号,可用于存储文件路径名或者窗口名
//1.c语言风格:char 变量名[] = ""
char ch[] = "abcd";
//输出完整字符串
cout << "ch=" << ch << endl;
//输出一个元素
cout << "ch[2]=" << ch[2] << endl;
//2.c++风格:需要包含头文件string,vs19好像不用
//string 变量名 = ""
string str = "1234";
cout << "str=" << str << endl;
cout << "str第一个元素" << str[0] << endl;
bool和cin
只有true和false两种状态,可以作为开关使用
一个例子,定义的是bool型,如果被赋予0和1之外的值,会出现越界的错误,一直在循环,没有cin的机会,还有就是判断用的和输出用的最好分开,防止功能耦合,by黄州彭于晏
#include <iostream>
using namespace std;
/*bool类型,只有true和false,且非0即1*/
int main() {
bool flag = 1;
while (flag) {
cout << "\n请输入key的值" << endl;
cin >> flag;
cout << "key=" << flag << endl;
}
cout << "key5555555=" << flag << endl;
return 0;
}
这里的flag只能输入0或者1,否则就死循环,无法再输入,int型输入字符型,也是如此
a++、++a以及a+=2
- a++:后置递增,先运算,在加一
- ++a:前置递增,在加一,再运算
- a+=2,即a=a+2;

选择结构
if、else if、else
如果有多个选择条件,应该是if + eles if + else if + else,如果有多个if,最后的else会与最近的if匹配,例如下面的
#include <iostream>
using namespace std;
int main() {
cout << "请在abc之间选择一个字母输入" << endl;
char letter;
cin >> letter;
if (letter == 'a') {
cout << "输入了a" << endl;
}
if (letter == 'b') {//应该是else if
cout << "输入了b" << endl;
}
if (letter == 'c') {//应该是else if
cout << "输入了c" << endl;
}
else//这里是与上一个c匹配,如果输入的不是c,就会执行
{
cout << "输入错误" << endl;
}
return 0;
}

三目运算符
通用格式:表达式1?表达式2:表达式3;
即:表达式1为真,则执行表达式2,否则执行表达式3;
A = (B > C ? B : C);//如果B>C,则A=B,否则A=C;
(B > C ? B : C)= A;//A的值赋给B和C中大的那一个
switch 注意break和return的区别
switch语句特点:
- 结构清晰,效率比if高,
- case后面只能是一个整型或者字符型,不能是一个区间,如果执行语句过长,要加上{},另外,如果出现了初始化由case标签跳过的错误,也需要把case后面的执行语句{}
- default表示不满足前面所有的条件
- 注意case后面的冒号,以及每个分支后面加上break,如果不加break,会出现执行多项case的错误
#include <iostream>
using namespace std;
//break作为case的结束标志,如果没有break,该case和下面所有没有break的case都会执行
//一般来说,break每项都要加上
void test01()
{
cout << "请输入一个分数,10分制度" << endl;
int source;
cin >> source;
switch (source)
{
case (10):
cout << "优" << endl;
//break;
case (9):
cout << "良" << endl;
break;
case (8):
cout << "中" << endl;
//break;
default:
cout << "差" << endl;
//break;
}
}
//break只是结束本次case,并不会跳出死循环,而return则是直接结束了函数
void test02()
{
int i = 0;
while (i < 10)
{
cout << "第" << i << "次循环" << endl;
switch (i)
{
case 0:
cout << "——" << i << endl;
//break;
case 1:
cout << "——" << i << endl;
//break;
case 2:
cout << "——" << i << endl;
break;
case 3:
cout << "——" << i << endl;
//break;
cout << "遇到了return" << endl;
return;//这里的return不是退出死循环,而是结束了整个函数
case 4:
cout << "——" << i << endl;
break;
case 5:
cout << "——" << i << endl;
break;
default:
cout << "--x" << endl;
break;
}
i++;
}
//上面的死循环+return 都没有执行到这一步,就由return退出了函数
cout << "循环结束了,循环次数"<< i << endl;
system("pause");
system("cls");
}
int main() {
//test01();
cout << "test02开始" << endl;
test02();
cout << "test02结束" << endl;
system("pause");
return 0;
}
循环结构
while循环与随机数 解决了while循环中非法输入后死循环的问题
- 案例:猜数字,0到100.
- 要点:生成一个随机数,
#include <ctime>
srand((unsigned int)time(NULL)); //与rand()搭配,生成随机数
int i = rand() % 101;//没有srand就是伪随机数
- 源码
#include <iostream>
#include <ctime>//系统时间头文件
using namespace std;
////解决了int输入字符串后死循环的问题
//cin.clear();
//cin.ignore(numeric_limits<streamsize>::max(), '\n');
void test01()
{
int i = rand() % 101;//没有srand就是伪随机数
//cout << "i=" << i << endl;
int guess;
cout << "请在0到100之间猜一个整数" << endl;
int count = 1;//记录游戏次数
bool flag = true;//判断是否猜测对的标志
int end = 10;//设置最大的猜测次数
while (1)
{
cin >> guess;
//先判断cin是否输入了整型,
//true
if (cin.good())
{
if (i < guess)
{
cout << "猜大了" << endl;
}
else if(i>guess)
{
cout << "猜小了" << endl;
}
else
{
break;
}
}
//非法输入,
else
{
//提示用户非法输入
cout << "你的输入有误,请重新猜一个整数" << endl;
//开始施法,防止死循环
cin.clear();//消除错误状态
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
cout << "你还有" << end - count << "次机会,";
cout << "请再次输入你猜的数字" << endl;
count++;
if (count == end)
{
cout << "游戏结束,正确答案是" << i << endl;
flag = 0;//失败,更新标志
break;
}
}
if (flag)
{
cout << "恭喜你猜对了,一共猜了" << count << "次" << endl;
}
}
void test02()
{
int s=1;
while (1)
{
cout << "请输入一个整数" << endl;
cin >> s;
//判断输入的是否是正确类型
if (cin.good())
{
cout <<"good_"<< s << endl;
if (s == 0) break;
}
else
{
//这里的s是0
cout << "error_" << s << endl;
//这两个必须配合使用
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(),'\n');
}
}
}
int main() {
//根据时间生成随机数种子,与rand搭配使用。
srand((unsigned int)time(NULL));
//猜数字
//test01();
//关于cin
test02();
system("pause");
return 0;
}
do while、取模和取余运算
- do{执行语句}while(条件)先执行再判断
- while(条件){执行语句} 先判断再执行
感觉while更常见
案例:求水仙花数,即个位、十位和百位的三次方之后仍是自身的三位数
#include <iostream>
using namespace std;
int main() {
int i = 100;
int count = 0;
do {
//cout << i << endl;
if (pow(i/100,3) + pow(i%10,3) + pow(i%100/10,3) == i) {
count++;
cout << "第" << count << "个水仙花数为:" << i << endl;
}
i++;
} while (i < 1000);
return 0;
}
for循环
for (0; 1; 3){
2
}//0只初始执行一次,如果满足条件1,执行2,再执行3;否则退出循环,顺序是0 123 123 ...
//此外,3也可以和2再一起
- for循环输出99乘法表
#include <iostream>
using namespace std;
int main() {
for (int i = 1; i < 10; i++)//行
{
for (int j = 1; j <= i; j++)//列
{
cout << j << "x" << i << "="<<i * j <<"\t";
}
cout << "\n";//换行
}
return 0;
}
- for循环敲桌子
#include <iostream>
using namespace std;
int main() {
for (int i = 1; i < 100; i++){
//7的倍数:对%7为0
//个位为7:%10为7
//十位为7:/10为7
if (i % 7 == 0 || i % 10 == 7 || i / 10 == 7) {
cout << "敲桌子" << endl;
}
else{
cout << i << endl;
}
}
return 0;
}
continue和break
以for循环为例:
- break:直接跳出循环
- continue:如果满足条件,则跳过本轮循环中尚未执行的语句,进入下一循环
数组
一维数组
定义方式
- 数据类型 数组名[数组长度];
- 数据类型 数组名[数组长度] = {值1,值2 …};
- 数据类型 数组名[]= {值1,值2 …};
无论是哪种方式,必须给定长度,否则无法初始化,其中3是根据元素个数推出了长度,方式2中,如果长度大于元素个数,会被补0
- 利用sizeof(数组名)获取数组长度;
- 利用sizeof(数组名[下标])获取单个元素长度;
- 1除以2得到元素个数
- 利用(int)arr获得数组首地址,不用加&,加了&好像也没事
- 利用(int)&arr[下标]获取某元素的地址,&为取址符号,必须加&
#include <iostream>
using namespace std;
int main() {
//数据类型 数组名[数组长度];
int arr1[2];
//数据类型 数组名[数组长度] = {值1,值2···};
int arr2[10] = {1,2,3 };
for (int i = 0; i < 10; i++){
cout << "arr[" << i << "]" << "="<<arr2[i] << endl;
}
cout << "arr2的数组长度为" << sizeof(arr2) << endl;
cout << "arr2单个元素长度" << sizeof(arr2[0]) << endl;
cout << "arr2数组元素个数" << sizeof(arr2) / sizeof(arr2[0]) << endl;
cout << "arr2数组的首地址为" << (int)arr2 << endl;
cout << "arr2数组中首元素的地址" << (int)&arr2[0] << endl;
//省略长度
int arr3[] = { 1,2,3 };
return 0;
}
案例:5只小猪称体重,找数组中的最大值
#include<iostream>
using namespace std;
int main() {
//创建数组,5之小猪的体重
int arr[] = { 400,250,380,260,300 };
//设置最大的体重,初始化为0
int max = 0;
for (int i = 0; i < 5; i++){
cout << "第" << (i + 1) << "只小猪体重:" << arr[i] << endl;
//如果数组中元素比max大,就更新max
max = arr[i] > max ? arr[i] : max;
}
cout << "最重的小猪体重为:" << max;
return 0;
}
案例:对数组元素进行逆序,while的方法可能条理更清晰
#include <iostream>
using namespace std;
//对数组元素进行逆序排列
int main() {
//定义数组
int arr[] = { 1,2,3,4,5,6,7};
//获取长度
int length = sizeof(arr) / sizeof(arr[0]);
//先输出一下
cout << "逆序之前:" << endl;
for (int i = 0; i < length; i++){
cout << arr[i] << " " ;
}
//定义临时变量
int temp;
//for循环的方法
cout << "\nfor循环逆序之后" << endl;
for (int i = 0; i < length-i; i++){
temp = arr[i];
arr[i] = arr[length - 1 - i];
arr[length - 1 - i] = temp;
}
for (int i = 0; i < length; i++){
cout << arr[i] << " ";
}
//while循环法
//先定义起始下标和结束下标
int start = 0;
int end = length - 1;
while (start<length){
temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
start++;
end--;
}
cout << "\nwhile循环逆序之后:" << endl;
for (int i = 0; i < length; i++){
cout << arr[i] << " ";
}
return 0;
}
冒泡排序
原理:
- 一组数据,每相邻的两个数据进行比较,如果第一个数据比第二个大,就交换两个数据,一轮对比结束,找到最大的数。
- 同样的方法,一轮轮地比较,每轮的比较次数减一。
#include <iostream>
using namespace std;
int main() {
int arr[] = { 3,2,5,4,1,8,6,9,1,9,7};
int length = sizeof(arr) / sizeof(arr[0]);
cout << "冒泡排序之前:" << endl;
for (int i = 0; i < length; i++){
cout << arr[i] << " ";
}
//冒泡排序
//总的排序轮数=元素个数-1
int len = length-1;
//i表示轮数,第0轮、第1轮···
for (int i = 0; i < len; i++){
//j为每轮排序中,对比的次数,j=总轮数-当前轮数
for (int j = 0; j < len-i; j++) {
//如果第一个数比第二个数大,就交换
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
cout << "\n冒泡排序之后:" << endl;
for (int i = 0; i < length; i++){
cout << arr[i] << " ";
}
return 0;
}
二维数组
定义方式
推荐第2中第二种,可读性好
- 数据类型 数组名[行数][列数];
- 数据类型 数组名[行数][列数]={{数据1,数据2},{数据1,数据2}};
- 数据类型 数组名[行数][列数]={数据1,数据2,数据3,数据4};
- 数据类型 数组名[ ][列数]={数据1,数据2,数据1,数据2};
#include <iostream>
using namespace std;
/*
推荐第2中第二种,可读性好
1. 数据类型 数组名[行数][列数];
2. 数据类型 数组名[行数][列数]={{数据1,数据2},{数据1,数据2}};
3. 数据类型 数组名[行数][列数]={数据1,数据2,数据3,数据4};
4. 数据类型 数组名[ ][列数]={数据1,数据2,数据1,数据2};
*/
int main() {
int arr1[3][2] =
{ {1,2},
{3,4},
{5,6}
};
for (int i = 0; i < 3; i++){
for (int j = 0; j < 2; j++){
cout << arr1[i][j] << " ";
}
cout << endl;
}
cout << "二维数组占用内存空间:" << sizeof(arr1) << endl;
cout << "二维数组一行占用的内存空间:" << sizeof(arr1[0]) << endl;
cout << "二维数组单个元素占用的内存空间:" << sizeof(arr1[0])[0] << endl;
cout << "二维数组行数:" << sizeof(arr1) / sizeof(arr1[0]) << endl;
//每行空间/单个元素空间=元素个数(列数)
cout << "二维数组列数:" << sizeof(arr1[0]) / sizeof(arr1[0][0]) << endl;
//利用数组名获取首地址
cout << "二维数组首地址:" << (int)arr1 << endl;
cout << "二维数组第一行首地址:" << (int)arr1[0] << endl;
//获取单个元素的首地址必须加&,数组或某一行加不加都可以
cout << "二维数组第一个元素首地址:" << (int)&arr1[0][0] << endl;
return 0;
}
二维数组案例:成绩统计
#include <iostream>
using namespace std;
int main() {
int arr[3][3] = { {100,90,80},{90,100,90},{90,90,90} };
cout << "语文\t数学\t英语\t总分" << endl;
for (int i = 0; i < 3; i++){
int sum = 0;
for (int j = 0; j < 3; j++){
cout << arr[i][j]<<"\t";
sum += arr[i][j];
}
cout << sum << endl;
}
return 0;
}
函数
- 返回值类型
- 函数名
- 参数列表
- 函数体语句
- return
参数列表和返回值非必须
值传递,形参变化,不会影响实参
默认参数
#include <iostream>
using namespace std;
/*注意两点:
1.给了一个默认参数,则以后的形参都要有默认参数
2.声明给了默认参数,定义就不再写,防二义性,因为编译器不知道听谁的*/
//如果b给了默认参数,则b以后的所有参数都要有
//int test01(int a, int b = 10, int c);
int test01(int a, int b = 10, int c=10);
int main() {
return 0;
}
//声明给过默认参数了,定义就不要再写默认参数了
int test01(int a, int b, int c) {
return a + b + c;
}
占位参数
//参数列表加个数据类型占个位置
void test(int a,int){}
//调用的时候得传参
test(10,10);
//占位参数也可以给个默认值,
void test02(int a,int = 10){}
//调用的时候就给一个a的值就行
test02(1);
函数重载
函数名相同,提供复用性,要实现函数重载,要满足以下条件:
- 同一个作用域(目前都是全局定义域),
- 函数名相同,
- 函数参数类型不同,个数不同,或者顺序不同
- 仅返回值类型不同,其他都相同,不能实现函数重载,如int fun()和void fun()
函数重载注意事项
- 引用也可以作为函数重载条件,区别关键是const,传入a走没加const的,直接传入整型数据10则走const那个,知识点参考常量引用
- 有默认参数的函数重载应该避免
#include <iostream>
using namespace std;
void fun(int& a);
void fun(const int& a);
void test(int a, int b = 10);
void test(int a);
int main() {
//1.引用作为重载条件
fun(10);
//对于int& a=10是不成立的,不满足引用的格式
//const int& a = 10;
//是合法的,编译器做了如下工作,
//int temp = 10;
//const int& a = temp;
int a = 10;
fun(a);
//这里传的是a,变量,可读可写,而const是只读的,所以会走没有const的版本
//2.默认参数的重载,
// 这种由默认参数的不知道调用哪个
//test(10);
test(10, 2);
return 0;
}
void fun(int& a) {
cout << "int &a 调用" << endl;
}
void fun(const int& a) {
cout << "const int &a 调用" << endl;
}
void test(int a, int b) {
cout << "int a, int b = 10" << endl;
}
void test(int a) {
cout << "int a" << endl;
}
分文件编写
主要是头文件,源
文件,以及调用
my_max.h
#include <iostream>
using namespace std;
int my_max(int a, int b);//函数声明
my_max.cpp
#include "my_max.h"
//my_max函数定义,包含my_max头文件
int my_max(int a, int b) {
int max = a > b ? a : b;
return max;
}
调用my_max
#include <iostream>
using namespace std;
#include "my_max.h"
int main() {
int a = 10, b = 20;
cout << "a=" << a << ",b=" << b << endl;
int max = my_max(a, b);
cout << "max is " << max;
}
指针
功能以及定义
功能:指针用来保存地址
定义:数据类型 * 指针名;
解引用:*指针名,来获取地址中的数据
#include <iostream>
using namespace std;
/*定义指针:
数据类型 * 指针名 = & 变量*/
int main() {
int a = 10;
int* p = &a;
cout << "a=\t\t" << a << endl;\
cout << "对p解引用:\t" << *p << endl;
cout << "a的地址:\t" << (int)&a << endl;
cout << "p指向地址:\t" << (int)p << endl;
cout << "p占用的内存空间:" << sizeof(p) << endl;
cout << "int*占用内存空间:" << sizeof(int*) << endl;
cout << "double*占用内存空间:" << sizeof(double*) << endl;
cout << "char*占用内存空间:" << sizeof(char*) << endl;
return 0;
}
指针占用的内存空间
把int*作为一种数据类型,看成是一个整体,用sizeof(int *)或者sizeof(指针名)类获取其占用的内存空间。对于所有类型的指针:
- 32位操作系统中:占4个字节
- 64位操作系统中:占8个字节
空指针和野指针,不要访问
空指针 int * p = NULL
- 指针变量指向内存中编号为0的空间
- 用于初始化指针变量
- 空指针指向的内存不可访问,因为0~255编号的内存被系统占用,无法访问
- 后续将p指向其他内存后可以访问
野指针
就是未经申请,自己指向一块内存空间,这种指针就是野指针,野指针指向的内存是我们无权访问的,好比去超市村包裹,正常流程是在终端抽取一个号码,即申请一块内存来存储数据,也就是我们的包裹。但是你未经申请,想要打开某一个柜子,是没有权限打开的,里面可能已经存有东西了。
#include <iostream>
using namespace std;
//空指针和野指针都不是自己申请的内存空间,无权访问
int main() {
//空指针
int* p = NULL;
cout << "p=" << (int)p << endl;
//再让p指向a的内存空间后可以访问
int a = 1;
p = &a;
cout << "p=" << (int)p << endl;
cout << "解引用:" << *p << endl;
//野指针
//好比去超市存包,存包前得抽一个号才能用,但是你自己硬要存在某一个柜子里了
//,里面放的是别人的包裹,你是无权访问的
int* ptr = (int*) 0x1100;//自己制定0x1100这个地址
cout << "ptr指向:" << (int)ptr << endl;
//cout << "ptr解引用" << *ptr << endl;//,但是没有访问权限,
return 0;
}
指针常量和常量指针
- 普通指针 int * p = &a;
- 常量指针 const+* const int * p = &a;
const修饰*p,*p是常量,*p不可以在被赋值,但是a可以被赋值,p不受限制,可以&其他 - 指针常量 *+const int * const p = &a;
const修饰 p, p不可以再&其他,但p不受限制. - const既修饰指针,也修饰常量 const int * const p = a;
*p和p都不能修改
#include <iostream>
using namespace std;
int main() {
int a = 10,b = 20;
cout << "a=" << a << ",b=" << b << endl;
cout << "&a=" <<(int)& a << ",b=" << (int)&b << endl;
//const=常量,*=指针,即常量指针
const int* p = &a;
cout << "\np指向地址" << (int)p << endl;
cout << "*p=" << *p << endl;
//看作是const 修饰的是*,*就是常量了,不可以修改
//*p = 20;//不可通过*p修改里面存放的值,但是a的值还是可以改的
a = 100;
cout << "*p=" << *p << endl;
p = &b;//p不受修饰,可以改指向的地址
cout << "*p=" << *p << endl;
//*+const 指针常量
int*const p2 = &b;
//const修饰p2,则p2不能改指向的地址了,但是*不受修饰
cout << "*p2=" << *p2 << endl;
*p2 = 2;
cout << "*p2=" << *p2 << endl;
//p2 = &a;//p2被const修饰不能改
return 0;
}
指针和数组
- 利用指针访问数组,制作指向首地址,数组名即为首地址,然后指针偏移,访问下一个元素。
- 指针也可以像数组那样加[下标]来访问里面的数据
#include <iostream>
using namespace std;
int main() {
int arr[] = { 1,2,4,5,6,7,8,9,0 };
int* p = arr;//数组名就是首地址
cout << "利用指针访问数组中第一个元素:" << *p << endl;
cout << "利用指针访问数组中第二个元素:" << p[1] << endl;
cout << "利用指针访问数组中第三个元素:" << p[2] << endl;
p++;//偏移访问下一个
cout << "利用指针访问数组中第二个元素:" << *p << endl;
cout << "利用指针访问数组中第三个元素:" << *(p+1) << endl;
cout << "\n\n";
//利用指针便利数组
//指针和下标
int len = sizeof(arr) / sizeof(arr[0]);
int* p2 = arr;
int* p3 = arr;
for (int i = 0; i < len; i++){
cout << p2[i] << " ";
}
cout << "\n\n";
//指针解引用和偏移
for (int i = 0; i < len; i++){
cout << *p3 << " ";
p3++;
}
return 0;
}
指针与函数,值传递和地址传递
- 值传递,形参改变,不会改变实参,值传递,相当于拷贝了一份数据,对副本操作,不会影响源文件
- 地址传递,形参改变,实参也改变,因为main和子函数操作的是同一块内存,子函数中改变了,main中也会改变
#include <iostream>
using namespace std;
void my_swap(int a, int b) {
cout << "值传递" << endl;//值传递,形参改变不改变实参
cout << "my_swap,传入:" << endl;
cout << "my_swap a=" << a << endl;
cout << "my_swap b=" << b << endl;
int temp;
temp = a;
a = b;
b = temp;
cout << "\nmy_swap交换后:" << endl;
cout << "my_swap a=" << a << endl;
cout << "my_swap b=" << b << endl;
}
void my_swap02(int*p1,int*p2) {
/*地址传递,形参改变不改变实参
传入地址,用指针来接收*/
cout << "\n\n地址传递" << endl;
cout << "my_swap02,传入:" << endl;
cout << "my_swap02 a=" << *p1 << endl;
cout << "my_swap02 b=" << *p2 << endl;
int temp;
temp = *p1;
*p1 = *p2;
*p2 = temp;
cout << "\nmy_swap02交换后:" << endl;
cout << "my_swap02 a=" << *p1 << endl;
cout << "my_swap02 b=" << *p2 << endl;
}
int main() {
int a = 10, b = 20;
cout << "main,初始:" << endl;
cout << "main a=" << a << endl;
cout << "main b=" << b << endl << endl;;
my_swap(a, b);//传入值
cout << "\nmain,调用my_swpa后:" << endl;
cout << "main a=" << a << endl;
cout << "main b=" << b << endl;
my_swap02(&a, &b);//传入地址
cout << "\nmain,调用my_swpa02后:" << endl;
cout << "main a=" << a << endl;
cout << "main b=" << b << endl;
return 0;
}

案例:指针+数组+函数实现冒泡排序
#include <iostream>
using namespace std;
/*这里展示了两种写法,第一个bubble是自己的理解写的,
要注意p的指向变化,第二个是老师写的,不太理解指针[],
直接将指针等价数组了,但是和循环更切合,用到了j,且不用更新p*/
void BubbleSort(int *p,int len) {
for (int i = 0; i < len-1; i++){
for (int j = 0; j < len-1-i; j++){
if (*p> *(p+1)){
int temp = *p;
*p = *(p+1);
*(p+1) = temp;
}
p++;
}
//这里很关键,内存循环中,p的指向已经改变,
//所以要在结束一轮循环前,让p重新指向首地址
p-=(len-1-i);
}
}
void BubbleSort2(int* p, int len) {
for (int i = 0; i < len - 1; i++) {
for (int j = 0; j < len - 1 - i; j++) {
//弹幕:指针指向数组时也可以用[]
if (p[j]>p[j+1]) {
int temp = p[j];
p[j] = p[j + 1];
p[j + 1] = temp;
}
}
}
}
void printArr(int* p, int len) {
for (int i = 0; i < len; i++) {
cout << *p << " ";
p++;
}
}
int main() {
int arr[] = { 5,1,2,9,7,6,4,3,8,0 };
int len = sizeof(arr) / sizeof(arr[0]);
cout << "排序前:" << endl;
printArr(arr, len);
//冒泡排序
BubbleSort(arr, len);
//BubbleSort(arr, len);
cout << "\n排序后:" << endl;
printArr(arr, len);
return 0;
}
结构体
定义
区别于整型,浮点型等内置的数据类型,结构体是一种自定义的数据类型
#include <iostream>
#include <string>
using namespace std;
//定义结构体
//struct 结构体名称{成员列表};
//创建学生结构体,姓名,编号,年龄等成员
struct Student {
string m_Name;
int m_ID;
int m_Age;
};
int main() {
//两种实例化方式
//方式1
Student s1;//实例化一个学生s1
s1.m_Name = "张三";
s1.m_ID = 201600066;
s1.m_Age = 22;
cout << "姓名" << s1.m_Name << endl;
cout << "学号" << s1.m_ID << endl;
cout << "年龄" << s1.m_Age << endl;
//方式2
Student s2 = { "李四",201600067,23};
cout << "姓名" << s2.m_Name << endl;
cout << "学号" << s2.m_ID << endl;
cout << "年龄" << s2.m_Age << endl;
return 0;
}
结构体数组
- 数组:数据类型 数组名[]={值1,值2···};
- 结构体数组:上述数据类型换成自定义的结构体
#include <iostream>
#include <string>
using namespace std;
//创建学生结构体,姓名,编号,年龄等成员
struct Student {
string m_Name;
int m_ID;
int m_Age;
};
int main() {
//定义数组,不过是把之前的int类型换成了自定义的struct
Student arr[] = { {"李四",201600067,23},
{"张三",201600066,23},
{"王五",201600057,22} };
//也可以再修改
arr[2].m_Age = 23;
arr[2].m_Name = "赵六";
arr[2].m_ID = 201600042;
int len = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < len; i++){
cout << "姓名:" << arr[i].m_Name << endl;
cout << "学号:" << arr[i].m_ID << endl;
cout << "年龄:" << arr[i].m_Age << endl << endl;;
}
return 0;
}
结构体指针
- 指针:数据类型 * 指针名 =&a;
数据类型 * 指针名 =数组名;
类似的,结构体指针的数据类型即结构体,访问成员时p->成员
#include <iostream>
#include <string>
using namespace std;
//创建学生结构体,姓名,编号,年龄等成员
struct Student {
string m_Name;
int m_ID;
int m_Age;
};
int main() {
//定义数组,不过是把之前的int类型换成了自定义的struct
Student arr[] = { {"李四",201600067,23},
{"张三",201600066,23},
{"王五",201600057,22} };
//也可以再修改
arr[2].m_Age = 23;
arr[2].m_Name = "赵六";
arr[2].m_ID = 201600042;
Student* p = arr;
int len = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < len; i++) {
cout << "姓名:" << p->m_Name << endl;
cout << "学号:" << p->m_ID << endl;
cout << "年龄:" << p->m_Age << endl << endl;
p++;
}
return 0;
}
结构体案例
- 要求:3名老师个带5名学生,显示学生姓名,成绩,并按学生成绩排序
- 重点:
- string nameSeed = “ABCDE”;nameSeed[1]=B
- 随机数
- 冒泡排序,外侧循环是轮数,内存循环才是具体的值比大小。
#include <iostream>
#include <string>
#include <ctime>
using namespace std;
/*
定义了俩结构体,老师结构体嵌套学生结构体数组
一个老师带5名学生,
按成绩排序
*/
struct student{
string s_Name;//姓名
int source;//分数
};
struct teacher{
string t_Name;//姓名
student sArr[5];//带5名学生数组
};
void setValue(teacher* p, int len);//设置属性
void showMessage(teacher* p, int len);//显示信息
void bubbleSort(teacher* p, int len);//冒泡排序
int main() {
teacher tArr[3];
int length = sizeof(tArr) / sizeof(tArr[0]);
setValue(tArr, length);
//showMessage(tArr, length);
bubbleSort(tArr, length);
showMessage(tArr, length);
return 0;
}
void setValue(teacher* p, int len) {
//随机数种子
srand((unsigned int)time(NULL));
string nameSeed = "ABCDE";//姓名种子
for (int i = 0; i < len; i++) {
p[i].t_Name = "Teacher_";
p[i].t_Name += nameSeed[i];
for (int j = 0; j < 5; j++) {
p[i].sArr[j].s_Name = "Student_";
p[i].sArr[j].s_Name += nameSeed[j];
p[i].sArr[j].source = rand() % 41 + 60;//分数,60到100
}
}
}
void bubbleSort(teacher* p, int len) {
for (int i = 0; i < len; i++) {//第i个老师
for (int j = 0; j < 4; j++) {//排序论述
for (int m = 0; m < 4 - j; m++) {//比较次数,m才是具体的学生,而不是j
//如果学生m的成绩比后一个大,就交换
if (p[i].sArr[m].source < p[i].sArr[m + 1].source) {
//定义临时学生结构体,进行结构体交换
student temp = p[i].sArr[m];
p[i].sArr[m] = p[i].sArr[m + 1];
p[i].sArr[m + 1] = temp;
}
}
}
}
};
void showMessage(teacher* p, int len) {
for (int i = 0; i < len; i++) {
cout << p[i].t_Name << endl;
for (int j = 0; j < 5; j++) {
cout << p[i].sArr[j].s_Name << ":" << p[i].sArr[j].source << endl;
}
cout << endl;
}
}

555

被折叠的 条评论
为什么被折叠?



