提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
视频看的是bilibili的黑马程序员的视频,链接:
https://www.bilibili.com/video/BV1et411b73Z?from=search&seid=14698314130453798526&spm_id_from=333.337.0.0
文字部分为手打,可能有部分小错误,欢迎批评指正。
1 ctrl+k+c可以把若干行一起注释掉
ctrl+k+u可以取消注释掉一整行
一、C++初识
1 编写程序四步
①创建项目②创建文件③编写代码④运行程序
2 框架
#include<iostream>
using namespace std;
//使用字符串时加头文件
//#include <string>
int main()
{
system("pause");
return 0;
}
3 常量
#define 常量名 常量值 (宏常量),在main之外
const 数据类型 常量名 = 常量值,在main里面
4 标识符命名规则
·标识符不能是关键字
·只能用字母、数字、下划线
·第一个字符必须是字母或下划线
·标识符中字母区分大小写
二、数据类型
1 数据类型存在的意义:给变量分配合适的内存空间。
2 整型
short 短整型 2字节 -32768~32767
int 整型 4字节(最常用)
long 长整型 Windows为4字节,Linux为4字节(32位),8字节(64字节)
long long 长长整型 8字节
3 sizeof( 数据类型/变量 )
如:sizeof(short) sizeof(num2)
4 实型 用于表示小数
float f1 = 3.14f; 不加f默认为double类型,加上f代表float类型。
默认显示6位有效数字,即3.1415926只显示成3.14159
5 科学技术法表示小数
float f2 = 3e2; f2等于300
float f3 = 3e-2; f3等于0.03
6 字符型
7 求字符型变量对应ASCⅡ码
char ch = 'a';
cout << (int)ch << endl;
把a的ASCⅡ码强转成一个十进制的数输出。
a–97
A–65
8 ASCⅡ码表格
9 常用的转义字符
换行符 \n
反斜杠
\\
水平制表 \t 作用是整齐的输出数据,是一共占8个位置,如果输出aaa则后面有5个空格,输出aaaa则后面有4个空格。
例如:
cout << "aaaa\thello world" << endl;
cout << "aa\thello world" << endl;
cout << "aaaaa\thello world" << endl;
10 字符串型
C语言风格:char 变量名[] = "字符串值”
C++风格:string 变量名 = “字符串值”’,使用使需要写头文件:#include < string >
11 布尔数据类型bool占1个字节。
bool flag = true;
bool flag = false;
12 输入数据:cin >> 变量
int main(){
//整型输入
int a = 0;
cout << "请输入整型变量:" << endl;
cin >> a;
cout << a << endl;
//浮点型输入
double d = 0;
cout << "请输入浮点型变量:" << endl;
cin >> d;
cout << d << endl;
//字符型输入
char ch = 0;
cout << "请输入字符型变量:" << endl;
cin >> ch;
cout << ch << endl;
//字符串型输入
string str;
cout << "请输入字符串型变量:" << endl;
cin >> str;
cout << str << endl;
//布尔类型输入
bool flag = true;
cout << "请输入布尔型变量:" << endl;
cin >> flag;
cout << flag << endl;
system("pause");
return 0;
}
三、运算符
1 算术运算符
2 只有整型变量才能做取模运算。
3 前置递增:先让变量+1,然后进行表达式运算
后置递增:先进行表达式运算,然后让变量+1
4 赋值运算符
5 比较运算符
6
int a = 10;
int b = 20;
cout << (a == b) << endl;
比较运算符输出时必须要加括号,否则会报错。
7 逻辑运算符
8 在C++中除了0都为真。
9 逻辑运算符输出时也要加括号(与6相联系)。
cout << !a << endl;
cout << (a && b) << endl;
cout << (a || b) << endl;
四、程序流程结构
1 C/C++支持最基本的程序运行结构:顺序结构、选择结构、循环结构。
2 单行格式if语句:if(条件){条件满足执行的语句}
3 if后面不要加分号,加了的话,大括号里的语句不论是否满足if条件都要执行。
例如:
if (score > 600)
{
cout << "我考上了一本大学!!!" << endl;
}
//这个if是正常语句,输入650则执行,500则不执行。
if (score > 600);
{
cout << "我考上了一本大学!!!" << endl;
}
//这个if不论输入650还是500,都会执行。
4 多行格式if语句:if(条件){条件满足执行的语句}else{条件不满足执行的语句};
5 多条件的if语句:if(条件1){条件1满足执行的语句}else if(条件2){条件2满足执行的语句}…else{都不满足执行的语句}
6 if语句小练习:有三只小猪,输入三只小猪的重量,用if语句判断三只小猪哪只最重。
#include <iostream>
using namespace std;
int main()
{
int num1 = 0;
int num2 = 0;
int num3 = 0;
cout << "请输入第一只小猪的重量: " << endl;
cin >> num1;
cout << "请输入第二只小猪的重量: " << endl;
cin >> num2;
cout << "请输入第三只小猪的重量: " << endl;
cin >> num3;
cout << "第一只小猪的重量为: " << num1 << endl;
cout << "第二只小猪的重量为: " << num2 << endl;
cout << "第三只小猪的重量为: " << num3 << endl;
if (num1 > num2)
{
if (num1 > num3)
{
cout << "第一只小猪最重" << endl;
}
else
{
cout << "第三只小猪最重" << endl;
}
}
else
{
if (num2 > num3)
{
cout << "第二只小猪最重" << endl;
}
else
{
cout << "第三只小猪最重" << endl;
}
}
system("pause");
return 0;
}
7 三目运算符。
表达式1 ?表达式2 :表达式3
如果表达式1的值为真,则执行表达式2,并返回表达式2的结果;
如果表达式1的值为假,则执行表达式3,并返回表达式3的结果。
例如:
c = a > b ? a : b;
8
//C++中三目运算符返回的是变量,可以继续赋值
(a > b ? a : b) = 100;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
9 switch语句语法。
switch(表达式)
{
case 结果1:执行语句;break;
case 结果2:执行语句;break;
...
default:执行语句;break;
}
switch小括号里的可以是一个变量。
例如:
int score = 0;
cout << "请给电影打分" << endl;
cin >> score;
switch (score)
{
case 10:
case 9:
cout << "经典" << endl;
break;
case 8:
cout << "非常好" << endl;
break;
case 7:
case 6:
cout << "一般" << endl;
break;
default:
cout << "烂片" << endl;
break;
}
10
switch缺点:语句中表达式类型只能是整型或者字符型,不可以是一个区间。
优点:结构清晰,执行效率高。
case里如果没有break,那么程序会一直向下执行,所以一般在每个case语句后面加上“break;”就一般不会出错。
11 while循环语句语法
while(循环条件){循环语句}
只要循环条件的结果为真,就执行循环语句。
12 在写循环时一定要避免死循环。
如:
while(1)
{
cout << num << endl;
num++
}
此循环会一直执行。
13 生成一个0-n的随机数
int num = rand() % n;
添加随机数种子,作用是利用当前系统时间生成随机数,防止每次随机数都一样。
srand((unsigned int)time(NULL)); //要添加头文件“#include <ctime>”
14 while循环练习案例:猜数字
系统随机生成一个1到100之间的数字,玩家进行猜测,如果猜错,提示玩家数字过大或过小,如果猜对恭喜玩家胜利,并且退出游戏。
#include <iostream>
using namespace std;
int main()
{
int num = rand() % 100;
int num2 = 0;
while (1)
{
cin >> num2;
if (num2 > num)
{
cout << "您输入的数过大" << endl;
}
else if (num2 < num)
{
cout << "您输入的数过小" << endl;
}
else
{
cout << "恭喜您通过游戏" << endl;
break;
}
}
system("pause");
return 0;
}
15 do…while循环语句语法:
do{ 循环语句 }while(循环条件);
16 通过一个三位数获取他的个位十位百位。
如:153。
获取个位:153%10=3。对10取模。
获取十位:153/10=15,15%10=5。先整除10,再对10取余。
获取百位:153/100。直接整除100。
17 找出三位数中的所有水仙花数(水仙花数是指一个 3 位数,它的每个位上的数字的 3次幂之和等于它本身)。
#include <iostream>
using namespace std;
int main()
{
int num = 100;
while (num < 1000)
{
int a = 0;
int b = 0;
int c = 0;
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++;
}
system("pause");
return 0;
}
18 for循环语句语法
for(起始表达式;条件表达式;末尾表达式){循环语句}
19 break语句
出现在switch条件语句中,作用是终止case并跳出switch
出现在循环语句中,作用是跳出当前的循环语句
出现在嵌套循环中,跳出最近的内层循环语句
20 continue语句
在循环语句中,跳过本次循环中余下尚未执行的语句,继续执行下一次循环。而break是退出整个for循环。
21 goto语句(不常使用)
有goto标记的地方,可以跳过下方的一些代码,直接执行标记之后的代码。
goto FLAG;
...
...
...
FLAG:
...
...
五、数组
1 数组定义方式
数据类型 数组名【数组长度】;
数据类型 数组名【数组长度】={值1,值2…};
数据类型 数组名【】={值1,值2…};
2 数组一开始没有赋值或者部分没有赋值,会用0进行填充。
3 一维数组名称的用途:
可以统计整个数组在内存中的长度 :sizeof(数组名)
可以获取数组在内存中的首地址:cout << 数组名 << endl;
cout << arr << endl; //cout << 数组名 << endl;
cout << (int)arr << endl; //把十六进制首地址强转成十进制
cout << “数组中第一个元素地址为: ” << &arr[0] << endl; //要加一个取址符号“&”
4 数组名是常量,不可以进行赋值操作。
5 冒泡排序(还未结合函数)
int arr[9] = { 4,2,8,0,5,7,1,3,9 };
int start = 0, end = sizeof(arr) / sizeof(arr[0]) - 1;
for (int i = start; i <= end; i++) {
cout << arr[i] << endl;
}
int temp;
for (int i = start; i < end; i++) {
bool flag = false;
for (int j = 0; j < end; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
flag = true;
}
}
if (flag == false) {
break;
}
}
for (int i = start; i <= end; i++) {
cout << arr[i] << endl;
}
system("pause");
return 0;
6 二维数组的四种定义方式。
数据类型 数组名[ 行数 ][ 列数 ];
数据类型 数组名[ 行数 ][ 列数 ] = { {数据1,数据2 } ,{数据3,数据4 } };
//一般推荐这种定义方式,比较直观数据类型 数组名[ 行数 ][ 列数 ] = { 数据1,数据2,数据3,数据4};
//行优先数据类型 数组名[ ][ 列数 ] = { 数据1,数据2,数据3,数据4};
7 二维数组数组名的作用:
查看二维数组所占内存空间
获取二维数组首地址
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;
//地址
cout << "二维数组首地址:" << arr << endl;
cout << "二维数组第一行地址:" << arr[0] << endl;
cout << "二维数组第二行地址:" << arr[1] << endl;
cout << "二维数组第一个元素地址:" << &arr[0][0] << endl; //访问具体元素地址要加取地址符“&”
cout << "二维数组第二个元素地址:" << &arr[0][1] << endl;
system("pause");
return 0;
}
8 二维数组案例
int main() {
int scores[3][3] =
{
{100,100,100},
{90,50,100},
{60,70,80},
};
string names[3] = { "张三","李四","王五" };
for (int i = 0; i < 3; i++)
{
int sum = 0;
for (int j = 0; j < 3; j++)
{
sum += scores[i][j];
}
cout << names[i] << "同学总成绩为: " << sum << endl;
}
system("pause");
return 0;
}
六、函数
1 函数的定义的5个步骤
返回值类型
函数名
参数表列
函数体语句
return表达式
返回值类型 函数名 (参数列表)
{
函数体语句
return表达式
}
num1和num2为形参,int a=1,b=2;int c=add(a,b),这里前面的a和b为实参。调用函数时,实参的值会传递给形参。
2 函数调用语法:
函数名称(参数)
3 如果函数不需要返回值,声明的时候可以写:
void 函数名 (参数列表)
{
函数体语句 //没有return语句
}
4 函数的常见样式
无参无返
有参无返
无参有返
有参有返
//1、 无参无返
void test01()
{
//void a = 10; //无类型不可以创建变量,原因无法分配内存
cout << "this is test01" << endl;
//test01(); 函数调用
}
//2、 有参无返
void test02(int a)
{
cout << "this is test02" << endl;
cout << "a = " << a << endl;
}
//3、无参有返
int test03()
{
cout << "this is test03 " << endl;
return 10;
}
//4、有参有返
int test04(int a, int b)
{
cout << "this is test04 " << endl;
int sum = a + b;
return sum;
}
5 函数的定义只有一次,函数的声明可以有多次。
提前告诉编译器函数的存在,可以利用函数的声明。
函数的定义若在main函数之前,函数的声明可以不存在,但要是在main函数之后,函数的声明必须有。
6 函数的分文件编写。
作用:让代码结果更加清晰。
步骤:
创建后缀名为.h的头文件
创建后缀名为.cpp的源文件
在头文件中写函数的声明
在源文件中写函数的定义
例如:
//swap.h文件
#include<iostream>
using namespace std;
//实现两个数字交换的函数声明
void swap(int a, int b);
//swap.cpp文件
#include "swap.h"
void swap(int a, int b)
{
int temp = a;
a = b;
b = temp;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
//main函数文件
#include "swap.h"
int main() {
int a = 100;
int b = 200;
swap(a, b);
system("pause");
return 0;
}
七、指针
1 指针的作用:可以通过指针间接访问内存。
2 指针定义的语法:数据类型 * 指针变量名
例如:
int a = 10;
int * p;
p = &a;
3 可以通过解引用的方式来找到指针指向的内存。
指针前加 * 代表解引用,找到指针指向的内存中的数据。
*p //对 * p操作相当于对a操作,如赋值啥的。
4 在32位操作系统下:指针型变量占用4字节空间,64位下占8个字节空间。不管是int还是float还是double还是char。
5 空指针:指针变量指向内存中编号为0的空间。
空指针用途:初始化指针变量。
int * p = NULL;
空指针指向的内存是不可以访问的。因为0~255之间的内存编号是系统占用的,因此不可以访问。
6 野指针:指针变量指向非法的内存空间。
在程序中,尽量避免出现野指针。
7 const修饰指针有三种情况:
const修饰指针 常量指针
const int * p1 = &a;指针的指向可以修改,但是指针指向的值不可以改。如:* p = 20;是错误的,p = &b;是正确的。
const修饰常量 指针常量
int * const p= &a; 指针的指向不可以改,指针指向的值可以改。如:* p = 20;是正确的,p = &b;是错误的。
const既修饰指针,又修饰常量
const int * const p = &a; 指针的指向和指针指向的值都不可以改。如:* p = 20;是错误的,p = &b;是错误的。
8 int * p = arr; 指针指向数组的首地址,p++后,指针指向数组第二个元素。
9 值传递和地址传递
//值传递
void swap1(int a ,int b)
{
int temp = a;
a = b;
b = temp;
}
//地址传递
void swap2(int * p1, int *p2)
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
int main() {
int a = 10;
int b = 20;
swap1(a, b); // 值传递不会改变实参
swap2(&a, &b); //地址传递会改变实参
cout << "a = " << a << endl;
cout << "b = " << b << endl;
system("pause");
return 0;
}
10 封装冒泡排序(把冒泡排序和指针,函数结合)
#include <iostream>
using namespace std;
void bubbleSort(int * arr, int len)
{
for (int i = 0; i < len - 1; i++) {
bool flag = false;
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;
flag = true;
}
}
if (flag == false) {
break;
}
}
}
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);
system("pause");
return 0;
}
八、结构体
1 结构体语法
struct 结构体名 { 结构体成员列表 };
如:
struct Stduent
{
string name;
int age;
int score;
};
通过结构体创建变量的方式:
struct 结构体名 变量名
struct 结构体名 变量名 = { 成员1值 , 成员2值…}
定义结构体时顺便创建变量
//结构体定义
struct student
{
//成员列表
string name; //姓名
int age; //年龄
int score; //分数
}stu3; //结构体变量创建方式3
int main() {
//结构体变量创建方式1
struct student stu1; //struct 关键字可以省略
stu1.name = "张三";
stu1.age = 18;
stu1.score = 100;
cout << "姓名:" << stu1.name << " 年龄:" << stu1.age << " 分数:" << stu1.score << endl;
//结构体变量创建方式2
struct student stu2 = { "李四",19,60 };
cout << "姓名:" << stu2.name << " 年龄:" << stu2.age << " 分数:" << stu2.score << endl;
stu3.name = "王五";
stu3.age = 18;
stu3.score = 80;
cout << "姓名:" << stu3.name << " 年龄:" << stu3.age << " 分数:" << stu3.score << endl;
system("pause");
return 0;
}
2 定义结构体时的关键字是struct,不可省略
创建结构体变量时,关键字struct可以省略
3 结构体数组
struct 结构体名 数组名[元素个数] = { {} , {} , …{} }
4 结构体定义是在main函数之外的。
5 如果一开始不知道结构体的某一个分量,可以先随便赋一个值,后面再进行修改。
6 结构体指针
利用操作符->可以通过结构体指针访问结构体属性。
//结构体定义
struct student
{
//成员列表
string name; //姓名
int age; //年龄
int score; //分数
};
int main() {
struct student stu = { "张三",18,100, };
struct student * p = &stu;
p->score = 80; //指针通过 -> 操作符可以访问成员
cout << "姓名:" << p->name << " 年龄:" << p->age << " 分数:" << p->score << endl;
system("pause");
return 0;
}
7 结构体的成员可以是另一个结构体
//学生结构体定义
struct student
{
//成员列表
string name; //姓名
int age; //年龄
int score; //分数
};
//教师结构体定义
struct teacher
{
//成员列表
int id; //职工编号
string name; //教师姓名
int age; //教师年龄
struct student stu; //子结构体 学生
};
int main() {
struct teacher t1;
t1.id = 10000;
t1.name = "老王";
t1.age = 40;
t1.stu.name = "张三";
t1.stu.age = 18;
t1.stu.score = 100;
cout << "教师 职工编号: " << t1.id << " 姓名: " << t1.name << " 年龄: " << t1.age << endl;
cout << "辅导学员 姓名: " << t1.stu.name << " 年龄:" << t1.stu.age << " 考试分数: " << t1.stu.score << endl;
system("pause");
return 0;
}
8 结构体做函数参数
传递方式:值传递,地址传递。
值传递用“.”地址传递用“->”。
//学生结构体定义
struct student
{
//成员列表
string name; //姓名
int age; //年龄
int score; //分数
};
//值传递
void printStudent(student stu )
{
stu.age = 28;
cout << "子函数中 姓名:" << stu.name << " 年龄: " << stu.age << " 分数:" << stu.score << endl;
}
//地址传递
void printStudent2(student *stu)
{
stu->age = 28;
cout << "子函数中 姓名:" << stu->name << " 年龄: " << stu->age << " 分数:" << stu->score << endl;
}
int main() {
student stu = { "张三",18,100};
//值传递
printStudent(stu);
cout << "主函数中 姓名:" << stu.name << " 年龄: " << stu.age << " 分数:" << stu.score << endl;
cout << endl;
//地址传递
printStudent2(&stu);
cout << "主函数中 姓名:" << stu.name << " 年龄: " << stu.age << " 分数:" << stu.score << endl;
system("pause");
return 0;
}
9 结构体中可以用const来防止误操作。
将函数中的形参改为指针,可以减少内存空间,而且不会复制新的副本出来。
在形参前面加入const之后,一旦有修改的操作就会报错,可以防止我们的误操作。
void printStudent(const student *stu) //加const防止函数体中的误操作
{
//stu->age = 100; //操作失败,因为加了const修饰
cout << "姓名:" << stu->name << " 年龄:" << stu->age << " 分数:" << stu->score << endl;
}
10 随机数种子
srand((unsigned int)time(NULL)); //随机数种子 头文件 #include <ctime>
11 结构体案例
案例1
案例描述:
学校正在做毕设项目,每名老师带领5个学生,总共有3名老师,需求如下
设计学生和老师的结构体,其中在老师的结构体中,有老师姓名和一个存放5名学生的数组作为成员
学生的成员有姓名、考试分数,创建数组存放3名老师,通过函数给每个老师及所带的学生赋值
最终打印出老师数据以及老师所带的学生数据。
struct Student
{
string name;
int score;
};
struct Teacher
{
string name;
Student sArray[5];
};
void allocateSpace(Teacher tArray[] , int len)
{
string tName = "教师";
string sName = "学生";
string nameSeed = "ABCDE";
for (int i = 0; i < len; i++)
{
tArray[i].name = tName + nameSeed[i];
for (int j = 0; j < 5; j++)
{
tArray[i].sArray[j].name = sName + nameSeed[j];
tArray[i].sArray[j].score = rand() % 61 + 40;
}
}
}
void printTeachers(Teacher tArray[], int len)
{
for (int i = 0; i < len; i++)
{
cout << tArray[i].name << endl;
for (int j = 0; j < 5; j++)
{
cout << "\t姓名:" << tArray[i].sArray[j].name << " 分数:" << tArray[i].sArray[j].score << endl;
}
}
}
int main() {
srand((unsigned int)time(NULL)); //随机数种子 头文件 #include <ctime>
Teacher tArray[3]; //老师数组
int len = sizeof(tArray) / sizeof(Teacher);
allocateSpace(tArray, len); //创建数据
printTeachers(tArray, len); //打印数据
system("pause");
return 0;
}
案例2
案例描述:
设计一个英雄的结构体,包括成员姓名,年龄,性别;创建结构体数组,数组中存放5名英雄。
通过冒泡排序的算法,将数组中的英雄按照年龄进行升序排序,最终打印排序后的结果。
五名英雄信息如下:
{"刘备",23,"男"},
{"关羽",22,"男"},
{"张飞",20,"男"},
{"赵云",21,"男"},
{"貂蝉",19,"女"},
//英雄结构体
struct hero
{
string name;
int age;
string sex;
};
//冒泡排序
void bubbleSort(hero arr[] , int len)
{
for (int i = 0; i < len - 1; i++)
{
for (int j = 0; j < len - 1 - i; j++)
{
if (arr[j].age > arr[j + 1].age)
{
hero temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
//打印数组
void printHeros(hero arr[], int len)
{
for (int i = 0; i < len; i++)
{
cout << "姓名: " << arr[i].name << " 性别: " << arr[i].sex << " 年龄: " << arr[i].age << endl;
}
}
int main() {
struct hero arr[5] =
{
{"刘备",23,"男"},
{"关羽",22,"男"},
{"张飞",20,"男"},
{"赵云",21,"男"},
{"貂蝉",19,"女"},
};
int len = sizeof(arr) / sizeof(hero); //获取数组元素个数
bubbleSort(arr, len); //排序
printHeros(arr, len); //打印
system("pause");
return 0;
}