C++基础

1.初识C++

1.1标准输出和输入

基本语法:

  1. 标准输入cin >> a;
  2. 标准输出cout << "文字提示" << 变量或表达式 << endl;这里 endl 相当于回车

在使用 cincout 时,要在源文件最上方加上 #include <iostream>using namespace std;

1.2注释

分为单行注释和多行注释:

  1. 单行注释用 //
  2. 多行注释用 /* */

1.3变量

定义为数据类型+变量名+赋初值

1.4常量

定义方式有两种

  1. #define宏常量,通常定义在文件最上方
  2. const修饰的变量,一般定义在函数内部

两种定义的常量都是不能被修改的,否则会报错。

1.5关键字

在给变量和常量起名字时,不要用关键字作变量名。

1.6标识符命名规则

给变量起名字时,最好做到见名知意。

2.数据类型

2.1整型

数据类型占用空间取值范围
short(短整型)2字节-215到215-1
int(整型)4字节-231到231-1
long(长整型)win下4字节、Linux下4字节(32位)、8字节(64位)-231到231-1
long long(长长整型)8字节-263到263-1

如果超出范围会发生一些有意思的事,比如:short a=32768;实际上a打印出来为-32768,从上限反转到下限。

其中int最为常用。

2.2 sizeof()

sizeof(数据类型/变量),返回是字节数

2.3浮点型

分为 floatdouble ,单精度占4个字节、双精度占8个字节,区别就是有效数字位数不同,不管是单精度还是双精度在打印时只显示6位有效数字

科学计数法:3e2 意思是3*10^2=300,e之后的数字表示10的多少次方。

2.4字符型

字符型变量占用1个字节空间,字符型变量并不是把字符本身放到内存中去存储,而是将对应的 ASCII 编码放入存储单元,想要打印 ASCII 的值可以用 (int)a 来转换。可以直接用 ASCII 给字符型变量赋值如:ch = 97;

常见的一些错误如下:

2.5转义字符

常用的几个如下:

2.6字符串型

两种风格

2.7 bool类型

bool类型只占用一个字节的空间,只有两个值 true 或 false 本质分别为1和0。

2.8数据的输入

主要语法用到 cin >> 变量,cin可以为整型、浮点型、字符型,字符串型、bool型(只要是输入非0的值,都会赋值成1)赋值。

3.运算符

3.1算术运算符

加减乘除,应当注意的是除法运算,两个整型数相除结果依然是整型,0不能作除数否则报错。

取模运算即取余数使用 % ,应当注意的是 0不能作为取余运算的右操作数,且两个小数不能作取余运算。

前置递增和后置递增,都可以让变量加1,但是它们的区别是:前置递增是先让变量+1,再进行表达式的运算,后置递增是先进行表达式的运算,再让变量+1。前置递减和后置递减也是同样的道理。

3.2赋值运算符

举例如下:

3.3比较运算符

主要有大于、小于、等于、不等于、大于等于、小于等于。比较运算表达式的结果为0或1,0代表逻辑 false ,1代表逻辑 true 。

注意:

3.4逻辑表达式

主要有与(&&)、或(||)、非(!)三种。

4.程序流程结构

4.1选择结构

4.1.1 if语句

1.单行 if 语句,语法如下:

注意的是 if(条件) 后面不要加分号,否则不管条件满足与否都会执行后面语句。

2.多行 if 语句,语法如下:

3.多条件的 if 语句,语法如下:

4.此外 if 语句还支持嵌套,让条件判断更加精细

4.1.2三目运算符

语法为:表达式1 ? 表达式2 : 表达式3;

如果表达式1的值为真,执行表达式2,并返回表达式2的结果;如果表达式1的值为假,执行表达式3,并返回表达式3的结果。在C++中三目运算符返回的是变量,可以继续赋值,举例如下:

通过上面例子可以知道,三目运算符表达式既可以作左值也可以作右值。

4.1.3 switch 语句

语法如下:

case 里面如果不写 break 程序会一直向下执行

与 if 的区别:

4.2循环结构

4.2.1 while 循环语句

语法:while (循环条件) {循环语句}

只要循环条件为真,就一直执行循环内的语句,要检查是否有跳出循环的出口,除非有的时候我们确实需要死循环。

做一个猜数字的案例,随机生成一个1到100的随机数,让玩家去猜,每次猜系统要提示玩家大了小了,直到玩家猜对为止,游戏结束。

生成一个1到100的随机数,代码为:

4.2.2 do while 循环语句

语法:do {循环语句} while(循环条件);

与 while 循环语句不同的是 do while 至少保证代码执行一次

可以写一个水仙花数案例,找出所有的水仙花数,水仙花数是指一个三位数,它各位数字的三次幂之和等于它本身的数。

4.2.3 for 循环语句

语法:for (起始表达式;条件表达式;末尾循环体) {循环语句}

注意 for 循环中的表达式要用分号分隔

4.2.4循环嵌套

可以尝试打印9*9乘法表

4.3跳转语句

4.3.1 break 语句

用于

4.3.2 continue 语句

用于在循环语句中,跳过本次循环中余下的未执行语句,继续执行下一次循环。例如可以充当一个筛选条件,打印0到100之间所有的奇数。

4.3.3 goto 语句

可以无条件的跳转代码,语法是 goto 标记; 这个标记一般用大写的单词来定义,例如:FLAG。在所需要跳转到地方写一个FLAG:然后当程序执行到 goto 语句的时候就能实现跳转。不过由于 goto 语句过于强大,不推荐使用,容易造成程序流程混乱。示例如下:

5.数组

5.1概述

数组两个特点

5.2一维数组

5.2.1一维数组定义方式

一维数组定义的三种方式

1.数据类型 数组名[数组长度];

2.数据类型 数组名[数组长度] = {值1,值2……}; 定义的时候赋初值,如果初始化的时候没有全部填写完会用0来填充剩余的数据比如:

3.数据类型 数组名[] = {值1,值2……};初始化几个值,数组长度就为几,不允许不赋值如:int arr[];错误!

需要注意的是一旦采用第一种方式,后面就不能群体赋值了

5.2.2一维数组数组名

一维数组名称的用途:

  1. 可以统计整个数组在内存中的长度 sizeof(数组名);,返回结果为字节数。如果要看每个元素占用的大小代码为 sizeof(数组名[0]);如果要看元素个数两个相除就可以。
  2. 可以获取数组在内存中的首地址,示例如下:

数组名一旦定义就成为一个常量,不能再对其进行赋值操作。

5.2.3冒泡排序

冒泡排序是一个比较重要的排序算法,下面为升序的冒泡排序代码:

5.3二维数组

5.3.1二维数组定义方式

二维数组定义的四种方式

  1. 数据类型 数组名[行数][列数];
  2. 数据类型 数组名[行数][列数]={{数据1,数据2},{数据3,数据4}};
  3. 数据类型 数组名[行数][列数]={数据1,数据2,数据3,数据4};
  4. 数据类型 数组名[][列数]={数据1,数据2,数据3,数据4};

需要注意的是一旦采用第一种方式,后面就不能群体赋值了

这里比较推荐第二种定义方式,直观简单。

5.3.2二维数组数组名

一维数组名称的用途:

  1. 查看二维数组所占内存空间。可以统计整个数组在内存中的大小 sizeof(数组名);,返回结果为字节数。如果要看每一行占用的大小代码为 sizeof(数组名[0]);,如果要看每一个元素占用内存的大小代码为sizeof(数组名[0][0])

    计算二维数组行数代码为sizeof(数组名)/sizeof(数组名[0]);,计算二维数组元素个数代码为 sizeof(数组名)/sizeof(数组名[0][0]);

  2. 获取二维数组首地址。示例如下:

5.3.3二维数组应用案例

成绩统计,每个人有多门课程成绩,需要用到二维数组

在存储人名的时候可以用一个字符串数组,如下:

6.函数

6.1概述

作用:将一段经常使用的代码封装起来,减少重复性代码。

6.2函数的定义

语法如下:

6.3函数的调用

语法为:函数名 (参数);

6.4值传递

值传递的时候,形参发生任何改变都不会影响实参。可以从内存分配的角度来理解。

6.5函数常见样式

常见有四种类型:

  1. 无参无返
  2. 无参有返
  3. 有参无返
  4. 有参有返

6.6函数的声明

一般情况下,自定义的函数要写在main函数的前面,如果自定义函数写在main函数之后,需要用到函数声明,语法为:

返回值类型 函数名 (参数列表);而且声明可以写多次,但是定义只能定义一次。

6.7函数的分文件编写

步骤为:

  1. 创建.h后缀的头文件
  2. 创建.cpp后缀的源文件
  3. 在头文件中写函数的声明
  4. 在源文件中写函数的定义

注意:在上述的源文件中,开头要写 #include "头文件名.h"这个就代表了头文件和源文件它俩之间是配套的(即有关联的) ;在上述的头文件中,要包含源文件用到的一些标准库,比如源文件中用到cout、cin,那么头文件开头就要写 #include<iostream>using namespace std; 最后,在main函数所在的源文件上方写 #include "头文件名.h"

7.指针

7.1指针的基本概念

指针的作用:可以通过指针间接访问内存

7.2指针变量的定义和使用

指针变量定义的语法为:数据类型 *变量名;下面为示例:

7.3指针所占内存空间

在32位操作系统下,指针都是占4个字节大小空间,不管是什么数据类型;在64位操作系统下,指针都是占8个字节大小空间,不管是什么数据类型。

7.4空指针和野指针

空指针作用:用于给指针变量进行初始化,空指针是不可以进行访问的,空指针NULL是0值,而0到255之间的内存编号是系统占用的,因此不可以访问。

野指针:指向非法的内存空间,示例如下:

空指针和野指针都不是我们申请的内存空间,因此不要去访问。

7.5 const 修饰指针

分为以下三种:

  1. const修饰指针 ---常量指针

    定义为:const int *p = &a;

    特点是:指针的指向可以修改,但是指针指向的值不可以改。*p = 20; 错误。p = &b; 正确。

  2. const修饰常量 ---指针常量

    定义为:int * const p = &a;

    特点是:指针的指向不可以修改,但是指针指向的值可以改。*p = 20; 正确。p = &b; 错误。

  3. const既修饰常量又修饰指针

    定义为:const int * const p = &a;

    特点是:指针的指向和其指向的值都不可以修改。*p = 20;p = &b; 均错误。

7.6指针和数组

利用指针来访问数组中的元素,下面为用指针遍历数组的示例代码:

7.7指针和函数

利用指针作函数参数,可以修改实参的值,示例代码如下:

这就是值传递与地址传递的不同之处。

7.8指针、数组、函数

做一个综合案例,封装一个函数,利用冒泡排序实现对一个数组的升序排序。数组为 int arr[10] = {4,3,6,9,1,2,10,8,7,5};

通过这个案例可以知道,当我们要向一个函数传递一个数组的时候,往往要用指针去接收它,而且为了方便一般还要传入数组的长度。

8.结构体

8.1结构体基本概念

结构体属于用户自定义的数据类型,允许用户存储不同的数据类型。

8.2结构体的定义与使用

语法:struct 结构体名 {结构体成员列表};

通过结构体创建变量的方式有三种:

  1. struct 结构体名 变量名;
  2. struct 结构体名 变量名 = {成员1的初值,成员2的初值……};
  3. 定义结构体时顺便创建变量

8.3结构体数组

语法:struct 结构体名 数组名[元素个数] = {{},{}……};

结构体数组与其他数组一样,可以在创建的时候赋初值,也可以只创建,之后用.号来赋属性的值。

8.4结构体指针

利用操作符->可以通过结构体指针访问结构体属性。

8.5结构体嵌套结构体

在结构体中可以定义另一个结构体作为成员,形成结构体嵌套结构体。

8.6结构体作函数参数

将结构体作为参数向函数中传递,传递方式有两种:

  1. 值传递
  2. 地址传递

比如说,向子函数传一个学生的结构体,要求子函数打印学生的信息,代码如下:

值传递和地址传递的不同在于:值传递不能改变实参的值,而地址传递可以。

8.7结构体中 const 的使用场景

作用:用 const 来限定只读操作,防止误修改

应用场景的产生:在向子函数传递一个结构体时,如果采用值传递,那么会在子函数中复制出一个新的副本,当结构体十分庞大时会占用比较多的内存资源,所以我们采用地址传递(只传入地址4个字节节省内存空间),但是地址传递可以修改实参的值,容易造成误修改。此时就有了使用 const 的必要 ,加入 const 之后一旦有修改的操作就会报错,可以防止误操作。