基础认知
//基础框架#include<iostream>usingnamespaceintmain(){....}//输出cout<<"要输出的内容"<<endl;1.变量
1.定义变量
//数据类型 变量名 = 变量初始值 //跟C语言一样 int a = 10;2.变量命名规则
- 不能是关键字
- 标识符由字母,数字,下划线构成
- 数字不能是变量的第一个字符
- 标识符是会区分大小写的
2.常量
有两种定义
1.#define 定义宏常量通常定义在文件上方
2.const修饰的变量定义在文件内
注意:常量是不可以修改的,一旦修改就会报错
//#define 常量名 常量值#defineday7intmain(){.....}//const 变量类型 变量名 = 变量值;intmain(){constintday=7;}3.关键字
1.定义:是c++中预定义的,不能用这些名字赋变量或常量,不然会报错
4.数据类型
4.1 存在意义
为了给变量分配合适的内存
4.2 具体类型
- 整型变量:表述整数类型的变量
短整型 short :2byte
整型 int : 4 byte
长整型 long : 4 byte(windows), 8byte(linux)
长长整型 long long : 8 byte
2.实型
- 单精度 float 4byte (默认情况下输出一个小数会输出六位有效数字)floata=3.12444;- 双精度 double 8byte科学计数法
floata=32e4;//e 后边代表是10的的多少次方,可正可负
3.字符型
所占内存大小: 一个字节
//创建方法 char 变量名 = '';chara='a';//赋值时必须使用单引号,且只能有一个字符可以强制转换为(int)类型查看对应的ASCII
4.字符串型
//创建格式(C语言风格)char变量名[]="字符串的值";//注意,需要使用双引号//创建格式2(C++)#include<string>string str="hello";5.布尔类型
代表真和假,只有两个值,true false,只占用一个字节的空间
boolflag=true;4.3 sizeof 关键字
用于判断占用的内存空间
//eg.sizeof(int);// > 4longnum=3;sizeof(num);// > 84.4 转义字符
用反斜杠来转义后面的符号,使其失去原有的意思直接输出
\n 换行
\t 制表
4.5 数据输入
需要使用关键字cin()
//具体实现inta=0;cout<<"请赋值A"<<endl;cin>>a;cout<<"A的值是:"<<a<<endl;5.运算符
1.算术运算符
用于处理四则运算
有以下几种(具体含义与C语言一样,用法也差不多)
%
++
–
2.赋值运算符
=:直接赋值
+=
-=
*=
/=
%=
//演示//赋值运算符可以看做对自身的处理a+=2;//实际上就是 a = a + 2;3.比较运算符
==
!=
<
>
<=
>=
4.逻辑运算符
与(&&),非(!),或(||),
返回值是真或者假,跟离散数学有点关系
6.程序流程结构
C语言和C++支持三种程序运行结构
顺序结构,选择结构,循环结构
- 顺序结构是不跳转的按顺序执行
- 选择结构则是看是否满足条件来执行程序
- 循环结构则是按照是否满足条件来循环执行一段代码
6.1选择结构
6.1.1 IF语句
有三种形式:单行,多行,多条件
//基本结构if(判断条件表达式){执行语句};//这是单行的if语句//下面是多行if语句if(判断表达式){执行语句;}else{执行语句;}//多条件if语句if(判断表达式){执行语句一;}elseif(判断表达式){执行语句二;}elseif(判断表达式){执行语句三;}else{执行语句四;}//前面所有条件都不满足时执行此代码- 特殊应用:嵌套IF语句
if(条件){if(条件2){}elseif(条件3){}else{}}//在满足条件一的情况下,再做更细节的判断6.1.2 三目运算符
//具体语法表达式1?表达式2:表达式3解释: 如果1的值为真,执行表达式2,返回2 的结果;否则执行三并返回3的结果.
6.1.3 switch语句
作用:执行多条件的分支语句
switch(表达式){case结果1:执行语句;break;case结果2:执行语句;break;...default:执行语句;break;}解释:当表达式的值等于任一一个结果时,就会执行对应的语句;若全部不满足,则执行defaul后面的语句
提示:这个语句会有穿透功能,也就是不加入break语句会一直执行下面的分支的语句
判断表达式时候只能是整形或者字符型,没办法判断区间; 但是执行效率高且结构清晰
6.2循环结构
6.2.1while循环
作用:满足循环条件就执行语句
while(循环条件){执行语句;}6.2.2do while
do{执行语句;}while(条件)与while的区别:先执行一次语句,再去判断条件进行重复执行
形象说明:拿钥匙开锁这个场景,每次先拿钥匙试下,如果不行就换钥匙直到开锁
练习:水仙花数,prac_base func_1
%10 获取个位数字
/10 %10 获取十位数字
/100 %10 获取百位数字
6.2.3 for 循环
作用:满足条件就循环,但是是有限次次数
for(起始表达式;条件表达式;末尾循环体){执行语句;}执行流程:初始化->满足条件->执行循环语句->执行末尾循环体->判断条件…
eg.
for(inti=0;i<5;i++){cout<<i<<endl;}注意:for循环需要用;隔开
练习
敲桌子func_2 prac_base.cpp
6.2.4 嵌套循环
练习: base.cpp nested_loop
prac_base .cpp times_tables
6.3跳转语句
6.3.1 break语句
练习: base.cpp jump()
作用:跳出选择结构或者循环结构
- switch放在case后,跳出case分支
- 循环语句中用于跳出循环
- 嵌套循环语句退出内层循环
6.3.2 continue语句
作用:跳出本次循环中余下尚未执行的语句,进行下次循环
注意:与break的区别,continue是执行到这一行就不执行了,进行下次循环,但是break是直接退出循环
//eg.输出奇数不输出偶数for(inti=0;i<9;i++){if(i%2==0){continue;}cout<<i<<endl;}6.3.3 goto语句
作用:无条件跳转语句
goto 标记
1xxxx2xxxxgotoFLAG;3xxxx4xxxx FLAG;5XXXX//执行顺序,1,2,5,会直接跳转到标记处运行之后的代码7.数组
7.1 基本概念
1.特点:放在一块连续的内存空间中,每个元素类型相同
7.1.1 定义方式
//数据类型 数组名[长度] int arr[4]; //5代表的总个数,但是索引是从0开始的. arr[0] = 10; arr[1] = 20; arr[2] = 30; arr[3] = 40; //数据类型 数组名[数组长度] = {值1, 值2, ...} int arr2[3] = {1, 2, 3}; //这种方法如果在初始化的时候没有全部填写数据,则会自动用0补齐 //数据类型 数组名[] = {值1, 值2, 值3, ...} int arr3[] = {2, 3, 4, 5}; //系统会自动计算元素个数输出数组:可以利用循环输出数组,for循环和下标的组合
定义数组注意:一定要有初始化的值,不能用NULL赋值
7.1.2 数组名
1.作用:获取数组首地址,获取数组长度
intarr[]={1,2,3};cout<<sizeof(arr)<<endl;//输出 : 12byte//算出数组元素个数intlen=sizeof(arr)/sizeof(arr[0]);//获取首地址cout<<"数组的首地址为:"<<(int)arr<<endl;//获取第一个元素的地址cout<<(int)&arr[0]<<endl;2.注意:数组名字是一个常量,不可以进行赋值的操作.
例题 prac_base.cpp func_3() func_4()
7.2 一维数组
7.2.1 冒泡排序
作用:把数组内的数字从小到大排列
原理:比较相邻的元素,如果前一个比后一个大就交换位置,对每一组元素执行以上步骤直到找到第一个最大的元素,重复以上步骤.每次比较步骤-1,直到不需要比较
次数:排序轮数等于总次数减一,每轮对比次数等于元素个数减去排序轮数减一
//冒泡排序//演示,利用数组 {24,2,8,0,5,7,1,3,9}intarr[]={24,2,8,0,5,7,1,3,9};for(inti=0;i<9;i++)//输出原数列{cout<<arr[i]<<" ";}cout<<endl;//开始排序for(inti=0;i<9-1;i++){for(intj=0;j<9-i-1;j++){if(arr[j]>arr[j+1])//前一个数字比后一个大就交换顺序{inttemp=arr[j];arr[j]=arr[j+1];arr[j+1]=temp;}}}for(inti=0;i<9;i++)//输出排序完成的数列{cout<<arr[i]<<" ";}cout<<endl;7.3 二维数组
7.3.1 定义
比一维数组多一维,可以理解为一维数组是一列数字,二维数组是一个矩阵
- 定义方式:
arr[][]前一个代表行,后一个参数代表列,索引都从0开始
输出:可以利用嵌套循环
7.3.2 创建方式
//1.直接创建数组并且按照索引分别输入每个元素 int arr1[2][2]; arr[0][0] = 1; arr[0][1] = 2; arr[1][0] = 3; arr[1][1] = 4; //2.利用大括号创建数组 int arr2[2][3] = { {1, 2, 3}, {4, 5, 6} }; //强烈推荐这种方法 //3.直接自动区分行和列 int arr3[2][3] = {1, 2, 3, 4, 5, 6}; //4.不输入行数,自动区分 int arr4[][3] = {1, 2, 3, 4, 5, 6};7.3.3 数组名
作用:
- 查看占用的内存空间大小
- 查看二维数组的首地址
int arr[2][3] = { {1, 2, 3}, {4, 5, 6} }; //1.以下是利用数组名字查看占用内存空间 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; //查看列数,用一行的内存除以每个元素的内存//2.查看首地址 cout << arr << endl; //查看特定元素的首地址 cout << &arr[0][1] << endl;7.3.4
例题
见 prac_base.cpp func_5()
8.函数
8.1 基本概念
封装一段经常使用或者功能固定的代码,减少重复代码
定义步骤:
- 返回类型
- 函数名
- 参数表列
- 函数体语句
- return 表达式
//eg. int function(int a)//函数返回类型 函数名字(传入参数) { cout << "hello world" << endl;//具体函数执行语句 return 1;//返回值 }eg. base.cpp sum()
//函数的定义格式函数类型 函数名(参数){执行语句;return返回值;}- 注意: 返回值的类型必须与函数类型一致,且需要注意的是,若函数类型是 “VOID” 则不需要返回值
函数的调用:
利用函数名传入参数调用函数
//eg. void print_1(char arr[]) { cout << arr << endl; }- 注意:函数定义的时候定义的参数叫做形式参数,并没有实际的值;但当调用函数的时候传入的具体值(变量)叫做实际参数,函数会把实参的值传递给形参,并进行运算
- 在这个过程中,会发生***值传递***的过程,也就是说,只把实参的值传递给形参进行运算,而实参本身并不改变,相当于形参复制了实参的值(若利用指针则可以改变实参的值 )
值传递例题在 base.cpp value_pass()
8.2 常见的几种函数类型
- 无参无返
- 有参无返
- 无参有返
- 有参有返
voidpass(){cout<<'1'<<endl;}//无参无返voidpass_1(inta){cout<<a<<endl;}//有参无返intpass_2()//无参有返{inta=20;cout<<a<<endl;returna;}intpass_3(inta){cout<<a<<endl;returna;}8.3 函数的声明
函数的声明就是在定义函数之前先声明出函数类型和函数名,但不写函数体
==注意:==函数的声明可以有很多次,但是函数的定义只能有一次
作用:提前告诉编译器函数的存在,可以利用函数的声明,若函数的定义在main()函数之后最好先声明函数,不然在运行程序时会报错
8.4函数的分文件编写
作用:在编写大项目时使得代码结构更清晰
具体步骤:
- 创建头文件 (后缀名为 .h)
- 创建源文件 (后缀名为 .cpp
- 在头文件中声明函数
- 在源文件中定义函数
- 在其他文件中引用这个函数(只需要引用头文件即可)
练习: cpp//test//test1.h test1_root.cpp
引用头文件:
如果头文件位于当前源文件的上级或下级目录,你可以直接在#include指令中指明相对路径。
假设你的项目结构如下:
project/ ├── src/ │ └── main.cpp └── include/ └── my_header.h那么,在main.cpp中,你可以这样引用:
#include "../include/my_header.h" [reference:4][reference:5]这里的..代表上一级目录。这种方法直接、无需额外配置,但如果项目结构复杂,路径会变得冗长且难以维护。
9.指针
9.1 基本概念
指针指向内存空间,可以通过指针简介访问内存空间
- 内存从0开始,但使用十六进制数字表示
- 指针变量可以保存内存地址,通过这个指针变量可以直接修改内存地址存储的东西
9.2 基本使用
- 定义:
数据类型 * 变量名
数据类型 * 表示这是一个指针类型的变量,可以是整数指针,浮点数指针,具体看指针指向的数据的类型
//基本使用 int * p; int a = 10; p = &a; //&代表取得这个元素的内存地址 //*代表解引用,可以给指针变量解引用并且赋值 *p = 30;64位中指针变量占用8字节
32位占用4字节
9.3 空指针
NULL代表空指针
指针初始化时可以指向空指针
注意:空指针不能被调用,不能被解引用并且赋值
int* p = NULL
9.4 野指针
定义:指向非法内存空间的指针变量
//eg. int * p = (int*)0x1100; //这里是利用了强制转换,但实际上并没有申请这块内存空间,所以没有办法解引用或者操作这块空间,此类指针十分危险且无法被引用,被称为野指针9.5 CONST修饰指针
9.5.1 常量指针
在指针变量前增加const
const int * p = &a;
特点:指针的指向可以修改,指针指向的值不可以修改
解释:就是说,指针变量可以重新指向另一个内存位置,但是指针变量指向的内存地址的值不可以修改
9.5.2 指针常量
int * const p = &a;
指针的指向不可以改,但是指针指向的值可以修改
纯常量:const int * const p = &a;
9.6 指针与数组
作用:利用指针访问数组元素
eg
intarr[10]={1,2,3,4,5,6,7,8,9,10};int*p=arr;//arr就是数组首地址for(inti=0;i<10;i++){cout<<"第"<<i+1<<"个数据是: ";cout<<*p<<endl;p++;}例子 base.cpp pter_arr()
9.7 指针与函数
作用: 利用指针作为形参,可以改变实参的值
不只是作为值传递,而是作为地址传递
eg.
//利用指针进行数字交换inta=10;intb=20;voidswap2(int*a,int*b){inttemp=*a;*a=*b;*b=temp;}//利用地址传递,直接交换两个实参的值swap2(&a,&b);//使用该函数时要传入的是地址,而不是变量的值9.8 指针 数组 函数
例题:对一个数组进行升序排列
//思路解析 //1. 创建数组 //2. 创建函数实现排序算法(冒泡排序) //3. 输出排序好之后的数组 //eg. int arr[10] = {4, 3, 6, 9, 1, 2, 10, 8, 7, 5}; void func_6() { int arr[10] = {4, 3, 6, 9, 1, 2, 10, 8, 7, 5}; int len = sizeof(arr)/sizeof(arr[0]); // 一般排序的时候需要传入数组和长度 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; } } } for(int i = 0;i < len - 1;i++) { cout << arr[i] << " "; } }10.结构体
10.1 基本概念
定义:结构体是自定义的数据类型,允许存储不同的数据类型
**语法: **struct 结构体名{结构体成员列表};
10.1.1 创建方法
struct 结构体名 {};
//eg.structStudent{string name;intage;intscore;}10.1.2 实例化
就是通过创建的结构体(新的数据类型)创建一个新的实例
//eg. struct Student xiaoming;//1. 实例化一个新的变量xiaoming //给新的变量属性赋值 xiaoming.name = "小明"; xiaoming.age = 18; xiaoming.score = 100; //2. 直接实例化并且赋值 struct Student xiaohong = {"小红", 18, 100}; //3.(不常用) 创建结构体时顺便创建结构体变量 struct Student { string name; int age; }s3; //这里S3已经被实例化了struct 关键字在实例化时可以省略,在定义结构体时不可以省略
这与C语言有区别,C语言在使用结构体创建实例时必须携带STUCT关键字,除非是用TYPEDEF省略定义;
C++也有typedef语法,但是几乎不适用,因为在创建实例时可以省略关键字
C++唯一需要typedef的时候就是兼容C语言的写法可以这么写
若实在想给结构体取别名,使用如下语法
struct Student { int age; int height; }; using Student = St;//using 这个语法就可以起别名10.2 结构体数组
创建一个可以储存结构体的数组
**语法: **struct Student arr[元素个数] = {{}, {}, {}, ... };
结构体数组中存放的是实例化的结构体变量
//EG. struct Student { string name; int age; int score; }; struct Student stuArray[3] = { {"张三", 18, 100}, {"李四", 20, 98}, {"王五", 38, 19} };//创建结构体数组 //给结构体数组中的元素赋值或者更改属性值 stuArray[0].name = "赵四";//遍历结构体数组 for(int i = 0; i < 3; i++) { cout << "姓名:" << stuArray[i].name << " 年龄: " << stuArray[i].age << " 成绩: " << stuArray[i].score << endl; };注:结构体数组名作为参数传入函数属于"地址传递"
当然,从底层机制来看,属于数值传递,因为传递的是地址数值的副本,但虽然指针本身是副本,指向的数组却没有改变,所以修改内容相当于修改原数组
void func(struct Student arr[50]); // 写法1:看起来像数组
void func(struct Student arr[]); // 写法2:省略长度
void func(struct Student *arr); // 写法3:显式指针(最常见)这三种写法完全等价
10.3 结构体指针
10.3.1 定义
结构体类型名 * p = 地址;
//实例.structStudent{string name;intage;intscore;};Student s={"zhang",18,99};Student*p=&s;//初始化结构体指针实际上还是
数据类型 * 指针名字 = 具体地址;
10.4 结构体嵌套
在结构体中可以嵌套另一个结构体,用于解决复杂问题
//实例.structStudent{intage;string hobby;structsports;//struct关键字可以省略};structsport{string basket;string football;};调用结构体的子结构体时多写一些
Student stu;stu.s.basket="nike";10.5 结构体做函数的参数
//1. 值传递打印结构体信息 struct student { string name; int age; }; student s = {"张三", 18}; void print(student stu) { cout << "姓名 : " << stu.name << " 年龄: " << stu.age << endl; } //2. 地址传递时会修改实参,但是上边的值传递不会将传入参数改为指针,可以节省内存空间,因为指针变量占用的内存很小,若要值传递则会把原来的变量所有的值复制一遍,非常占内存
10.6 结构体中的const
当把结构体作为传入的参数且利用地址传递时使用,可以防止误操作结构体属性
void print_st(const student* stu) { stu -> age = 18;//这里会报错,因为使用了CONST关键字不允许修改该该变量的值 }