C++基础学习笔记(适合小白) 基础认知//基础框架#includeiostreamusingnamespaceintmain(){....}//输出cout要输出的内容endl;1.变量1.定义变量//数据类型 变量名 变量初始值 //跟C语言一样 int a 10;2.变量命名规则不能是关键字标识符由字母,数字,下划线构成数字不能是变量的第一个字符标识符是会区分大小写的2.常量有两种定义1.#define 定义宏常量通常定义在文件上方2.const修饰的变量定义在文件内注意:常量是不可以修改的,一旦修改就会报错//#define 常量名 常量值#defineday7intmain(){.....}//const 变量类型 变量名 变量值;intmain(){constintday7;}3.关键字1.定义:是c中预定义的,不能用这些名字赋变量或常量,不然会报错4.数据类型4.1 存在意义为了给变量分配合适的内存4.2 具体类型整型变量:表述整数类型的变量短整型 short :2byte整型 int : 4 byte长整型 long : 4 byte(windows), 8byte(linux)长长整型 long long : 8 byte2.实型- 单精度 float 4byte (默认情况下输出一个小数会输出六位有效数字)floata3.12444;- 双精度 double 8byte科学计数法floata32e4;//e 后边代表是10的的多少次方,可正可负3.字符型所占内存大小: 一个字节//创建方法 char 变量名 ;charaa;//赋值时必须使用单引号,且只能有一个字符可以强制转换为(int)类型查看对应的ASCII4.字符串型//创建格式(C语言风格)char变量名[]字符串的值;//注意,需要使用双引号//创建格式2(C)#includestringstring strhello;5.布尔类型代表真和假,只有两个值,true false,只占用一个字节的空间boolflagtrue;4.3 sizeof 关键字用于判断占用的内存空间//eg.sizeof(int);// 4longnum3;sizeof(num);// 84.4 转义字符用反斜杠来转义后面的符号,使其失去原有的意思直接输出\n 换行\t 制表4.5 数据输入需要使用关键字cin()//具体实现inta0;cout请赋值Aendl;cina;coutA的值是:aendl;5.运算符1.算术运算符用于处理四则运算有以下几种(具体含义与C语言一样,用法也差不多)%–2.赋值运算符:直接赋值-*/%//演示//赋值运算符可以看做对自身的处理a2;//实际上就是 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 whiledo{执行语句;}while(条件)与while的区别:先执行一次语句,再去判断条件进行重复执行形象说明:拿钥匙开锁这个场景,每次先拿钥匙试下,如果不行就换钥匙直到开锁练习:水仙花数,prac_base func_1%10 获取个位数字/10 %10 获取十位数字/100 %10 获取百位数字6.2.3 for 循环作用:满足条件就循环,但是是有限次次数for(起始表达式;条件表达式;末尾循环体){执行语句;}执行流程:初始化-满足条件-执行循环语句-执行末尾循环体-判断条件…eg.for(inti0;i5;i){coutiendl;}注意:for循环需要用;隔开练习敲桌子func_2 prac_base.cpp6.2.4 嵌套循环练习: base.cpp nested_loopprac_base .cpp times_tables6.3跳转语句6.3.1 break语句练习: base.cpp jump()作用:跳出选择结构或者循环结构switch放在case后,跳出case分支循环语句中用于跳出循环嵌套循环语句退出内层循环6.3.2 continue语句作用:跳出本次循环中余下尚未执行的语句,进行下次循环注意:与break的区别,continue是执行到这一行就不执行了,进行下次循环,但是break是直接退出循环//eg.输出奇数不输出偶数for(inti0;i9;i){if(i%20){continue;}coutiendl;}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};coutsizeof(arr)endl;//输出 : 12byte//算出数组元素个数intlensizeof(arr)/sizeof(arr[0]);//获取首地址cout数组的首地址为:(int)arrendl;//获取第一个元素的地址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(inti0;i9;i)//输出原数列{coutarr[i] ;}coutendl;//开始排序for(inti0;i9-1;i){for(intj0;j9-i-1;j){if(arr[j]arr[j1])//前一个数字比后一个大就交换顺序{inttemparr[j];arr[j]arr[j1];arr[j1]temp;}}}for(inti0;i9;i)//输出排序完成的数列{coutarr[i] ;}coutendl;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(){cout1endl;}//无参无返voidpass_1(inta){coutaendl;}//有参无返intpass_2()//无参有返{inta20;coutaendl;returna;}intpass_3(inta){coutaendl;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 NULL9.4 野指针定义:指向非法内存空间的指针变量//eg. int * p (int*)0x1100; //这里是利用了强制转换,但实际上并没有申请这块内存空间,所以没有办法解引用或者操作这块空间,此类指针十分危险且无法被引用,被称为野指针9.5 CONST修饰指针9.5.1 常量指针在指针变量前增加constconst int * p a;特点:指针的指向可以修改,指针指向的值不可以修改解释:就是说,指针变量可以重新指向另一个内存位置,但是指针变量指向的内存地址的值不可以修改9.5.2 指针常量int * const p a;指针的指向不可以改,但是指针指向的值可以修改纯常量:const int * const p a;9.6 指针与数组作用:利用指针访问数组元素egintarr[10]{1,2,3,4,5,6,7,8,9,10};int*parr;//arr就是数组首地址for(inti0;i10;i){cout第i1个数据是: ;cout*pendl;p;}例子 base.cpp pter_arr()9.7 指针与函数作用: 利用指针作为形参,可以改变实参的值不只是作为值传递,而是作为地址传递eg.//利用指针进行数字交换inta10;intb20;voidswap2(int*a,int*b){inttemp*a;*a*b;*btemp;}//利用地址传递,直接交换两个实参的值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*ps;//初始化结构体指针实际上还是数据类型 * 指针名字 具体地址;10.4 结构体嵌套在结构体中可以嵌套另一个结构体,用于解决复杂问题//实例.structStudent{intage;string hobby;structsports;//struct关键字可以省略};structsport{string basket;string football;};调用结构体的子结构体时多写一些Student stu;stu.s.basketnike;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关键字不允许修改该该变量的值 }10.7 练习