还得学C++,简单初入门

还得学C++,简单初入门

一、C++入门

  • C++语言
    • 计算机程序指的是计算机能识别和执行的一系列指令。
    • 我们在设计程序与计算机沟通时,需要学习使用一门计算机可以看得懂的语言。
    • C++语言作为求职面试以及算法竞赛中的常用编程语言,是我们学习计算机语言的首选。

第一个C++程序
使用C++打印出Hello, World!,常用来检测语言的开发环境是否安装妥当

//导入系统输入输出头文件 iostream
#include <iostream>

//使用标准命名空间 std
using namespace std;

int main() {
    //将 Hello, World! 打印在屏幕上,并且进行换行
    cout << "Hello, World!" << endl;
    return 0;
}

  • 编译预处理:所有#开头的代码

    • 当我们编写完源程序,在执行编译之前,编译器会首先调用预处理器,找到所有以#开头的代码行进行处理。
    • 预处理指令include意思是找到后面跟随的头文件,并且加载文件内容到程序中。
  • 使用命名空间namespace

    • 命名空间是C++中的一项特性,便于管理重复命名的功能模块。
    • 使用using声明之后,程序员可以直接使用命名空间中定义的名称,不需要额外指定前缀。
  • 程序中的主函数main

    • C++程序的运行从主函数main()开始。
    • 每个C++程序有且仅有一个main()函数,程序在运行时会自动调用main()函数。
  • 程序主体:cout打印内容

这行代码是一个语句,表示使用标准库函数提供的cout将"“中间的输出内容打印在屏幕上,并且进行换行。
每一个分号”;"表示一个语句的结束

  • 注释:藏在代码中的说明书
    • 在编译过程中,注释中的所有内容会被编译器自动忽略,最终也不会被执行。
    • 在C++中,以双斜杠"//"用来注释内容,之后的文字直到行末都为注释。
      现在你已经了解了如何使用C++语言让计算机输出Hello, World。

变量

  • 计算机的内存
    变量指的是会随着程序运算而改变的量。
    Tips: 比如用户在售卖机购买的可乐数量和爆米花数量都是不确定的,最后的总价也会各异,所以这些数量和总价都以变量的形式存在于计算机中。维护这些变量会用到计算机的存储功能。

    • 计算机的存储功能会使用内存实现。
    • 计算机中的操作系统一般会把内存划分成不同区域来存储数据,以便于管理。
    • 内存中每个基本存储单元可以存放一个字节的数据,每个字节具有8位,也就是8个比特(bit)。
    • 每个内存单元有一个唯一的地址,常用一个16进制数表示和区分。
  • 变量的声明

    • 变量的声明就是向内存申请变量,用于存放数据的过程,一般的声明方式为数据类型 变量名称。
// 声明可乐数量变量 coke
int coke;
// 声明爆米花数量变量 popcorn
int popcorn;
// 声明消费总额变量 money
int money;
  • 变量的命名规则
    变量名称也叫做标识符,有固定的构造规则:
    • 只能由字⺟、数字和下划线组成;
    • 数字不可以出现在第一个位置上;
    • C++的关键字(保留字)不可以⽤做标识符;
    • 最好简单易懂,用具有对应含义的英文或者拼音来表示;
  • 变量的初始化
    • 在声明变量时,也可以赋予这个变量一个初值,这被称为变量的初始化。
// 声明消费总额变量 money,并且初始化数值为 0
int money = 0;

变量的输出

  • 使用C++代码来在屏幕上展示初始化过的的消费总额,这叫做变量的输出,输出的内容是变量中保存的数值,而不是变量名称。
//将初始化好的消费总额打印在屏幕上,并且进行换行
cout << money << endl;

常量

常量指不会随着程序运行而改变的量,分为两种:字面量和符号常量

字面量

  • 我们将存放在变量中的数据称之为字面量。
  • 把字面量装到变量中使用的操作叫做赋值,一般写法为变量名 = 字面量,比如:
// 小戴需要2瓶可乐,3个爆米花
coke = 2;       
popcorn = 3;

字面量分为以下几种不同类型:

  • 整数字面量:没有任何小数或指数部分的数字字面量,与数学中的整数直接关联。
    如十进制的13,八进制的0123,十六进制的0x12a。

  • 浮点字面量:有分数形式或指数形式的数字字面量,与数学中的小数直接关联。
    如小数形式的0.66,指数形式的1.23E-1。

  • 字符字面量:分为单字符字面量与转义符字面量。如字母’a’,换行符’\n’,所有字符都采用ASCII编码,共有128个字符。

  • 字符串字面量:由一对双引号括起来的字符序列。

Hello, World

符号常量

  • 随着程序运算不改变的量,赋予名称之后,有一个特定的名字,叫做符号常量,可以使用const关键字来定义并且初始化:

const 数据类型 常量名称 = 初始值;

或者

数据类型 const 常量名称 = 初始值;

比如:

const int kCokePrice = 5;
int const kPopcornPrice = 10;

二、顺序结构程序设计

数据类型

  • 在C++的变量声明中,变量名之前需要指定数据类型。

数据类型 变量名称;

  • 数据类型将会决定一个变量存储什么样的信息,从而决定变量的容量有多大,在内存中需要分配多大的空间。
  • C++种的基本类型包括了整数、浮点数两种。

数值整数类型

  • 数值整数用来表示没有小数部分的数字。
  • 可以按照占用内存大小分为short、int、long以及long long这四种,占用内存越大的类型能表示的数值范围就更大。
    • short类型一般占用2字节
    • int类型一般占用4个字节
    • long类型一般占用4个字节
    • long long类型一般占用8个字节
  • 同时又可以按照是否表示负值分为有符号版本和无符号版本
    • 比如unsigned int就表示无符号的int类型,只能表示正值,表示范围为 0 ~ 2 32 − 1 0~2^{32}−1 02321
    • signed int就表示有符号的int类型,可以表示负值,表示范围为 − 2 31 ~ 2 31 − 1 -2^{31} ~2^{31}−1 2312311
    • 在不指定有无符号时,都默认是有符号版本。

我们可以需要根据实际需求,在变量声明或者初始化时指定变量的数据类型,例如:

short price = 500;    // 单价
int coupon = -2000;   // 优惠
long total = 48000;   // 总价

字符整数类型

  • 字符类型char是另一种特殊的整数类型,它专门用来存储计算机中的基本符号:英文字母、数字以及标点等。
  • 计算机通过ASCII编码,将128个字符映射到对应数字上,于是我们使用1个字节(8位) 就可以将所有的字符表示出来。
  • 可以既可以使用字符常量,也可以使用字符对应的ASCII编码,来给char类型的变量赋值。
// 用字符常量初始化一个 char 类型
char size_1 = 'L';
// 用整数常量初始化一个 char 类型,字符L的ASCII编码值为76
char size_2 = 76;

浮点类型

  • C++中的浮点数分为三种类型:float、double以及long double,分别表示不同的精度。
  • 浮点数的精度在于它可以表示的有效位数以及指数范围。
  • 在三种浮点类型中,更大的内存空间可以表示更多的有效位数:
    • float类型通常占用4个字节,有效位数为6位
    • double类型占用的空间是float类型的两倍,即8个字节,有效位数为15位
    • long double类型一般占用16个字节的空间
      可以需要根据实际需求,在浮点数变量声明或者初始化时指定数据类型,例如:
float ratio = 0.618;           // 黄金分割比例
double pi = 3.1415926;          // 圆周率
long double atom = 1e80

基本算术与赋值运算符

C++中,基本的算术运算分为如下5种:加法、减法、乘法、除法以及求模。C++ 使用运算符(operator)来完成这些算术运算。

  • 加法:+运算符,比如表达式3 + 2可以得到5
  • 减法:-运算符,比如表达式21 - 12结果为9
  • 乘法:*运算符,比如表达式4 * 5将得到20
  • 除法:/运算符,比如表达式18 / 6,19/6,我们得到3
  • 求模:%运算符,比如表达式32 % 5将会得到2
    比如小键想买5袋饼干,小戴想买3袋饼干,计算两人需要购买的饼干的总袋数时,我们会用到以下语句:
int cookie;
cookie = 5 + 3;

以上计算语句中出现了赋值运算符=,代表了把表达式的值赋给变量的操作。

在实际使用中,很多表达式都包含了多个运算符。比如,5 + 3 * 6。C++使用优先级规则来决定首先使用哪个运算符。

  • 对于算术运算符,遵循的是通常的代数优先级,乘除取模在先,加减运算在后。
  • 我们可以使用()圆括号对来明确计算的顺序,在()中的表达式具有最高的计算优先级。
  • 对于优先级相同的两个运算符,将通过结合律来决定计算的先后:
    • 算术运算符的结合律都是从左到右的;
    • 赋值运算符的结合律是从右到左的。

自增自减运算符
自增运算符++作用在变量操作数上,可以使该变量的值在原来基础上递增1:

  • 当我们使用前缀模式时,该变量将先于赋值运算符进行递增,比如coffee_box = ++coffee
  • 当我们使用后缀模式时,该变量将后于赋值运算符进行递增,比如coffee_box = coffee++
    自减运算符–同样作用在变量操作数上,可以使该变量的值在原来基础上递减1,用法同上。

计算且赋值运算符
C++提供了将算术运算与赋值操作相结合的运算符,称为计算且赋值运算符,符号表示与功能描述如下:
在这里插入图片描述

位运算是在数值的二进制形式表示下进行的运算,因此会涉及到许多特有的运算规则。C++中包含了6种按位运算符,分别为:

  • 按位与运算符&、按位或运算符|、异或运算符^

&、|、^都用于对两个二进制操作数,按照逐个位进行与运算。假设a和b是两个只能取二进制值即1和0的操作数,下表演示了这三个运算符的工作方式:
在这里插入图片描述
令变量A = 60,B = 13作为计算样例,我们首先将他们转换为八位二进制数进行表示,分别得到:

A = 0011 1100
B = 0000 1101

计算后得到:

A & B = 0000 1100 // 12
A | B = 0011 1101 // 61
A ^ B = 0011 0001 //49

  • 按位取反运算符~
    C++中的取反运算符~,对单个二进制操作数进行计算,按照每个位进行取反运算,取反规则是0变1,1变0。

令变量A = 60作为计算样例:

A = 0011 1100
~A= 1100 0011 // -61

  • 左移运算符<<、右移运算符>>

在C++中,左移运算符<<,可以将一个操作数的各二进制位全部左移若干位,得到结果左边多余的二进制位将被丢弃,右边不足的二进制位将被补0。

我们对A = 60应用左移运算符进行1次位移,可以得到:

A = 0011 1100
A << 1 = 0111 1000

C++中右移运算符>>,可以将一个操作数的各二进制位全部右移若干位,右侧多余的位将会被舍弃,而左侧较为复杂:

  • 对于无符号数,会在左侧补0;
  • 对于有符号数,则会用符号位补齐,正数为0,负数为1。
    我们对A = 60应用右移运算符进行2次位移,可以得到:

A = 0011 1100
A >> 2 = 0000 1111

三、分支结构程序设计

关系与逻辑表达式

关系表达式用于判断左右两边的表达式之间的关系,比如是否大于、是否相等等,表达式的值为0或者1,表示假或者真。
用法:

  • 判断 a 和 b 的大小关系可以用a > b a >= b a < b a <= b
  • 当然我们也可以单纯的判断 a 和 b 是否相等 a == b a != b
    比如:
    判断己方血量 hp_a 和 敌方血量hp_b 两个数值之间的关系。
int hp_a = 456, hp_b = 857;
// 判断 自己血量 是否大于 敌方血量
cout << (hp_a > hp_b) << endl;
// 判断 自己血量 是否大于等于 敌方血量
cout << (hp_a >= hp_b) << endl;
// 判断 自己血量 是否小于 敌方血量
cout << (hp_a < hp_b) << endl;
// 判断 自己血量 是否小于等于 敌方血量
cout << (hp_a <= hp_b) << endl;
// 判断 自己血量 是否等于 敌方血量
cout << (hp_a == hp_b) << endl;
// 判断 自己血量 是否不等于 敌方血量
cout << (hp_a != hp_b) << endl;
// 判断 自己回50点血后的血量 是否小于 敌方血量
cout << ((hp_a + 50) < hp_b) << endl;
// 判断 自己血量 是否小于 100
cout << (hp_a < 100) << endl;

逻辑表达式
逻辑表达式用于连接关系表达式判断更复杂的条件是否成立,常用的逻辑运算符有以下三种:

  • &&:判断两个条件是否同时成立
  • ||:判断两个条件是否至少有一个成立
  • !:判断某个条件是否不成立

具体的运算规则可以参考下表:
比如:
假设布尔值 higher_hp 表示自己血量比对方高,higher_mp 表示自己蓝量比对方高。 判断“是否自己血量和蓝量都比敌方高”,“是否自己血量和蓝量和中至少有一种比敌方高”,“是否血量没有敌方高”,“是否自己血量和蓝量都没有敌方高”。

// 假设血量比敌方高,但是蓝量没有敌方高
bool higher_hp = 1;
bool higher_mp = 0;

// 是否自己血量和蓝量都比敌方高
cout << (higher_hp && higher_mp) << endl;
// 是否自己血量和蓝量和中至少有一种比敌方高
cout << (higher_hp || higher_mp) << endl;
// 是否血量没有敌方高
cout << (!higher_hp) << endl;
// 是否自己血量和蓝量都没有敌方高
cout << (!higher_hp && !higher_mp) << endl;

优先级
对于一些其他常用的运算符来说,按照优先级从高到低,左边更高,右边更低,排出来是这样的:
在这里插入图片描述

if 语句

if 语句可以用来表达分支结构,控制程序在不同条件下做不同的事情。

if 语句的基础语法:

if (成立条件表达式) {
    当条件成立时需要执行的语句
}
if ... else 语句的语法:

if (成立条件表达式) {
    当条件成立时需要执行的语句
} else {
    当条件不成立时需要执行的语句
}
ifelse if 语句 的语法:

if (成立条件表达式1) {
    当条件1成立时需要执行的语句
} else if (成立条件表达式2) {
    条件1不成立但是条件2成立时需要执行的语句
} else {
    当条件12都不成立时需要执行的语句
}

如果情况需要分成不只三种,我们也可以在else后面再接if、else、if、else,依次判断每个条件是否成立,成立就执行对应的操作,否则就判断下一个条件是否成立:

if (成立条件表达式1) {
    当条件1成立时需要执行的语句
} else if (成立条件表达式2) {
    否则,当条件2成立时需要执行的语句
} else if (成立条件表达式3) {
    否则,当条件3成立时需要执行的语句
} ... else if (成立条件表达式n) {
    否则,当条件n成立时需要执行的语句
} else {
    当上述所有条件都不成立时需要执行的语句
}

举例:

假设现在公园售票处规定了票价和年龄的关系:

  • 年龄小于5岁,输出“免票”;
  • 年龄在5-12岁之间(包含5岁和12岁),输出“7折票”;
  • 年龄大于等于60岁,输出“5折票”;
  • 否则输出“全票”

我们可以这样写:

if (age < 5)
    cout << "免票" << endl; 
else if (age <= 12)
    cout << "7折票" << endl;
else if (age >= 60)
    cout << "5折票" << endl;
else
    cout << "全票" << endl;

if语句嵌套

if 语句嵌套指的是在分支内部嵌入if语句表示新的分支。

  • 对于最外层的分支,每个分支需要执行的语句都可以再嵌入分支
  • 嵌入的这个分支可以以任何形式出现,可以是if,可以是if … else,也可以是if … else if
    举个例子,假设在条件1成立时,我们要通过条件2再进行分支,就可以这样写:
if (成立条件表达式1) {
    if (成立条件表达式2) {
        当条件12都成立时需要执行的语句
    }
} else {
    当条件1不成立时需要执行的语句
}

对于if语句嵌套,我们需要注意,如果没有大括号,那么else默认会匹配到最近的那一个if。
另外,为了代码的可读性,我们尽量去避免非必要的多重if语句嵌套。
举例
网吧老板根据别人输入的年龄判断是否可以进入网吧:如果顾客的年龄大于等于18岁,就输出“允许进入”;否则输出“禁止进入”。
对于允许进入网吧的人,如果历史消费大于200元,再输出“进门左转”提示语,进入VIP区域。

// 首先读入年龄,以及历史账单的信息
int age; 
cin >> age; 

double bill;
cin >> bill;

// 我们可以先写上最外层的结构,如果成年允许进入,否则禁止进入。
if (age >= 18) {
    cout <<  "允许进入" << endl;
    // 在允许进入的分支下,我们还要再考虑是否是vip
    // 是的话让他进门左转
    // 所以需要嵌入一个新的if语句
    if (bill > 200) 
        cout  << "进门左转" << endl;
}
else {
    cout <<  "禁止进入" << endl; 
}

switch 语句

switch语句专门用于判断一个变量的值,根据不同的值进行不同的操作。

switch语句的用法:

switch (变量名) {
    case 变量可能的情况1: 执行语句1; [break;]
    case 变量可能的情况2: 执行语句2; [break;]
    ...
    // 可以有任意数量的 case 语句
    default: 执行语句n;
}

举例

聊天机器人跟每个人打招呼的方式各有不同:

如果是小六:主人你好!

今天你想吃什么?

如果是小一:小一你好!

今天天气怎么样?

如果是小二:你有什么需要帮助的吗?

如果是小四/小五:我不想跟你说话。

其他人:我不太清楚你是谁…

char opt;
cin >> opt;

switch (opt) {
    // 如果opt=='6',执行完两句cout后,遇见break,就会跳出整个switch
    case '6': 
        cout << "主人你好!" << endl;
        cout << "今天你想吃什么" << endl;
        break;
    case '1': 
        cout << "小一你好!" << endl;
        cout << "今天天气怎么样?" << endl;
        break;
    case '2': 
        cout << "你有什么需要帮助的吗?" << endl; 
        break;
    // 如果opt=='4',由于'4'的 case 后面没有 break
    // 所以会往下执行'5'的 case 后面的语句,直到遇到 break
    case '4': case '5':
        cout << "我不想跟你说话" << endl;
        break;
    default: 
        cout << "我不太清楚你是谁..." << endl;
}

四、循环结构程序设计

for循环语句

当需要重复执行一段代码很多遍的时候,可以使用循环结构来解决问题。

  • 循环结构是指在程序中需要反复执行某个功能而设置的一种程序结构。
  • 由循环体中的条件,判断继续执行该功能还是退出循环。
    for循环语句的一般形式可以这样表示:
for (循环变量赋初始值;循环条件;更新循环变量) {
    循环体
}

除了正常的循环之外,循环控制语句可以更改程序执行的正常序列。循环控制语句常用的是 break 和 continue。

  • break
    • 通常放在循环体中,当执行到这句语句时,跳出整个循环,也就是说整个循环立即终止
  • continue
    • 通常也是放在循环体中,当执行到这句语句时,跳过当前循环体,强迫进入下一次循环

举例

  • 假设从第1到第100天,每天存和天数相同的钱,每天输出存款整数;
  • 如果天数是10的倍数(第10、20、30、…天),那么那天可以不存钱,也不输出存款总量;
  • 当存款总数到1000元时,就不存了。
    可以这么写:
// 输入一个整型变量表示存款总数量
int savings = 0;

// 用循环变量 i 表示现在的天数
// 最开始为1
// 每次循环后都加1天
// 不满足小于等于100天时就跳出循环
for (int i=1; i<=100; i++) {
    // 如果天数是10的倍数,直接进入下一天
    if (i % 10 == 0)
        continue;
    
    // 更新存款总数
    savings = savings + i;
    // 输出存款总数
    cout << i << ":总数" << savings << endl;
    
    // 当存到1000元时,跳出循环
    if (savings >= 1000)
        break;
}

while循环

当循环变量不关键时,我们可以用 while语句来完成循环结构。while循环只关注循环终止的条件和循环体的内容本身。
while 写法:

while (循环成立条件) {
循环体 }

执行逻辑:

  • 只要循环成立条件为真,就进入循环体
  • 重复这个步骤,直到循环成立条件为假

举例:

猜数字游戏: 系统在0~100中随机生成一个数字,
你去猜生成的数字是多少,

系统会告诉你猜大了还是猜小了,

你再去猜,直到猜到正确答案。

int num, guess;

srand((unsigned)time(NULL));
num = rand() % 100 + 1;

cin >> guess;

while (guess != num) {
    if (guess > num)
        cout << "猜大了" << endl;
    else if (guess < num)
        cout << "猜小了" << endl;

    cin >> guess;
}

cout << "猜对了" << endl;

do while 的写法:

do {
循环体 } while (循环成立条件);

执行逻辑:

  • 和while差不多
  • 唯一的区别在于:因为条件表达式出现在循环的尾部,所以至少会执行一次循环体,执行完成后,再判断是否进入下一次循环。

举例
猜数字游戏:

int num, guess;

srand((unsigned)time(NULL));
num = rand() % 100 + 1;

do {
    cin >> guess;
    if (guess > num)
        cout << "猜大了" << endl;
    else if (guess < num)
        cout << "猜小了" << endl;
} while (guess != num);

cout << "猜对了" << endl;

多重循环

循环嵌套适用于循环的大操作里有重复的小操作的情景。
循环嵌套注意事项:

  • 可以任意嵌套,比如for嵌for,for嵌while,while嵌for,while嵌while
  • 如果是for嵌for,内外层的循环变量需要用不一样的变量,否则容易产生混乱
  • 缩进以增强代码可读性
  • 可以多层嵌套,但是太多层嵌套容易超时,需要引起注意

用for循环内部嵌套for循环的方式来打印九九乘法表:

// 1-9,每个数字打印一行
for (int i = 1; i <= 9; i++) {
    // 在第i行中,对于每个小于i的数字,都打印一个等式和tab分隔
    for (int j = 1; j <= i ; j++) {
        cout << j << "*" << i << "=" << j*i << "\t";
    }
    // 第i行最后打印换行符
    cout << endl;
}

五、数组

数组是一个固定大小的相同类型元素的顺序集合,用于储存一系列数据。
数组的声明
在 C++ 中声明数组时,我们需要指定元素的类型和元素的数量。其中,元素的数量必须是一个固定的常量,不能是变量,这样才能分配固定的空间。

元素类型 数组名称[数组长度];

数组元素的访问
数组的每个元素可以通过索引来访问,具体的形式是数组名称[索引序号],比如 sales[0], sales[1], sales[2]。数组的索引序号的范围是从 0 到 数组长度-1 。
数组的初始化
数组有两种方式进行初始化:

一种是在声明的同时直接对整个数组初始化:

元素类型 数组名称[数组长度] = {元素1, 元素2, …, 元素n};

  • 如果大括号中给出的元素数量少于或者等于数组长度,会把这些值依次赋给所有元素,后面的默认为0
  • 对整个数组初始化的时候,可以省略中括号中的数组长度,这样默认初始化的数组长度就是大括号中元素的数量

另一种初始化方式是在声明之后,访问数组中的每一个元素,逐个进行初始化赋值。

数组的输入输出
普通的数组只能访问单个元素,对单个元素进行输入输出。
举例

假设商品第一个月的销量为1,接下来每个月的销量都是到前一个月为止的累计销量,也就是说: 第二个月的销量是第一个月的销量1,总累计销量是2
第三个月的销量是前二个月的累计销量2,总累计销量是4 第四个月的销量是前三个月的累计销量4,总累计销量是8 以此类推…
我们想要计算一年中每个月的累计销量并输出。

// 给第一个月的销量赋初值,剩下的默认被初始化为0
int sales[12] = {1};

// 用循环依次计算每个月的累计销量
for (int i = 1; i < 12; i ++)
    sales[i] = 2 * sales[i-1];

// 输出12个月的累计销量
for (int i = 0; i < 12; i ++)
    cout << sales[i] << " "; 

多维数组

我们将从多维数组的声明、访问元素、初始化和输入输出四个方面来介绍多维数组的用法。

多维数组的声明
声明多维数组仍然需要指定元素的类型和每个维度的数量:

元素类型 数组名称[数组第1个维度长度][数组第2个维度长度]…[数组第n个维度长度]

多维数组访问元素
和一维数组一样,多维数组依然是通过索引来访问元素,访问方式为数组名称[第1个维度索引][第2个维度索引]…[第n个维度索引]。

多维数组的初始化
多维数组的初始化有两种方式:

第一种方式是在声明时对整个多维数组初始化,初始值都放在大括号中,如果给出的元素数量少于本身的数量,那么后面的会被默认初始化为0。

假设是一个二维数组:

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};

第二种初始化方式是在声明后分别对每一个元素逐一进行访问,对每个访问的元素进行初始化赋值,可以借助for语句嵌套来实现。

多维数组的输入输出
和一维数组一样,普通的多维数组也是只能对单个元素进行输入输出。

举例
现在有五位选手,三位评委分别在两轮比赛里都给他们评分了,如下图所示。
在这里插入图片描述

假设小键发现评委1对选手1第二轮的得分打错了,想要修正为重新输入的分数,修正后,输出每个评委对每个选手的打分,同时计算每位选手的总分并输出。总分的计算方法为两轮平均得分(向下取整)的和。
那此时我们就可以使用三维数组来描述这个数据结构,并模拟上述过程。

// 声明并初始化得分
int scores[5][3][2] = {
    {{8, 7}, {4, 3}, {6, 5}},
    {{5, 6}, {6, 5}, {3, 8}},
    {{3, 8}, {2, 9}, {4, 7}},
    {{8, 7}, {7, 5}, {6, 3}},
    {{7, 7}, {9, 7}, {8, 9}}
};

int avg_score, score_sum;

// 修正分数
scanf("%i", &scores[0][0][1]);

for (int i=0; i<5; i++) {
    score_sum = 0;
    cout << "选手" << (i+1);
    
    // 对该选手的每一轮打印分数并统计平均分
    for (int k=0; k<2; k++){
        cout << "第" << (k+1) << "轮得分:";
        avg_score = 0;
        
        // 计算该选手在该轮的平均分
        for (int j=0; j<3; j++) {
            avg_score += scores[i][j][k];
            cout << scores[i][j][k] << " ";
        }
        cout << endl;
        avg_score /= 3;
        
        // 该选手的总得分加上该轮的平均分
        score_sum += avg_score;
    }
    
    cout << score_sum << endl;
}

六、字符串

字符数组

字符数组是由若干个字符元素构成的数组,可以按照普通数组的方式去声明、初始化、访问元素、对元素逐个进行输入输出。
字符数组在绝大多数情况下,是用来存储字符串的,这种用字符数组存储的字符串,我们称之为字符数组型字符串。
字符数组型字符串实际上是使用字符\0终止的一维数组,数组中元素的类型是字符型,字符数组型字符串的基本操作如下:

  • 声明:和普通字符数组一样,不过因为需要补充一个\0,字符数组的长度需要比字符串的字符数量多1个。
  • 访问元素:通过索引访问。
  • 初始化:有两种方式对字符数组型字符串进行初始化
    • 第一种初始化方式和普通的字符数组是相同的,给每个元素指定初始化值,不过需要补充上字符’\0’
    • 第二种方式是使用字符串常量初始化字符数组
// 第一种:给每个元素指定初始化值
char userName[11] = {'L', 'a', 'o', 'W', 'a', 'n', 'g', '\0'};
char userName[11] = {'L', 'a', 'o', 'W', 'a', 'n', 'g'};
char userName[] = {'L', 'a', 'o', 'W', 'a', 'n', 'g', '\0'};

//第二种:使用字符串常量初始化字符数组
char userName[11] = {"LaoWang"};
char userName[11] = "LaoWang";
  • 输入输出:除了像普通数组一样对每个元素逐个输入输出之外,字符数组型字符串也可以直接输入输出
char userName[11];
scanf("%s", userName);
printf("%s", userName);
cin >> userName;
cout << userName <<endl;

由于字符串是一个常用的类型,所以官方提供了一些字符串常用处理函数:

  • strcat(s1, s2) 连接字符串
  • strlen(s1) 获取字符串长度
  • strcmp(s1, s2)比较字符串的字典序
  • strcpy(s1, s2)复制字符串
    举例:
#include <iostream>
// 为了调用这些函数,我们必须加在cstring这个头文件
#include <cstring>
using namespace std;
int main() {
    char userName_old[10] = "LaoWang";
    char userName_new[10] = "Liu";
    // 用 strcat:返回把 userName_new 接到 userName_old 的后面的字符串
    cout << strcat(userName_old, userName_new) << endl;
    // 返回 userName_old 的长度
    cout << strlen(userName_old) << endl;

    // 返回新老用户名字典序的比较
    cout << strcmp("LaoWang", "Liu") << endl;
    //把 "Liu" 复制到 userName_old
    strcpy(userName_old, "Liu");
    cout << userName_old << endl;
    // 因为只修改了前4个元素,所以第5个元素还是'a'
    cout << userName_old[4] << endl;
    return 0;
}

String 类型

C++提供了一套更好的工具,叫做标准模版库(Standard Template Library,STL),封装了很多功能,比如一些数据结构(队列等)和算法(排序等),其中一种叫 string 的数据类型可以专门用来处理字符串的相关问题。
string 类型直接把字符串当作一个整体,可以像整型变量、字符变量一样使用。
string 类型的用法有以下一些注意点:

  • 头文件
    首先,需要加载 string 类型所在的头文件。
# include <string>
  • 声明和初始化
    string 类型的声明和初始化和普通变量一样。
// 声明
string a;
// 声明与初始化
string b = "yes";
  • 输入输出
    string 类型的字符串一般直接通过cin和cout进行输入输出。
    由于字符串是一个常用的类型,所以官方提供了一些字符数组型字符串常用处理函数,使用 string 类型来完成这些字符串之间的操作更简便:
    • s1 + s2 连接字符串
    • s1.size() 或者 s1.length() 获取字符串长度
    • strcmp(s1, s2) 比较字符串的字典序
    • s1 = s2复制字符串

举例

我们对小六的新老用户名做一些操作试试:

string userName_old = "LaoWang";
string userName_new = "Liu";
string str;
int len;
// 连接小六的新老用户名,并赋值给str
str = userName_old + userName_new;
cout << userName_old << " + " << userName_new << " = " << str << endl;
// 输出连接后str的总长
cout << "str length:  " << str.size() << endl;
cout << "str length:  " << str.length() << endl;
// 比较新老用户名的字典序
cout << (userName_old > userName_new) << endl;
// 再把老用户名赋给str
str = userName_old;
cout << "str : " << str << endl;

另外,还有一些string类型的其他非常方便的操作函数可以了解一下,详见下面的表格:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

七、函数与结构体

函数

函数就是把一段具有某种特定的功能的代码封装起来。

一个C++程序无论包含多少个函数,必须有一个主要的函数,叫做main()函数,作为执行整个程序的入口。你可以在main()函数中去调用其他函数,同样的,其它函数之间也可以互相调用。

函数可以分为声明、定义与调用几个部分:

  • 声明
    函数声明时,我们需要把函数名、参数和返回值类型都定义好,声明的形式一般如下:

返回值类型 函数名(参数1类型 参数1, 参数2类型 参数2, …, 参数n类型 参数n);

  • 定义
    C++中定义函数时,需要在声明的基础上写好函数体,函数定义的一般形式如下:

返回值类型 函数名(参数1类型 参数1, 参数2类型 参数2, …, 参数n类型 参数n) {
函数体 }

  • 调用
    定义了函数之后,函数里面的代码是不会执行的。只有调用了这个函数,才会去执行函数中的代码。
    如果我们函数的定义在调用前进行的话,也可以省略函数的声明这一步。

函数名(实际参数1, 实际参数2, …, 实际参数n)

函数的参数传递是一个重点:
常用的是传值传递和引用传递。

  • 传值传递
    • 在这种方法中,把参数的实际值赋值给函数的形式参数。在这种情况下,修改函数内的形式参数对实际参数没有影响。
  • 引用传递
    • 该方法把参数的引用赋值给形式参数。在函数内,该引用用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。

如果我们把数组作为参数,传递的参数是数组名。我们知道数组名表示的是数组的地址,所以这时候我们传递的参数实际上是数组的地址,在函数中修改数组里的某一个值,会在内存中直接修改这个数组。

函数定义时,我们可以给函数的参数设置默认值,这样我们调用函数时,可以选择不传递参数,选择默认的参数。

举个例子,假设我们要写一个函数,判断一个数组中最大的数,可以这样完成。

// 定义函数,参数为数组a和长度len,默认len为1,
int MyMax(int a[], int len = 1) {
    int max_num = 0;
    for (int i=0; i<len; i++) {
        if (a[i] > max_num)
            max_num = a[i];
    }
    return max_num;
}

int main() {
    int nums[10] = {3, 2, 1, 1, 2, 3, 3, 2, 1, 0};
    int nums2[1] = {3};
    // 调用函数
    cout << MyMax(nums, 10) << endl;
    // 调用函数,len使用默认值1
    cout << MyMax(nums2) << endl;
    
    return 0;
}

递归函数

函数的函数体中又调用了它自己,这就叫做“递归函数”。
递归函数的写法有两个基本要素:

  • 递归关系

    • 比如计算某个数字的阶乘,我们知道,递归的关系就是:数字n的阶乘 = 数字n * 数字n-1的阶乘。
  • 递归的终止条件

    • 只知道递归关系是不够的,我们需要有一个递归终止的条件。在计算阶乘这个例子中,递归终止的条件是计算到数字1的阶乘的时候,函数可以直接返回数字1的阶乘就是1。

更严谨的,我们可以在n小于1的时候,输出错误操作。

#include <iostream>
using namespace std;

int factorial(int n) {
    if (n < 1) {
        cout << "错误操作" << endl;
        return -1;
    }

    if (n == 1)
        return 1;
    else
        return n * factorial(n-1);
}

int main() {
    cout << factorial(4) << endl;
    return 0;
}

结构体

由于数组只能存储一组同样数据类型的信息,我们可以使用结构体来将一组不同类型的数据聚合成一个整体,以便于去处理这些信息。

  • 结构体的定义
    每个结构体除了有名称,还有有很多个不同类型的成员变量用于表示这个结构体的属性。结构体的定义方式如下:
struct 结构体名称 {
    数据类型1 变量名1;
    数据类型2 变量名2, 变量名3;
    ...
    数据类型n 变量名m;
};
  • 结构体变量声明
    声明结构体变量的方式与声明普通变量类似。对于定义好的结构体Student,声明结构体类型的变量如下:
struct Student{    
    int number, birth_year;
    string name;
};
// 声明三个学生
Student zhang_san, li_si, wang_mazi;

也可以声明结构体变量的数组,以保存500个学生的信息。

// 声明一个学生数组,数组长度为500,可以保存500个学生的信息
Student students[500];
  • 初始化结构体 对于结构体变量,我们可以通过两种方式初始化它:使用初始化列表或构造函数。

使用初始化列表和数组的初始化类似,会根据给出的元素依次初始化结构体中的每个成员,如果给出的元素小于成员数量,排在后面的就会保持没有被初始化。举个例子:

struct Student{    
    int number, birth_year;
    string name;
};
// 初始化一个学号为1,2000年出生,名叫 ZhangSan的学生
Student zhang_san = {1, 2000, "ZhangSan"};

构造函数初始化,可以在创建一个结构体变量而不向其传递某些成员变量的值时,提供默认值。我们可以先在结构体内部完成一个构造函数,再调用这个构造函数来初始化结构体变量:

struct Student{    
    int number, birth_year;
    string name;
    
    // 在结构体里定义构造函数
    // 在初始化时所有学生的出生年份都被设置为2000
    // 可以传入两个参数,分别代表学号和姓名,如果不传入参数,默认学号为0,姓名为""
    Student (int num=0, string n="") {
        number = num;
        birth_year = 2000;
        name = n;
    }
};
// 初始化时只用传递两个参数即可
Student li_si(2, "LiSi");
  • 结构体成员访问
    如果要访问某一个结构体变量的某个成员,可以使用结构体变量名.结构体成员变量名的方式访问:
cout << zhang_san.number << endl;
cout << zhang_san.name << endl;
cout << li_si.birth_year << endl;
  • 代码:员工信息的存储
    我们现在需要创建一个公司员工的结构体Employee,用于
    • 保存员工的编号、姓名和每日需要工作小时数(默认8小时)
    • 初始化小一(1号,XiaoYi),小二(2号,XiaoEr),小六(3号,XiaoLiu),小四(4号,XiaoSi),小五(5号,XiaoWu)这五位员工的信息
    • 写一个函数,展示员工的信息
      我们可以这样来完成:
#include <iostream>
using namespace std;

// 定义结构体 Employee,并声明长度为5的结构体数组 employees_info
struct Employee{    
    int number, working_hours;
    string name;
    
    // 构建函数
    Employee (int num=0, string n="") {
        number = num;
        working_hours = 8;
        name = n;
    }
} employees_info[5];

// 展示某位员工信息的函数
void showEmployee(const Employee &employee_info) {
    cout << "Employee Number : " << employee_info.number << endl;
    cout << "Name : " << employee_info.name << endl;
    cout << "Working Hours : " << employee_info.working_hours << endl;
}

int main() {
    // 初始化5位员工
    employees_info[0] = Employee(1, "XiaoYi");
    employees_info[1] = Employee(2, "XiaoEr");
    employees_info[2] = Employee(3, "XiaoLiu");
    employees_info[3] = Employee(4, "XiaoSi");
    employees_info[4] = Employee(5, "XiaoWu");
    
    // 调用函数展示5位的信息
    for(int i=0; i<5; i++) {
        showEmployee(employees_info[i]);
    }
    return 0;
}

好了C++入门部分就这些了,其中还些许细节之处,希望大家可以继续学习,本文最好的是适合一些有编程基础的同学呢。
路漫漫其修远兮、吾将上下而求索。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值