变量:
变量是专门用来存储数据的容器,会根据数据类型决定容量大小。
代码中的 int
(integer)用来明确变量的数据类型
int
型数据的变量可以用来存储整数,如:1
、23
、-1
等没有小数部分的数值int
型数据占有4个字节内存,不同类型的数据表示范围不同,占用的内存空间不尽相同
变量名的命名规则:
在C++中,变量名称也叫做标识符,表示⽤来标记和识别不同变量的不同的符号,有固定的构造规则:
- 只能由字⺟、数字和下划线组成;特别的;在C++中,标识符中的英文字母是区分大小写的;
- 例如:
sweet_popcorn
合法,但是zero&coke
使用了符号&
,因此不合法。
- 例如:
- 数字不可以出现在第一个位置上;
- 例如:
coke330
合法,但是330coke
以数字作为开头,因此不合法。
- 例如:
- 在C++中,标识符中的英文字母是区分大小写的;
- 例如:
coke330
和Coke330
表示的是完全不同的变量名称,即表示不同的标识符。
- 例如:
- C++的关键字(保留字)不可以⽤做标识符;
- 例如:
pout
合法,但是cout
是C++的关键字,不可以用作标识符,因此不合法 Tips: 无需背诵所有关键字
- 例如:
-
常见的关键字有
cout
、int
或include
等具有特殊含义的字符
变量名的初始化:
- 变量的初始化 即赋予变量一个初始值。
Tips: 我们来看一下money
这个变量,与变量coke
和popcorn
不同,总价(money)这个变量可以明确一个初始数值:0
。所以,我们在定义这个变量同时,可以为它赋予一个初始值,即初始化变量money
。
int money = 0;
-
代码中的符号
"="
是赋值运算符- 操作是将符号
"="
右边的数值存放到 左边 的变量中 - 关于运算符,我们将在之后的课程中详细展开讲解
- 操作是将符号
-
变量在初始化时应该根据数据类型进行赋值,否则将会发生错误.
- 例如:不能把小数赋值给一个整数类型的变量
int a = 3.14 ;
是错误的。
- 例如:不能把小数赋值给一个整数类型的变量
-
未进行初始化的变量具有不确定的数值,直接进行计算将会发生错误
- 例如:没有初始化
sum
值,就进行相加计算。sum = sum + 1;
是不能够被执行的
- 例如:没有初始化
const 设置无法修改的常量
常量:
在C++编程中必须使用不能键入或具有特殊含义的字符。例如,换行符(回车),制表符,问号,引号等。为了使用这些字符,就会使用''开头的转义字符序列用来表示一个特殊字符。
例如:
ASCII编码:
-
字符串字面量是由一对双引号括起来的字符序列
-
字符串中可以包含类似于字符字面量普通字符以及转义字符
-
字符串除了存储所包含的字符外,还额外包含一个结束标志
'\0'
'\0'
:结束符;ASCII编码
对应数值为0
的字符
- 在C++中,随着程序运算不改变的量叫做符号常量,可以使用
const
关键字来定义并且初始化:
-
const
是⼀个修饰符,加在数据类型int
的前⾯,用来给这个变量加上一个不变的属性- 初始化时也可以将修饰符const与数据类型
int
调换位置,写成int const kCokePrice = 5;
- 初始化时也可以将修饰符const与数据类型
最后,总结一下符号常量的初始化伪代码:
总结:
常量指不会随着程序运行而改变的量,分为两种:字面量和符号常量。
字面量
-
我们将存放在变量中的数据称之为字面量。
-
把字面量装到变量中使用的操作叫做赋值,一般写法为
变量名 = 字面量
,比如:
字面量分为以下几种不同类型:
-
整数字面量:没有任何小数或指数部分的数字字面量,与数学中的整数直接关联。
如十进制的
13
,八进制的0123
,十六进制的0x12a
。 -
浮点字面量:有分数形式或指数形式的数字字面量,与数学中的小数直接关联。
如小数形式的
0.66
,指数形式的1.23E-1
。 -
字符字面量:分为单字符字面量与转义符字面量。如字母
'a'
,换行符'\n'
,所有字符都采用ASCII编码,共有128个字符。 -
字符串字面量:由一对双引号括起来的字符序列。
如
"Hello, World!"
。
符号常量
- 随着程序运算不改变的量,赋予名称之后,有一个特定的名字,叫做符号常量,可以使用
const
关键字来定义并且初始化:
数组初始化
- 在C++中,数组的初始化有如下两种方式:
- 一种初是在声明的同时,使用大括号包含对应数值,直接对整个数组初始化
- 另一种初始化方式是在声明之后,逐个访问数组元素进行一一初始化赋值
举例:小六店里的商品第一个月卖出1件,接下来每个月都卖出2件,那么每个月统计的累计销量应该是1、3、5、7、9、11。
-
选择直接对整个数组初始化时:
- 如果大括号中给出的值的数量等于元素数量,会把这些值依次赋给所有元素
- 比如
int sales[6] = {1, 3, 5, 7, 9, 11}
- 比如
- 如果大括号中给出少于元素数量,会把这些值赋给前面几个元素,后面的默认为0
- 比如
int sales[6] = {1, 3}
,那么可以得到6个元素分别为:1, 3, 0, 0, 0, 0 的数组 - 如果想把数组全部初始化为0,可以写成
int sales[6] = {0}
- 比如
- 对整个数组初始化的时候,可以省略中括号中的数组长度,这样初始化的数组长度就是大括号中元素的数量
- 比如
int sales[] = {1, 3, 5, 7, 9, 11}
会初始化一个长度为6的整型数组,与int sales[6] = {1, 3, 5, 7, 9, 11}
是等价的。
- 比如
- 如果大括号中给出的值的数量等于元素数量,会把这些值依次赋给所有元素
-
选择在声明之后对数组中的元素逐个进行初始化赋值时:
- 可以借助循环,按照索引的范围逐个赋值
数组怎么输入输出呢?
- 在C++中,普通的一维数组只能对单个元素进行输入输出。
-
举例:输入输出数组中第一、二个月的累计销量:
一维数组输入输出的程序段
多维数组:
除了一维形式的数据,现实生活中也有多个维度的复杂数据。
- 在C++中,每一个元素也是数组的数组称为多维数组。
- 例如,二维数组可以看作是每个元素都是一维数组的数组
- 类似一维数组,二维数组依然通过索引来访问元素
- 数组每一维度的索引范围是从
0
到维度长度-1
- 数组元素的访问形式是
数组名称[行索引][列索引]
- 数组每一维度的索引范围是从
-
二维数组的初始化
二维数组的初始化有两种方式:
- 第一种方式是在声明时对整个二维数组初始化:
-
二维数组初始化的程序段(一):
int scores[5][3] = {
{8, 4, 6} , /* 初始化索引号为 0 的行 */
{5, 6, 3} , /* 初始化索引号为 1 的行 */
{3, 2, 4} , /* 初始化索引号为 2 的行 */
{8, 7, 6} , /* 初始化索引号为 3 的行 */
{7, 9, 8} , /* 初始化索引号为 4 的行 */
};
// 或者省略掉第二层的大括号
int scores[5][3] = {8, 4, 6, 5, 6, 3, 3, 2, 4, 8, 7, 6, 7, 9, 8};
Tips:在这种情况下,如果给出的元素数量少于本身的数量,那么后面的依然会被默认初始化为0。
- 第二种初始化方式是在声明后分别对每一个元素逐一进行访问,并且进行初始化赋值
- 可以借助for语句的嵌套来实现
二维数组初始化的程序段(二):
int scores[5][3];
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 3; j++) cin >> scores[i][j];
}
Tips:在这种情况下,需要事先明确每个for语句的循环次数。否则,可能会产生数组越界等问题。
二维数组的输入输出
-在C++中,和一维数组一样,普通的二维数组也只能对单个元素进行输入输出。
举例:输入输出二维数组中第一位评委对第一、二位选手的打分:
二维数组输入输出的程序段
int scores[5][3] = {0};
cin >> scores[0][0];
scanf("%i", &scores[0][1]);
cout << scores[0][0];
printf("%i", scores[0][1]);
多维数组的声明
声明多维数组仍然需要指定元素的类型和每个维度的数量:
元素类型 数组名称[数组第1个维度长度][数组第2个维度长度]...[数组第n个维度长度]
多维数组访问元素
和一维数组一样,多维数组依然是通过索引来访问元素,访问方式为数组名称[第1个维度索引][第2个维度索引]...[第n个维度索引]
。
字符数组:
字符数组与字符串
- 由一系列字符组成的一个处理单位称为字符串,如一个单词或一个句子。
- C++ 中的字符串常量是用一对双引号括起来,由
'\0'
作为结束符的一组字符。
- C++ 中的字符串常量是用一对双引号括起来,由
Tips:不含任何字符的字符串称为空字符串,用一对双引号表示,即 ""
。空字符串并不是不占空间,而是占用了 11 字节的空间,这个字节中储存了一个 '\0'
。
- 通常用一个字符数组来保存字符串,即所有元素的类型都是字符型的数组
- 由于字符串以
'\0'
作为结束符,因此所需的储存空间比实际的字符串长度大 11。
- 由于字符串以
举例:小六要创建一个用户名"LaoWang"
,就可以用一个长度大于等于8的字符数组来表示,前面8个元素分别是:'L'
, 'a'
, 'o'
, 'W'
, 'a'
, 'n'
, 'g'
, '\0'
。
Tips:在 C++ 中,'a'
和 "a"
是不一样的,前者是一个字符常量,在内存中占 11 字节,后者是一个字符串,占 22 字节的空间,第 11 个字节储存了字母 a
的内码值,第二个字节储存了 '\0'
。
- 字符数组的声明
- 字符数组型字符串的声明和普通字符数组一样,不过有一个需要注意的地方:字符数组的长度需要比字符串的字符数量多1个,因为需要补充一个
\0
,作为字符串结尾的标志。
- 字符数组型字符串的声明和普通字符数组一样,不过有一个需要注意的地方:字符数组的长度需要比字符串的字符数量多1个,因为需要补充一个
举例:char userName[11]
就可以声明一个名字叫userName
的字符数组型字符串,这个数组最多能存放一个长度为10的字符串。
-
// 第一种:给每个元素指定初始化值 // 依次赋初值,剩下的会默认被初始化为\0 char userName[11] = {'L', 'a', 'o', 'W', 'a', 'n', 'g', '\0'}; char userName[11] = {'L', 'a', 'o', 'W', 'a', 'n', 'g'}; // 和普通数组一样,元素个数可以省略,c++会自动识别长度为8 char userName[] = {'L', 'a', 'o', 'W', 'a', 'n', 'g', '\0'};
字符数组的访问元素
- 和普通字符数组一样,字符数组型字符串也可以直接通过索引来访问
- 比如访问第一个元素就可以用
userName[0]
- 比如访问第一个元素就可以用
- 和普通字符数组一样,字符数组型字符串也可以直接通过索引来访问
-
字符数组的初始化
- 第一种初始化方式和普通的字符数组是相同的,给每个元素指定初始化值,不过需要补充上字符
'\0'
字符数组初始化的程序段(一)
- 第一种初始化方式和普通的字符数组是相同的,给每个元素指定初始化值,不过需要补充上字符
// 第一种:给每个元素指定初始化值
// 依次赋初值,剩下的会默认被初始化为\0
char userName[11] = {'L', 'a', 'o', 'W', 'a', 'n', 'g', '\0'};
char userName[11] = {'L', 'a', 'o', 'W', 'a', 'n', 'g'};
// 和普通数组一样,元素个数可以省略,c++会自动识别长度为8
char userName[] = {'L', 'a', 'o', 'W', 'a', 'n', 'g', '\0'};
- 第二种是使用字符串常量初始化字符数组
字符数组初始化的程序段(二)
//第二种:使用字符串常量初始化字符数组
char userName[11] = {"LaoWang"};
// 大括号可以省略
char userName[11] = "LaoWang";
字符数组的输入输出
字符数组可以进行逐个字符的输入输出,这种做法和普通的数组操作一样,分为以下两种方式:
-
将整个字符串一次性地用对象
cin
和cout
的>>
和<<
操作完成输入或输出。 -
通过
cin
的成员函数get
或getline
输入。 -
方式一:使用
cin
和cout
-
对于字符数组
userName
,输入一个字符串到数组中,可以使用语句:
-
cin >> ch;
-
- 输入的时候,使用
cin
语句,会不断的读入字符串,直到遇到一个空白字符(空格、回车或者制表符)就结束读入 - 用
cin
向计算机输入一串字符时,输入的字符的数量应该少于已定义的字符数组的长度,否则会出现问题 - 如果输入的字符的数量小于字符数组长度时,剩下的部分会默认补上
'\0'
- 输入的时候,使用
cout << ch;
-
对于字符数组
userName
,输出其中的内容: - 从字符数组的第一个字符开始输出,直到遇到
'\0'
(不会输出'\0'
)- 如果一个字符数组中包含一个以上
'\0'
,则遇第一个'\0'
时cout
输出就结束
- 如果一个字符数组中包含一个以上
-
方式二:用
scanf
printf
也可以输入输出字符串,有以下一些需要注意的点:- 字符的输入用
scanf("%c", &变量名)
,而输入一个字符串用scanf("%s", 数组名)
- 字符的输入用
- 从字符数组的第一个字符开始输出,直到遇到
'\0'
(不会输出'\0'
)- 如果一个字符数组中包含一个以上
'\0'
,则遇第一个'\0'
时cout
输出就结束
- 如果一个字符数组中包含一个以上
-
方式二:用
scanf
printf
也可以输入输出字符串,有以下一些需要注意的点:- 字符的输入用
scanf("%c", &变量名)
,而输入一个字符串用scanf("%s", 数组名)
- 字符的输入用
scanf("%s", userName);
-
- 注意,因为是字符串也是一个字符数组,
scanf
里,数组前不需要加&
,只有变量名字需要加&
。
- 注意,因为是字符串也是一个字符数组,
- 字符的输出用
printf("%c", &变量名)
,而输出一个字符串用printf("%s", 数组名)
printf("%s", userName);
字符数组型字符串的常用操作
字符串不能用系统的内置运算符进行操作,C++语言设计了一个 cstring
库,提供了一些用来处理字符串的函数。
-
连接字符串
使用
strcat(s1, s2)
函数可以把字符串s2
连接到s1
的末尾。 -
获取字符串长度
使用
strlen(s1)
函数可以返回字符串s1
的有效字符数。比如"yes"的长度就是3。 -
比较字符串的字典序
使用
strcmp(s1, s2)
函数可以比较两个字符串之间的字典序:如果s1
和s2
是相同的,会返回0;如果s1
的字典序在s2
前面,则返回值会小于0;如果s1
的字典序在s2
后面,则返回值会大于0。 -
复制字符串
使用
strcpy(s1, s2)
函数可以复制字符串s2
到字符串s1
。如果s2
比s1
短,那么s1
这个数组后面没被覆盖的部分不会改变。比如s1
存的是{q, w, e, r, \0}
,s2
存的是{a, s, \0}
,那么使用strcpy(s1, s2)
后,s1前五位应该是{a, s, \0, r, \0}
。
string 类型的基本操作
- 字符数组型字符串是把字符串当作一个元素为字符的一维数组,而 string 类型是直接把字符串当作一个整体,可以像整型变量、字符变量一样使用。
string 类型的用法有以下一些注意点:
-
头文件
- 首先需要加载 string 类型所在的头文件。
# include <string> 声明和初始化 string 类型的声明和初始化和普通变量一样。 // 声明 string a; // 声明与初始化 string b = "yes"; 输入输出
-
声明和初始化
- string 类型的声明和初始化和普通变量一样。
-
输入输出
- string 类型的字符串一般直接通过
cin
和cout
进行输入输出。- 输入的时候,使用
cin
语句,会不断的读入字符串,直到遇到一个空白字符(空格、回车或者制表符)就结束读入 - 输出的时候,从字符串中第一个字符开始输出,直到遇到
'\0'
(不会输出'\0'
)
- 输入的时候,使用
- string 类型的字符串一般直接通过
string 类型的常用操作
对于string 类型的字符串,官方提供了一些字符数组型字符串常用处理函数,可以对字符数组型的字符串进行一些常规操作。本节选取抽取一些常用操作,和字符数组型字符串对照讲解一下:
-
连接字符串
- 字符数组型字符串会使用
strcat(s1, s2)
函数把字符串s2
连接到s1
的末尾。 - string 类型可以直接使用
s1 + s2
连接两个字符串。
- 字符数组型字符串会使用
-
获取字符串长度
- 字符数组型字符串会使用
strlen(s1)
函数返回字符串s1
的字符数。 - string 类型可以直接使用
s1.size()
或者s1.length()
返回字符串s1
的字符数。
- 字符数组型字符串会使用
-
比较字符串的字典序
- 字符数组型字符串会使用
strcmp(s1, s2)
函数比较两个字符串之间的字典序:- 如果
s1
和s2
是相同的,会返回0 - 如果
s1
在s2
前面,则返回值会小于0 - 如果
s1
在s2
后面,则返回值会大于0
- 如果
- string 类型可以直接使用关系运算符来比较两个字符的字典序:
- 如果
s1 < s2
为1
(真),就表示s1
的字典序在s2
前面 - 如果
s1 < s2
为0
(假),就表示s1
的字典序不在s2
前面
- 如果
- 字符数组型字符串会使用
-
复制字符串
- 字符数组型字符串使用
strcpy(s1, s2)
函数复制字符串s2
到字符串s1
。 - string 类型可以直接使用赋值表达式
s1 = s2
来复制字符串s2
到字符串s1
。
- 字符数组型字符串使用
string 类型的其他非常方便的操作函数,详见下面的表格:
函数的声明
- 函数的声明是为了告诉编译器如何调用这个函数,形式如下:
返回值类型 函数名(参数1类型 参数1, 参数2类型 参数2, ..., 参数n类型 参数n);
- 返回值类型:一个函数可以返回一个值,返回值类型是函数返回的值的数据类型。
- 有些函数执行所需的操作而不返回任何值,此时的返回值类型是
void
- 有些函数执行所需的操作而不返回任何值,此时的返回值类型是
- 函数名:这是函数的实际名称
- 一般会按照函数功能取名
- 参数:声明时的参数称为形式参数,类似于占位符
- 参数是可选的,函数可能不包含参数,也可以包含很多个参数
- 在函数被调用之前,我们并不知道形式参数的值是什么
- 返回值类型:一个函数可以返回一个值,返回值类型是函数返回的值的数据类型。
举例:声明一个MyMax
函数,函数功能是得到两个数字中最大的那一个数字。
- 语句
int MyMax(int a, int b);
声明了这个函数- 函数的名称叫做
MyMax
- 函数需要接收两个整数类型的参数
- 函数返回一个整数类型的值
- 函数的名称叫做
函数的定义
- C++中定义函数时,需要在声明的基础上写好函数体,函数定义的形式如下:
返回值类型 函数名(参数1类型 参数1, 参数2类型 参数2, ..., 参数n类型 参数n) {
函数体
}
举例:在声明后,定义MyMax
函数,实现返回两个整型数中更大的一个数的功能。
参数传递: 传值和引用
调用函数时,参数的传递一般分为传值传递和引用传递
- 传值传递
- 把参数的实际值赋值给函数的形式参数
- 修改函数内的形式参数对实际参数没有影响
- 引用传递
- 该方法把参数的引用赋值给形式参数
参数传递:参数默认值
- 函数定义时,我们可以给函数的参数设置默认值
- 这样我们调用函数时,可以选择不传递参数,选择默认的参数。
递归函数的两个基本要素
递归关系
- 问题规模为n时与问题规模为n-1时之间的转换关系
- 计算某个数字的阶乘,递归的关系就是:数字n的阶乘 = 数字n * 数字n-1的阶乘
- 这个函数可以写成: 递归关系的程序段
递归的终止条件
- 递归关系需要有一个递归终止的条件。
- 在计算阶乘中,递归终止的条件是计算到数字1的阶乘的时候,函数可以直接返回数字1的阶乘就是1
- 补充上这个条件: 递归终止条件的程序段