解决方案

[学习笔记] 1. C++ - CPP基础入门

seo靠我 2023-09-25 23:39:02

课程链接:https://www.bilibili.com/video/BV1et411b73Z

文章目录

1. 初识C++1.1 第一个C++程序1.2 注释1.3 变量1.4 常量1.5 关键字1.6SEO靠我 标识符命名规则2. 数据类型2.1 整型2.2 sizeof关键字2.3 实型(浮点型)2.4 字符型ASCII码表格2.5 转义字符2.6 字符串型2.7 布尔类型2.8 数据的输入3. 运算符3SEO靠我.1 算术运算符3.2 赋值运算符3.3 比较运算符3.4 逻辑运算符4. 程序流程结构4.1 选择结构4.1.1 if语句4.1.2 三目运算符4.1.3 switch语句4.2 循环结构4.2.1SEO靠我 while循环4.2.2 do...while循环语句4.2.3 for循环语句4.2.4 嵌套循环4.3 跳转语句4.3.1 break语句4.3.2 continue语句4.3.3 goto语句SEO靠我5. 数组 (array)5.1 概述5.2 一维数组5.2.1 一维数组的定义方式5.2.2 一维数组数组名5.2.3 冒泡排序5.3 二维数组5.3.1 二维数组定义方式5.3.2 二维数组数组名SEO靠我5.3.3 二维数组应用案例6. 函数6.1 概述6.2 函数的定义6.3 函数的调用6.4 值传递6.5 函数的常见样式6.6 函数的声明6.7 函数的分文件编写1. 创建后缀名为`.h`的头文件 SEO靠我-> `swap.h`2. 创建后缀名为`.cpp`的源文件 -> `swap.cpp`3. 在头文件中写函数的声明4. 在源文件中写函数的定义main函数所在.cpp文件7. 指针 (pointerSEO靠我)7.1 指针的基本概念7.2 指针变量的定义和使用7.3 指针所占的内存空间7.4 空指针和野指针7.5 const修饰指针7.5.1 常量指针7.5.2 指针常量7.5.2 `const`即修饰指SEO靠我针,又修饰常量7.6 指针和数组7.7 指针和函数7.8 指针、数组、函数8. 结构体8.1 结构体基本概念8.2 结构体定义和使用8.3 结构体数组8.4 结构体指针8.5 结构体嵌套结构体8.6 SEO靠我结构体做函数参数8.7结构体中const使用场景8.8 结构体案例8.8.1 案例18.8.2案例29. 通讯录管理系统9.1 系统需求9.2 创建项目9.3 菜单功能9.4 退出功能9.5 添加联系SEO靠我人9.5.1 设计联系人结构体9.5.2. 设计通讯录结构体9.5.3. `main`函数中创建通讯录9.5.4. 封装添加联系人函数9.5.5. 测试添加联系人功能9.6 显示联系人9.6.1 封装SEO靠我显示联系人函数9.7 删除联系人9.7.1 封装检测联系人是否存在9.7.2. 封装删除联系人函数9.8 查找联系人9.8.1 封装查找联系人函数9.9 修改联系人9.9.1 封装修改联系人函数9.1SEO靠我0 清空联系人9.10.1 封装清空联系人函数9.11 通讯录系统全部代码

1. 初识C++

1.1 第一个C++程序

#include <iostream> using namespaceSEO靠我 std;int main() {cout << "Hello World" << endl;system("pause");return 0; }

1.2 注释

作用:在代码中加一些说明SEO靠我和解释,方便自己或其他程序员阅读代码

CPP的注释有两种格式:

单行注释: // 描述信息 通常放在一行代码的上方,或者一条语句的末尾,对该行代码说明 多行注释: /* 描述信息 */ 通常放在一段代码的SEO靠我上方,对该段代码做整体说明

Note: 编译器在编译代码时,会忽略注释的内容

#include <iostream> using namespace std;/*main是一个程序的入口,SEO靠我每个程序都必须有这么一个函数,有且仅有一个 */ int main() {// 在屏幕中输出Hello Worldcout << "Hello World" << enSEO靠我dl;system("pause");return 0; }

1.3 变量

作用:给一段指定的内存空间起名,方便操作这段内存

语法:数据类型 变量名 = 初始值;

示例:

#include<ioSEO靠我stream> using namespace std;int main() {// 变量创建的语法:数据类型 变量名 = 变量初始值int a = 10;cout << "a = "SEO靠我 << a << endl; // a = 10system("pause");return 0; }

1.4 常量

作用:用于记录程序中不可更改的数据

C++定义常量的两种方式:

#defiSEO靠我ne 宏常量: #define 常量名 常量值 通常在文件上方定义,表示一个常量 const修饰的变量: const 数据类型 常量名 = 常量值 通常在变量定义前加关键字const,修饰该变量为常量SEO靠我,不可修改

const: 英[kɒnst] 美[kɑnst]

adj. 恒定的; 不变的;

n. 常数; 恒量;

示例:

#include <iostream> using namespace SEO靠我std;/* 常量的定义方式1. #define 宏常量 -> #define 常量名 常量值2. const修饰的变量 -> const 数据类型 常量名 = 常量值 SEO靠我 */#define Day 7int main() {cout << "一周总共有: " << Day << " 天" << endl; // 一周总共有: 7 天const int month =SEO靠我 12; // const修饰的变量也称为常量cout << "一年总共有: " << month << " 个月份" << endl; // 一年总共有: 12 个月份system("pause")SEO靠我;return 0; }

1.5 关键字

作用:关键字是C++中预先保留的单词(标识符)

在定义变量或常量时,不要覆盖关键字!

C++关键字如下:

关键字asmdoifreturntypedefSEO靠我autodoubleinlineshorttypeidbooldynamic_castintsignedtypenamebreakelselongsizeofunioncaseenummutablesSEO靠我taticunsignedcatchexplicitnamespacestatic_castusingcharexportnewstructvirtualclassexternoperatorswitSEO靠我chvoidconstfalseprivatetemplatevolatileconst_castfloatprotectedthiswchar_tcontinueforpublicthrowwhilSEO靠我edefaultfriendregistertruedeletegotoreinterpret_casttry

Note:在给变量或常量起名时,不要使用CPP的关键字,否则会产生歧义。

示例:

#incluSEO靠我de <iostream> using namespace std;int main() {// 创建变量时变量名使用关键字int true = 10; // 不能使用关键字作为变量名SEO靠我,会报错!system("pause");return 0; }

1.6 标识符命名规则

作用:C++规定给标识符(变量、常量)命名时,有一套自己的规则:

标识符不能是关键字标识符只能由字母SEO靠我、数字、下划线组成第一个字符必须为字母或下划线(不能以数字开头)标识符中字母区分大小写

建议:给标识符命名时,争取做到见名知意的效果,方便自己和他人阅读

#include <iostream>using SEO靠我namespace std;/*1. 标识符不能是关键字2. 标识符只能由字母、数字、下划线组成3. 第一个字符必须为字母或下划线(不能以数字开头)4. 标识符中字母区分大小写 */ SEO靠我 int main() {// 1. 标识符不能是关键字// int int = 10; // 错误// 2. 标识符只能由字母、数字、下划线组成int abc = 10;int _abSEO靠我c = 20;int _123abc = 30;// 3. 第一个字符必须为字母或下划线(不能以数字开头)// int 123abc = 40; // 错误// 4. 标识符中字母区分大小写int aSEO靠我aa = 100;int AAA = 300;cout << aaa << endl; // 100cout << AAA << endl; // 300system("pause");return SEO靠我0; }

2. 数据类型

C++规定在创建一个变量或常量时,必须要指定出相应的数据类型,否则无法给变量分配内存。

数据类型存在的意义是给变量分配合适的内存空间。

2.1 整型

作用:整型变量表示SEO靠我的是整数类型的数据。C++中能够表示整型的类型有以下几种方式,区别在于所占用的空间不同:

数据类型占用空间取值范围short(短整型)2字节(−215∼215−1)(-2^{15} \sim 2^{15SEO靠我} - 1)(−215∼215−1) ⇔\Leftrightarrow⇔ (−32,768∼32,767)(-32,768 \sim 32,767)(−32,768∼32,767)int(整型)4字节SEO靠我(−231∼231−1)(-2^{31} \sim 2^{31} - 1)(−231∼231−1) ⇔\Leftrightarrow⇔ (−2,147,483,648∼2,147,483,647)(-SEO靠我2,147,483,648 \sim 2,147,483,647)(−2,147,483,648∼2,147,483,647)long(长整型)Windows为4字节,Linux为4字节(32位),8SEO靠我字节(64位)(−231∼231−1)(-2^{31} \sim 2^{31} - 1)(−231∼231−1) ⇔\Leftrightarrow⇔ (−2,147,483,648∼2,147,483SEO靠我,647)(-2,147,483,648 \sim 2,147,483,647)(−2,147,483,648∼2,147,483,647)long long(长长整型)8字节(−263∼263−1)SEO靠我(-2^{63} \sim 2^{63} - 1)(−263∼263−1) ⇔\Leftrightarrow⇔ (−9,223,372,036,854,775,808∼9,223,372,036,85SEO靠我4,775,807)(-9,223,372,036,854,775,808 \sim 9,223,372,036,854,775,807)(−9,223,372,036,854,775,808∼9,2SEO靠我23,372,036,854,775,807)

在日常开发中,int是最常用的。

#include<iostream> using namespace std;/*整型:1. 短整型 shSEO靠我ort2. 整型 int3. 长整型 long4. 长长整型 long long */ int main() {// 1. 短整型 short (−32,768 ~ 3SEO靠我2,767)short num1 = 10;// 2. 整型 int (−2,147,483,648 ~ 2,147,483,647)int num2 = 10;// 3. 长整型 long (−2,SEO靠我147,483,648 ~ 2,147,483,647)long num3 = 10;// 4. 长长整型 long long ((−9,223,372,036,854,775,808 ~ 9,223SEO靠我,372,036,854,775,807))long long num4 = 10; cout << "num1: " << num1 << endl; // num1: 10cout << "numSEO靠我2: " << num2 << endl; // num2: 10cout << "num3: " << num3 << endl; // num3: 10cout << "num4: " << nuSEO靠我m4 << endl; // num4: 10cout << "-------------------" << endl;/*探讨越界的情况:当出现超过表示范围的数时,会自动轮到开头*/// 1. 短SEO靠我整型 short (−32768~32767)short ol_num1 = 32768;cout << "ol_num1: " << ol_num1 << endl; // ol_num1: -32SEO靠我768// 2. 整型 int (−2,147,483,648 ~ 2,147,483,647)int ol_num2 = 2147483648;cout << "ol_num2: " << ol_nSEO靠我um2 << endl; // ol_num2: -2147483648// 3. 长整型 long (−2,147,483,648 ~ 2,147,483,647)long ol_num3 = 21SEO靠我47483648;cout << "ol_num3: " << ol_num3 << endl; // ol_num3: -2147483648// 4. 长长整型 long long ((−9,22SEO靠我3,372,036,854,775,808 ~ 9,223,372,036,854,775,807))long long ol_num4 = 9223372036854775808;cout << "SEO靠我ol_num4: " << ol_num4 << endl; // ol_num4: -9223372036854775808system("pause");return 0; }

2.SEO靠我2 sizeof关键字

作用:利用sizeof关键字可以统计数据类型所占内存的大小。

语法:sizeof(数据类型 / 变量)

示例:

#include<iostream> using namSEO靠我espace std;int main() {/*使用sizeof求出数据类型/变量所占的内存大小*/short num1 = 10;cout << "short占用的内存空间为: " << sizeSEO靠我of(short) << endl; // short占用的内存空间为: 2cout << "num1变量对应的数据类型所占用的内存空间为: " << sizeof(num1) << endl; //SEO靠我 num1变量对应的数据类型所占用的内存空间为: 2int num2 = 10;cout << "int占用的内存空间为: " << sizeof(int) << endl; // int占用的内存空SEO靠我间为: 4long num3 = 10;cout << "long占用的内存空间为: " << sizeof(long) << endl; // long占用的内存空间为: 4long long nuSEO靠我m4 = 10;cout << "long long占用的内存空间为: " << sizeof(long long) << endl; // long long占用的内存空间为: 8system("pSEO靠我ause");return 0; }

2.3 实型(浮点型)

作用:用于表示小数。

浮点型变量分为两种:

单精度: float双精度: double

两者的区别在于表示的有效数字范围不同。

数据类SEO靠我型占用空间有效数字范围float4字节7位有效数字double8字节15~16位有效数字

有效数字包含小数点前面和后面的!

需要注意的是,在写float类型时,数字后面加上一个f,例如:

float numSEO靠我 = 3.14f;

因为如果不加f,那么编译器看到小数会默认它为double,还需要将double转为为float,这样会多一步。

示例:

#include <iostream> usingSEO靠我 namespace std;int main() {// 1. 单精度 float// 2. 双精度 doublefloat f1 = 3.1415126f; // 一般会在后面写一个f// endSEO靠我l = end linecout << "f1: " << f1 << endl; // f1: 3.14151double d1 = 3.1415126;cout << "d1: " << d1 <SEO靠我< endl; // d1: 3.14151// 统计float和double占用的内存空间cout << "float占用的内存空间: " << sizeof(float) << "字节" << eSEO靠我ndl; // float占用的内存空间: 4字节cout << "double占用的内存空间: " << sizeof(double) << "字节" << endl; // double占用的内存SEO靠我空间: 8字节// 科学计数法float f2 = 3e2f; // 3 * 10^2double d2 = 3e-2; // 3 * 10^-2cout << "f2: " << f2 << endSEO靠我l; // f2: 300cout << "d2: " << d2 << endl; // d2: 0.03system("pause");return 0; }

默认情况下,CPP显示SEO靠我一个小数最多显示6位小数。

2.4 字符型

作用:字符型变量用于显示单个字符

语法:char ch = a;

注意:

在显示字符型变量时,用单引号将字符括起来,不要使用双引号单引号内只能有一个字符,不可以是字符SEO靠我串字符型变量并不是把字符本身放到内存中存储,而是将对应的ASCII编码放入到存储单元C和CPP中字符型变量只占用1个字节

字节字节,就是一个英文单词所占用的大小,所以对于char,在空间中就是占一个字节SEO靠我

需要记忆的ASCII码值:

a: 97A: 65

示例:

#include<iostream> using namespace std;int main() {// 1. 字符型变量的创建SEO靠我方式char ch = a;cout << "ch: " << ch << endl; // ch: a// 2. 字符型变量所占用内存大小cout << "char所占的内存大小: " << sizSEO靠我eof(char) << "字节" << endl; // char所占的内存大小: 1字节// 3. 字符型变量常见错误// char ch2 = "a"; // 不能用双引号创建字符// charSEO靠我 ch3 = abcdef; // 不能用单引号创建字符串// 4. 字符型变量对应的ASCII编码// (数据类型)变量: 将变量强转为指定的数据类型cout << (int)ch << endl;SEO靠我 // 97cout << (int)A << endl; // 65system("pause");return 0; }

ASCII码表格

ASCII值(十进制)控制字符解释ASCIISEO靠我值(十进制)控制字符解释ASCII值(十进制)控制字符解释ASCII值(十进制)控制字符解释0NUT (null)空字符32(space)空格64@电子邮件符号96`开单引号1SOH (start oSEO靠我f headline)标题开始33!叹号65A大写字母A97a小写字母2STX (start of text)正文开始34"双引号66B大写字母B98b小写字母b3ETX (end of text)正SEO靠我文结束35#井号67C大写字母C99c小写字母c4EOT (end of transmission)传输结束36$美元符号68D大写字母D100d小写字母d5ENQ (enquiry)请求37%百分号SEO靠我69E大写字母E101e小写字母e6ACK (acknowledge)收到通知38&和号70F大写字母F102f小写字母f7BEL (bell)响铃39’闭单引号71G大写字母G103g小写字母g8BSEO靠我S (backspace)退格40(开括号72H大写字母H104h小写字母h9HT (horizontal tab)水平制表符41)闭括号73I大写字母I105i小写字母i10LF (NL line SEO靠我feed, new line)换行键42*星号74J大写字母J106j小写字母j11VT (vertical tab)垂直制表符43+加号75K大写字母K107k小写字母k12FF (NP form SEO靠我feed, new page)换页键44,逗号76L大写字母L108l小写字母l13CR (carriage return)回车键45-减号/破折号77M大写字母M109m小写字母m14SO (shiSEO靠我ft out)不用切换46.句号/点78N大写字母N110n小写字母n15SI (shift in)启用切换47/斜杠79O大写字母O111o小写字母o16DLE (data link escape)SEO靠我数据链路转义480数字080P大写字母P112p小写字母p17DC1 (device control 1)设备控制1491数字181Q大写字母Q113q小写字母q18DC2 (device contrSEO靠我ol 2)设备控制2502数字282R大写字母R114r小写字母r19DC3 (device control 3)设备控制3513数字383S大写字母S115s小写字母s20DC4 (device cSEO靠我ontrol 4)设备控制4524数字484T大写字母T116t小写字母t21NAK (negative acknowledge)拒绝接收535数字585U大写字母U117u小写字母u22SYN (sSEO靠我ynchronous idle)同步空闲546数字686V大写字母V118v小写字母v23ETB (end of trans. block)结束传输块557数字787W大写字母W119w小写字母w24SEO靠我CAN (cancel)取消568数字888X大写字母X120x小写字母x25EM (end of medium)媒介结束579数字989Y大写字母Y121y小写字母y26SUB (substitutSEO靠我e)代替58:冒号90Z大写字母Z122z小写字母z27ESC (escape)换码(溢出)59;分号91[开方括号123{开花括号28FS (file separator)文件分隔符60<小于92\SEO靠我反斜杠124``29GS (group separator)分组符61=等号93]闭方括号125}闭花括号30RS (record separator)记录分隔符62>大于94^脱字符126~波浪号3SEO靠我1US (unit separator)单元分隔符63?问号95_下划线127DEL (delete)删除

ASCII码大致由以下两部分组成:

ASCII非打印控制字符:ASCII表上的数字0 ~ 31分SEO靠我配给了控制字符,用于控制像打印机等一些外围设备。ASCII打印字符:数字32 ~ 126分配给了能在键盘上找到的字符,当查看或打印文档时就会出现。

2.5 转义字符

作用:用于表示一些不能显示出来的ASCSEO靠我II字符

现阶段我们常用的转义字符有:

\n\\\t 重要转义字符含义ASCII码值(十进制)\a报警007\b退格(BS), 将当前位置移到前一列008\f换页(FF), 将当前位置移到SEO靠我下页开头012⭐️\n换行(LF), 将当前位置移到下一行开头010⭐️\r回车(CR), 将当前位置移到本行开头013⭐️\t水平制表(HT), 跳到下一个TAB位置009\v垂直制表(VT)011SEO靠我⭐️\\代表一个反斜线字符\092\代表一个单引号(撇号)字符039\"代表一个双引号字符034\0代表一个问号000\ddd8进制转义字符, d范围0~73位8进制\xhh16进制转义字符, h范围SEO靠我0~9, a~f, A~F3位16进制

注意:

\r表示将当前的光标移动到行首,但不会移动到下一行;\n表示将光标移动到下一行,但不会移动到行首。

单独一个\r或\n都不是一般意义上的回车,\r\n放在一起SEO靠我才是。通常在写程序的时候只要一个\n就可以了,这是因为编译器会自动将\n替换成\r\n。

示例:

#include<iostream> using namespace std;int maSEO靠我in() {// 1. 换行符 \ncout << "hello wolrd";/*hello wolrd请按任意键继续. . .*/cout << "hello wolrd\n";/*hello wSEO靠我olrd请按任意键继续. . .*/// 2. 反斜杠 \\ cout << "\\" << endl; // \ // 3. 水平制表符 \t 可以整齐地输出数据cout << "aSEO靠我aa\thello world" << endl;/*aaa hello world请按任意键继续. . .*/cout << "a\thello world" << endl;cout << "abSEO靠我\thello world" << endl;cout << "abc\thello world" << endl;cout << "abcd\thello world" << endl;/*a heSEO靠我llo worldab hello worldabc hello worldabcd hello world请按任意键继续. . .*/// 4. 回车 \rcout << "abc\rdefg" <SEO靠我< endl; // defg(回车会让光标回到行首,因此defg覆盖掉了abc)cout << "123\r\n"; // \r\n表示开始下一行并回到行首/*\r表示将当前的光标移动到行首,但不会SEO靠我移动到下一行;\n表示将光标移动到下一行,但不会移动到行首。单独一个\r或\n都不是一般意义上的回车,\r\n放在一起才是。通常在写程序的时候只要一个\n就可以了,这是因为编译器会自动将\n替换成\rSEO靠我\n。*/system("pause");return 0; }

2.6 字符串型

作用:用于表示一串字符。

两种风格:

C语言风格字符串:char 变量名[] = "字符串值"; -> chSEO靠我ar str1[] = "Hello World";C++语言风格字符串: string 变量名 = "字符串值";

注意:

C语言风格的字符串要用双引号括起来C++风格字符串需要加入头文件#includSEO靠我e <string>

示例:

#include <iostream> using namespace std; #include <string>int main() {/SEO靠我/ 1. C风格字符串char str_c[] = "Hello World";cout << str_c << endl; // Hello World// 2. C++风格字符串(使用的时候需要引SEO靠我入string头文件)string str_cpp = "Hello World";cout << str_cpp << endl; // Hello World// 看一下两种字符串占空间的大小coSEO靠我ut << "C大小: " << sizeof(str_c) << "字节" << endl; // C大小: 12字节cout << "C++大小: " << sizeof(string) << "SEO靠我字节" << endl; // C++大小: 40字节system("pause");return 0; }

2.7 布尔类型

作用:布尔数据类型表示真或假的值

bool类型只有两个值:

trSEO靠我ue: 真 (本质是1)false: 假 (本质是0)

bool类型占1个字节大小(因为本质上是数字1/0)

语法:bool 变量名 = true/false;

示例:

#include <iostream>SEO靠我, <string> using namespace std;int main() {// 1. 创建bool数据类型bool flag_1 = true;bool flag_2 = SEO靠我false;cout << flag_1 << endl; // 1cout << flag_2 << endl; // 0// 2. 查看bool数据类型占用空间大小cout << "bool数据类SEO靠我型占 " << sizeof(bool) << " 字节" << endl; // bool数据类型占 1 字节system("pause");return 0; }

2.8 数据的输入SEO靠我

作用:用于从键盘获取数据

关键字:cin

语法:cin >> 变量

示例:

#include<iostream> #include<string> using namespacSEO靠我e std;int main() {// 1. 整型int a = 0;cout << "请给整型变量a赋值: " << endl;cin >> a; // 请给整型变量a赋值:cout << "整型SEO靠我变量a = " << a << endl; // 整型变量a = 100// 2. 浮点型float f = 3.14f;cout << "请给浮点型变量f赋值: " << endl;cin >> fSEO靠我; // 请给浮点型变量f赋值:cout << "浮点型变量f = " << f << endl; // 浮点型变量f = 7.77// 3. 字符型char ch = a;cout << "请给字符SEO靠我型变量ch赋值: " << endl;cin >> ch; // 请给字符型变量ch赋值:cout << "字符型变量ch = " << ch << endl; // 字符型变量ch = b// 4.SEO靠我 字符串型string str = "None";cout << "请给字符串型变量str赋值: " << endl;cin >> str;cout << "字符串型变量str = " << str SEO靠我<< endl; // 字符串型变量str = "Hello"// 5. boolbool flag = false;cout << "请给bool型变量flag赋值: " << endl;cin >SEO靠我> flag; // bool类型只要是非0的值都代表真cout << "bool型变量flag = " << flag << endl; // bool型变量bool = "1"/*请给整型变量a赋SEO靠我值:100整型变量a = 100请给浮点型变量f赋值:3.3浮点型变量f = 3.3请给字符型变量ch赋值:b字符型变量ch = b请给字符串型变量str赋值:Hello字符串型变量str = HelSEO靠我lo请给bool型变量flag赋值:1bool型变量flag = 1*/system("pause");return 0; }

3. 运算符

作用:用于执行代码的运算。

本章主要讲以下几类运SEO靠我算符:

运算符类型作用算术运算符用于处理四则运算赋值运算符用于将表达式的值赋给变量比较运算符用于表达式的比较,并返回一个真值或假值逻辑运算符用于根据表达式的值返回真值或假值

3.1 算术运算符

作用:用于处SEO靠我理四则运算。

算术运算符包含以下符号:

运算符术语示例结果注意+正号+33-负号-3-3+加10+515-减10-55*乘10*550/除10/52除数不能是0%取模(取余数)10%31必须是两个整数, SEO靠我除数不能是0++前置递增a=2; b=++a;a=3; b=3;++后置递增a=2; b=a++;a=3; b=2;–前置递减a=2; b=–a;a=1; b=1;–后置递减a=2; b=a–;a=1SEO靠我; b=2; 前置先执行再表达式运算;后置先表达式运算再执行取余操作的被除数可以是0,且结果恒等于0;但除数不能是0,会报错!

取余操作的本质就是除法

#include<iostream>SEO靠我 using namespace std;int main() {// 1. 加减乘除int a1 = 10;int b1 = 3;/*因为a和b都是int,因此两个整数做除法仍然是iSEO靠我nt*/cout << a1 + b1 << endl; // 13cout << a1 - b1 << endl; // 7cout << a1 * b1 << endl; // 30cout <<SEO靠我 a1 / b1 << endl; // 3int a2 = 10;int b2 = 20;cout << a2 / b2 << endl; // 0int a3 = 10;int b3 = 0;//SEO靠我 cout << a3 / b3 << endl; // 0 // Integer division by zero。// 两个小数相除double d1 = 0.5;double d2 = 0.22SEO靠我;cout << d1 / d2 << endl; // 2.27273// 整数和小数相除int a4 = 2;double d3 = 3.14;cout << a4 / d3 << endl; /SEO靠我/ 0.636943// 两个不同数据类型的小数相除float f1 = 3.14f;float d4 = 7.11;cout << f1 / d4 << endl; // 0.441632// 2.SEO靠我 取模(取余)int aa1 = 10;int aa2 = 3;cout << aa1 % aa2 << endl; // 1cout << aa2 % aa1 << endl; // 3// 两个小SEO靠我数是不可以取余float ff1 = 3.14f;float ff2 = 1.01f;// cout << ff1 % ff2 << endl; // 表达式必须具有整数或未区分范围的枚举类型(取余操SEO靠我作必须是整数!)// 取余操作的除数不能是0,被除数可以是0且结果恒等于0int aaa1 = 0;int aaa2 = 3;cout << aaa1 % aaa2 << endl; // 0// cSEO靠我out << aaa2 % aaa1 << endl; // Integer division by zero// 3. 前置递增、后置递增、前置递减、后置递减// 3.1 前置递增: 先让变量+1,SEO靠我然后进行表达式运算int a = 10;++a; // 让变量+1cout << "a = " << a << endl; // 11// 3.2 后置递增: 先进行表达式运算,再让变量+1int bSEO靠我 = 10;b++;cout << "b = " << b << endl; // 11// 前置和后置的区别a = 10;b = ++a * 10;cout << "a = " << a << enSEO靠我dl; // a = 11cout << "b = " << b << endl; // b = 110a = 10;b = a++ * 10;cout << "a = " << a << endl;SEO靠我 // a = 11cout << "b = " << b << endl; // b = 100// 3.3 前置递减a = 10;--a;cout << "a = " << a << endl; SEO靠我// 9// 3.4 后置递减b = 10;b--;cout << "b = " << b << endl; // 9// 前置和后置的区别a = 10;b = --a * 10;cout << "aSEO靠我 = " << a << endl; // a = 9cout << "b = " << b << endl; // b = 90a = 10;b = a-- * 10;cout << "a = " SEO靠我<< a << endl; // a = 9cout << "b = " << b << endl; // b = 100system("pause");return 0; }

3.2 SEO靠我赋值运算符

作用:用于将表达式的值赋给变量。

赋值运算符包括以下几个符号:

运算符术语示例结果=赋值a=2; b=3;a=2; b=3;+=加等于a=0; a+=2;a=2;-=减等于a=0; a-=2;aSEO靠我=-2;*=乘等于a=2; a*=3;a=6;/=除等于a=6; a/=3;a=2;%=模等于a=6; a%=4;a=2; #include<iostream> usiSEO靠我ng namespace std;int main() {// =int a = 10;cout << "a = " << a << endl; // a = 10a = 20;cout << "a SEO靠我= " << a << endl; // a = 20// +=a = 10;a += 2; // a = a + 2cout << "a = " << a << endl; // a = 12// SEO靠我-=a = 10;a -= 2;cout << "a = " << a << endl; // a = 8// *=a = 10;a *= 2;cout << "a = " << a << endl;SEO靠我 // a = 20// /=a = 10;a /= 2;cout << "a = " << a << endl; // a = 5// %=a = 10;a %= 2;cout << "a = " SEO靠我<< a << endl; // a = 0system("pause");return 0; }

3.3 比较运算符

作用:用于表达式的比较,并返回一个真值或假值。

比较运算符有以下符号:SEO靠我

运算符术语示例结果==相等于4==30!=不等于4!=31<小于4<30>大于4>31<=小于等于4<=30>=大于等于4>=31 #include<iostream> SEO靠我 using namespace std;int main() {int a = 10;int b = 20;// ==cout << (a == b) << endl; // 0// !=cout SEO靠我<< (a != b) << endl; // 1// >cout << (a > b) << endl; // 0// <cout << (a < b) << endl; // 1// >=coutSEO靠我 << (a >= b) << endl; // 0// <=cout << (a <= b) << endl; // 1system("pause");return 0; }

3.4 SEO靠我逻辑运算符

作用:用于根据表达式的值返回真值或假值

逻辑运算符有以下符号:

运算符术语示例结果!非!a如果a为假,则!a为真;如果a为真,则!a为假&&与a && b如果a和b都为真,则结果为真,否则为假|SEO靠我|与a || b如果a或b有一个为真,则结果为真 #include<iostream> using namespace std;int main() {// 逻辑非 !SEO靠我int a = 10;cout << "!a: " << !a << endl; // !a: 0cout << "!!a: " << !!a << endl; // !!a: 1// 逻辑与 &&iSEO靠我nt b = 20;cout << "a && b: " << (a && b) << endl; // a && b: 1bool c = false;cout << "b && c: " << (SEO靠我b && c) << endl; // b && c: 0int d = 0;cout << "c && d: " << (c && d) << endl; // c && d: 0// 逻辑或 ||SEO靠我cout << "a || b: " << (a || b) << endl; // a || b: 1cout << "b || c: " << (b || c) << endl; // b || SEO靠我c: 1cout << "c || d: " << (c || d) << endl; // c || d: 0system("pause");return 0; }

4. 程序流程结构SEO靠我

C/C++支持最基本的三种程序执行结构:顺序结构、选择结构、循环结构:

顺序结构:程序按顺序执行,不发生跳转选择结构:依据条件是否满足,有选择的执行相应功能循环结构:依据条件是否满足,循环多次执行某段代SEO靠我

4.1 选择结构

4.1.1 if语句

作用:执行满足条件的语句

if语句的三种形式:

单行格式if语句:if(条件){满足条件时执行的语句}多行格式if语句:if(条件){满足条件时执行的语句}else{SEO靠我不满足条件时执行的语句}多条件的if语句:if(条件){条件1满足时执行的语句}else if(条件2){条件2满足时执行的语句}... else{所有条件都不满足时执行的语句}

补充:嵌套if语句:在SEO靠我if语句中,可以嵌套使用if语句,达到更精确的条件判断。

示例:

#include<iostream> using namespace std;int main() {// 用户输入分数,SEO靠我如果分数大于600,视为考上一本大学,在屏幕上输出int score = 0;cout << "请输入分数: ";cin >> score;cout << "输入的分数为: " << score <<SEO靠我 "\r\n" << endl;// 1. 单行格式if语句:if(条件){满足条件时执行的语句}cout << "---------1. 单行格式if语句---------" << endl;if SEO靠我(score >= 600) {cout << "恭喜您考上了一本大学!" << endl;}// 2. 多行格式if语句:if(条件){满足条件时执行的语句}else{不满足条件时执行的语句}couSEO靠我t << "\r\n---------2. 多行格式if语句---------" << endl;if (score >= 600) {cout << "恭喜您考上了一本大学!" << endl;}eSEO靠我lse{cout << "很可惜,您没考上一本大学" << endl;}// 3. 多条件的if语句:if(条件){条件1满足时执行的语句}else if(条件2){条件2满足时执行的语句}... eSEO靠我lse{所有条件都不满足时执行的语句}cout << "\r\n---------3. 多条件的if语句---------" << endl;if (score >= 600) {cout << "恭SEO靠我喜您考上了一本大学!" << endl;}else if (score >= 450) {cout << "恭喜您考上了二本大学!" << endl;}else if (score >= 300) {SEO靠我cout << "恭喜您考上了三本大学!" << endl;}else if (score >= 200) {cout << "恭喜您考上了专科大学!" << endl;}else {cout << SEO靠我"很可惜,您的分数不足以考上大学" << endl;}// 补充:在一本分数中,如果大于700分,考入北大,大于650分,考入清华,大于600考入人大。cout << "\r\n---------补充SEO靠我---------" << endl;if (score >= 600) {cout << "恭喜您考上了一本大学!" << endl;if (score > 700) {cout << "您能考上北SEO靠我大!" << endl;}else if (score > 650) {cout << "您能考上清华!" << endl;}else {cout << "您能考上人大!" << endl;}}/*请SEO靠我输入分数: 620输入的分数为: 620---------1. 单行格式if语句---------恭喜您考上了一本大学!---------2. 多行格式if语句---------恭喜您考上了一本大学!SEO靠我---------3. 多条件的if语句---------恭喜您考上了一本大学!---------补充---------恭喜您考上了一本大学!您能考上人大!*/system("pause");retuSEO靠我rn 0; }

练习案例:有三只小猪ABC,请分别输入三只小猪的体重,并判断哪只小猪最重。

#include<iostream> using namespace std;iSEO靠我nt main() {// 1. 创建三只小猪的体重int a = 0;int b = 0;int c = 0;// 2. 用户输入三只小猪的重量cout << "请输入小猪A的体重: ";cin >SEO靠我> a;cout << "请输入小猪B的体重: ";cin >> b;cout << "请输入小猪C的体重: ";cin >> c;cout << endl;// 3. 显示三只小猪的体重cout <SEO靠我< "小猪A的体重 = " << a << endl;cout << "小猪B的体重 = " << b << endl;cout << "小猪C的体重 = " << c << endl;cout <<SEO靠我 endl;// 4. 判断哪只最重if (a > b) {if (a > c) {cout << "小猪A最重!" << endl;}}else { // b > aif (b > c) {coutSEO靠我 << "小猪B最重!" << endl;}else{cout << "小猪C最重!" << endl;}}/*请输入小猪A的体重: 10请输入小猪B的体重: 20请输入小猪C的体重: 30小猪A的体SEO靠我重 = 10小猪B的体重 = 20小猪C的体重 = 30小猪C最重!*/system("pause");return 0; }

4.1.2 三目运算符

作用:通过三目运算符实现简单的判断

SEO靠我法:表达式1 ? 表达式2 : 表达式3

解释:

如果表达式1的值为真,执行表达式2,并返回表达式2的结果;如果表达式1的值为假,执行表达式3,并返回表达式3的结果。

Python中是 num = 值1 iSEO靠我f 表达式1 else 值2

#include<iostream> using namespace std;int main() {// 创建三个变量 abc// 将a和b作比较,将变量SEO靠我大的值赋值给变量cint a = 10;int b = 20;int c = 0;c = a > b ? a : b;cout << "c = " << c << endl; // c = 20// SEO靠我在C++中,三目运算符返回的是变量,可以继续赋值(a > b ? a : b) = 100;cout << "a = " << a << endl; // a = 10cout << "b = " <SEO靠我< b << endl; // b = 100system("pause");return 0; }

4.1.3 switch语句

作用:执行多条件分支语句

语法:

switch (表达式) SEO靠我{ case 结果1: 执行语句;break; case 结果2: 执行语句;break;...default: 执行语句;break; }

注意:

swiSEO靠我tch语句中表达式类型只能是整型或字符型case里如果没有break,那么程序会一直向下执行switch相对if的优缺点: 优点:结构清晰,执行效率高缺点:判断时候只能是整数或字符型,不可以是一个区间SEO靠我

示例:

#include<iostream> using namespace std;// switch语句 int main() {/*给电影打分:10 ~ 9:经典8SEO靠我 ~ 7:非常好6 ~ 5:一般5以下:烂片*/// 1. 提出用户给电影打分int score = 0;cout << "请给电影打分: ";cin >> score;// 2. 根据用户输入的分数SEO靠我来提出最终结果cout << "\r\nswitch语句结果:" << endl;switch (score){case 10:cout << "您认为是经典电影" << endl;break;casSEO靠我e 9:cout << "您认为是经典电影" << endl;break;case 8:cout << "您认为是一般电影" << endl;break;case 7:cout << "您认为是一般电SEO靠我影" << endl;break;case 6:cout << "您认为是一般电影" << endl;break;case 5:cout << "您认为是一般电影" << endl;break;defSEO靠我ault:cout << "您认为是烂片" << endl;break;}/*switch相对if的优缺点:优点:结构清晰,执行效率高缺点:判断时候只能是整数或字符型,不可以是一个区间*/cout <SEO靠我< "\r\nif语句结果:" << endl;if (score >= 9) {cout << "您认为是经典电影" << endl;}else if (score >= 5) {cout << "SEO靠我您认为是一般电影" << endl;}else {cout << "您认为是烂片" << endl;}system("pause");return 0; }

4.2 循环结构

4.2.1 SEO靠我while循环

作用:满足循环条件,执行循环语句

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

解释:只要循环条件的结果为真,就执行循环语句。

注意:在执行循环语句时,程序必须提供跳出循环的出否,否则出现死循SEO靠我

#include<iostream> using namespace std;int main() {// 在屏幕中打印 0~9 这10个数字int num = 0;while (nSEO靠我um < 10) {cout << num << endl;num += 1;}system("pause");return 0; }

while循环练习案例:猜数字

案例描述:系统随机生SEO靠我成一个1到100之间的数字,玩家进行猜测,如果猜错,提示玩家数字过大或过小,如果猜对恭喜玩家胜利,并且退出游戏。

#include<iostream> using namespace sSEO靠我td; // 引入time头文件 #include<ctime>int main() {// 添加随机数种子,利用当前系统时间生成随机数,防止每次随机数都一样(随机本质SEO靠我上是伪随机)srand((unsigned int)time(NULL));// 1. 生成随机数int num = rand() % 100 + 1; // 生成0~99的随机数// 2. 让玩家进SEO靠我行猜测int val = 0; // 玩家输入的数据//限定猜测次数(5次)int times = 5;while (1) {cout << "猜个数: ";cin >> val;times -= 1SEO靠我;// 3. 判断玩家的猜测并给出提示if (times != 0) {if (val > num) {cout << "猜的大了" << endl;}else if (val < num) {couSEO靠我t << "猜的小了" << endl;}else // 猜对了 -> 退出游戏{cout << "猜对了!游戏结束..." << endl;break;}cout << "剩余次数" << timeSEO靠我s << "\n" << endl;}else{cout << "次数用尽,游戏失败..." << endl;break;}}system("pause");return 0;/*猜个数: 50猜的大SEO靠我了剩余次数4猜个数: 30猜的小了剩余次数3猜个数: 35猜对了!游戏结束...*/ }

4.2.2 do…while循环语句

作用:满足循环条件,执行循环语句

语法:do{循环语句} whSEO靠我ile(循环条件);

注意:与while的区别在于do...while会先执行一次循环语句,再判断循环条件

do...while与while循环的区别在于: do...while会先执行一次循环语句,再判SEO靠我断循环条件。

#include<iostream> using namespace std;/*do...while和while的区别:do...while会先执行一次循环(不管条件是否SEO靠我满足) */ int main() {// 在屏幕中输出0~9这10个数字int num = 0;cout << "---------do while---------SEO靠我" << endl;do{cout << num << endl;num += 1;} while (num < 10);cout << "\r\n---------while---------" <SEO靠我< endl;num = 0;while (num < 10) {cout << num << endl;num += 1;}system("pause");return 0; }

练习SEO靠我案例:水仙花数

案例描述:水仙花数是指: 一个3位数,它的每个位上的数字的3次幂之和等于它本身

例如: 13+53+33=1531^3 + 5^3 + 3^3 = 15313+53+33=153

请利用doSEO靠我...while语句,求出所有3位数中的水仙花数

#include<iostream> using namespace std; #include<math.h> // SEO靠我引入数学头文件int main() {// 1. 将所有的三位数进行输出(100 ~ 999)int num = 100;int a = 0; // 个位int b = 0; // 十位int c =SEO靠我 0; // 百位int times = 1;// 2. 在所有三位数中找到水仙花数/*e.g. 153获取个位: 153 % 10 = 3 获取十位: 153 / 10 = 15; 15 % 10 SEO靠我= 5 获取百位: 153 / 100 = 1判断:个位**3 + 十位**3 + 百位**3 == 本身*/do{a = num % 10;b = num / 10 % 10;c = num / 1SEO靠我00;if ((pow(a, 3) + pow(b, 3) + pow(c, 3)) == num) {cout << "水仙花数" << times << ": " << num << endl;tSEO靠我imes += 1;}num += 1;} while (num < 1000);/*水仙花数1: 153水仙花数2: 370水仙花数3: 371水仙花数4: 407*/system("pause")SEO靠我;return 0; }

4.2.3 for循环语句

作用: 满足循环条件,执行循环语句

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

示例:

#include<ioSEO靠我stream> using namespace std;int main() {// 打印数字0~9for (int i = 0; i < 10; i++){cout << i << SEO靠我endl;}system("pause");return 0; }

注意:

for循环中的表达式,要用分号进行分割while, do...while, for都是开发中常用的循环语句,foSEO靠我r循环结构比较清晰,比较常用。

练习案例:敲桌子

案例描述:从1开始数的数字100,如果数字个位含有7,或者数字十位含有7,或者该数字是7的倍数,我们打印敲桌子,其余数字直接打印输出。

#include<iSEO靠我ostream> using namespace std;int main() {// 1. 先输出1到100for (int i = 1; i <= 100; i++){/*2. 从SEO靠我这100个数字中找到特殊数字,改为"敲桌子"* 特殊数字* 7的倍数: num % 7 == 0* 个位有7: num % 10 == 7* 十位有7: num / 10 == 7*/if (i % SEO靠我7 == 0 || i % 10 == 7 || i / 10 == 7) {cout << "敲桌子" << endl;}else {cout << i << endl;}}system("pausSEO靠我e");return 0; }

4.2.4 嵌套循环

作用: 在循环体中再嵌套一层循环,解决一些实际问题

例如我们想在屏幕中打印如下图片,就需要利用嵌套循环。

#include<iostreaSEO靠我m> using namespace std;int main() {for (int i = 0; i < 11; i++) // 行{for (int j = 0; j < 11;SEO靠我 j++) // 列{cout << "* ";}cout << endl;}system("pause");return 0; }

练习案例:乘法口诀表

案例描述:利角嵌套循环,实现九九SEO靠我乘法表

#include<iostream> using namespace std;int main() {/** 列数 * 行数 = 计算结构* * 条件: 列数 <= 当前行数*/SEO靠我for (int i = 1; i < 10; i++) // 行{for (int j = 1; j <= i; j++) // 列{cout << i << "*" << j << "=" << SEO靠我i * j << "\t";}cout << endl;}/*1*1=12*1=2 2*2=43*1=3 3*2=6 3*3=94*1=4 4*2=8 4*3=12 4*4=165*1=5 5*2=1SEO靠我0 5*3=15 5*4=20 5*5=256*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=367*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=SEO靠我42 7*7=498*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=649*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6SEO靠我=54 9*7=63 9*8=72 9*9=81请按任意键继续. . .*/system("pause");return 0; }

4.3 跳转语句

4.3.1 break语句

作用: 用于SEO靠我跳出选择结构或者循环结构

break使用的时机:

出现在switch条件语句中,作用是终止case并跳出switch出现在循环语句中,作用是跳出当前的循环语句出现在嵌套循环中,跳出最近的内层循环语句

示例1SEO靠我:

#include<iostream> using namespace std;// break的使用时机 int main() {// 1. 出现在switch语句中SEO靠我 cout << "------ 1. 出现在switch语句中 ------" << endl;cout << "请选择副本的难度" << endl;cout << "1. 普通" << endl;SEO靠我cout << "2. 中等" << endl;cout << "3. 困难" << endl;int select = 0; // 用户选择结果变量cout << "请选择(1 2 3): ";ciSEO靠我n >> select; // 等待用户输入switch (select){case 1:cout << "您选择的是普通难度" << endl;break;case 2:cout << "您选择的是SEO靠我中等难度" << endl;break;case 3:cout << "您选择的是困难难度" << endl;break;default:cout << "您选择的选择有误!" << endl;breSEO靠我ak;}// 2. 出现在循环语句中cout << "\r\n------ 2. 出现在循环语句中 ------" << endl;for (int i = 0; i < 10; i++){cout SEO靠我<< i << endl;// 如果i==5, 退出循环if (i == 5) {break;}}// 3. 出现在嵌套循环语句中cout << "\r\n------ 3. 出现在嵌套循环语句中 -SEO靠我-----" << endl;for (int i = 0; i < 10; i++){for (int j = 0; j < 10; j++){// 如果j == 5,退出循环if (j == 5)SEO靠我 {break;}cout << "* ";}cout << endl;}system("pause");return 0; }

4.3.2 continue语句

作用: 在循环语句中,跳SEO靠我过本次循环,继续执行下一次循环。

#include<iostream> using namespace std;int main() {for (int i = 0; i <= 100;SEO靠我 i += 1) {if (i % 10 == 0) {cout << endl;}// 如果是奇数则输出if (i % 2 == 1) {cout << i << "\t";}else{continSEO靠我ue;}}/*1 3 5 7 911 13 15 17 1921 23 25 27 2931 33 35 37 3941 43 45 47 4951 53 55 57 5961 63 65 67 69SEO靠我71 73 75 77 7981 83 85 87 8991 93 95 97 99*/system("pause");return 0; }

4.3.3 goto语句

作用: 可以无条件SEO靠我跳转语句

跳转语法: goto 标记; -> goto FLAG; // 跳到标记

标记语法: 标记: -> FLAG: // 表明标记的位置

示例:

int main3() {goto FLAG; // 跳SEO靠我转到标记FLAG的位置FLAG: // 确认标记的位置return 0; }

解释: 如果标记的名称存在,当程序执行到goto语句时,会跳转到标记的位置

注意:学习goto语句只是为了明白SEO靠我这个语句的作用,我们写代码的时候不要用,跳来跳去的,麻烦且容易出bug.

#include<iostream> using namespace std;// goto语句 SEO靠我 int main() {cout << "1. xxxxxxxx" << endl;cout << "2. xxxxxxxx" << endl;goto FLAG; // 跳转到标记FLAG的位置cSEO靠我out << "3. xxxxxxxx" << endl;cout << "4. xxxxxxxx" << endl;FLAG: // 确认标记的位置cout << "5. xxxxxxxx" << SEO靠我endl;/*1. xxxxxxxx2. xxxxxxxx5. xxxxxxxx请按任意键继续. . .*/system("pause");return 0; }

5. 数组 (arraSEO靠我y)

5.1 概述

所谓数组(array),就是一个集合,里面存放了相同类型的数据元素,数组有两个特点:

数组中的每个数据元素都是相同的数据类型数组是由连续的内存位置组成的

在Python中,list是列表不SEO靠我是数组;Python的list里面可以存放不一样的数据类型,但数组中一定要存放相同的数据类型

5.2 一维数组

5.2.1 一维数组的定义方式

一维数组定义的三种方式:

数据类型 数组名 [数组长度];数据类SEO靠我型 数组名[数组长度] = {值1, 值2, ...}; (如果在初始化数据时没有全部填写,则会用0来填补)数据类型 数组名[] = {值1, 值2, ...];

C++中没有built-in的方法求数SEO靠我组的长度

总结:

数组名的命名规范与变量名命名规范一致,不要和变量重名数组的下标从0开始索引

示例:

#include<iostream> using namespace std;// 一维数SEO靠我组的定义 int main() {// ----- 1. 数据类型 数组名 [数组长度]; -----cout << "----- 1. 数据类型 数组名 [数组长度]; -----"SEO靠我 << endl;int arr1[5]; // 定义数组// 给数组中的元素赋值for (int i = 0; i < 5; i++){arr1[i] = (i + 1) * 10;}// 访问数组SEO靠我元素for (int i = 0; i < 5; i++) {cout << "arr1[" << i << "]: " << arr1[i] << endl;}// ----- 2. 数据类型 数组SEO靠我名[数组长度] = { 值1, 值2, ... }; ----- cout << "\r\n----- 2. 数据类型 数组名[数组长度] = {值1, 值2, ...}; ----- " << enSEO靠我dl;int arr2[5] = { 10, 20, 30, 40, 50 };// 访问数组元素for (int i = 0; i < 5; i++) {cout << "arr2[" << i <SEO靠我< "]: " << arr2[i] << endl;}// ----- 3. 数据类型 数组名[] = {值1, 值2, ...}; -----cout << "\r\n----- 3. 数据类型 SEO靠我数组名[] = {值1, 值2, ...}; -----" << endl;int arr3[] = { 90, 80, 60, 50, 40, 30, 20, 10, 0 };// 访问数组元素foSEO靠我r (int i = 0; i < 9; i++){cout << "arr3[" << i << "]: " << arr3[i] << endl;}/*----- 1. 数据类型 数组名 [数组长SEO靠我度]; -----arr1[0]: 10arr1[1]: 20arr1[2]: 30arr1[3]: 40arr1[4]: 50----- 2. 数据类型 数组名[数组长度] = {值1, 值2, .SEO靠我..}; -----arr2[0]: 10arr2[1]: 20arr2[2]: 30arr2[3]: 40arr2[4]: 50----- 3. 数据类型 数组名[] = {值1, 值2, ...}SEO靠我; -----arr3[0]: 90arr3[1]: 80arr3[2]: 60arr3[3]: 50arr3[4]: 40arr3[5]: 30arr3[6]: 20arr3[7]: 10arr3[SEO靠我8]: 0*/system("pause");return 0; }

5.2.2 一维数组数组名

一维数组名称的用途:

可以统计整个数组在内存中的长度: sizeof(数组名)可以获取数组在SEO靠我内存中的首地址: cout << arr << endl; 单个元素的长度: sizeof(arr[0])整个数组的长度: sizeof(arr)

这样我们就可以得到数组中元素的个数,SEO靠我即数组的长度。

C++中没有built-in的方法求数组的长度

#include<iostream> using namespace std;int main() {// 1. 可以统计整SEO靠我个数组在内存中的长度: sizeof(数组名)int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };cout << "arr数组占用内存空间大小为: " << sSEO靠我izeof(arr) << "字节" << endl; // arr数组占用内存空间大小为: 40字节cout << "arr数组每个元素占用内存空间大小为: " << sizeof(arr[0]) SEO靠我<< "字节" << endl; // arr数组每个元素占用内存空间大小为: 4字节cout << "arr数组的元素个数(数组长度)为: " << sizeof(arr) / sizeof(arrSEO靠我[0]) << endl; // arr数组的元素个数(数组长度)为: 10// 2. 可以获取数组在内存中的首地址: cout << arr << endl; cout << "arr数组的首地址为SEO靠我: " << arr << endl; // 000000B955D0F748cout << "arr数组的首地址(十进制)为: " << (int) arr << endl; // 14397581SEO靠我52cout << "arr数组的第一个元素的地址为: " << &arr[0] << endl; // 000000B955D0F748cout << "arr数组的第一个元素的地址(十进制)为: SEO靠我" << (int)&arr[0] << endl; // 1439758152cout << "arr数组的第二个元素的地址为: " << &arr[0] << endl; // 000000B95SEO靠我5D0F748cout << "arr数组的第二个元素的地址(十进制)为: " << (int)&arr[0] << endl; // 1439758152/** 1. &是取址符* * 2. 可以看SEO靠我到,数组的首地址和数组第一个元素的地址是一样的!* * 3. 因为数组在内存空间中是连续的,因此第一个元素的地址和第二个元素的地址差4(int的大小是4字节!)*/// 数组名是常量,不可以进行赋值/SEO靠我/ arr = 100; // IDE报错: 表达式必须是可修改的左值system("pause");return 0; }

练习案例1: 五只小猪称体重

案例描述: 在一个数组中记录了五SEO靠我只小猪的体重,如: int arr[5]= { 300, 350, 200, 400, 250 };

找出并打印最重的小猪体重。

#include<iostream> using nameSEO靠我space std;int main() {// 1. 创建5只小猪体重的数组int arr[5] = { 300, 350, 200, 400, 250 };// 2. 定义最大值int max_nSEO靠我um = arr[0];int order = 0;// 3. 逻辑判断for (int i = 1; i < 5; i++){if (arr[i] > max_num) {max_num = arrSEO靠我[i];order = i;}}// 4. 打印最大值cout << "最大值为: " << max_num;cout << "。是第 " << order + 1 << " 只小猪" << endlSEO靠我; // 最大值为: 400。是第 4 只小猪system("pause");return 0; }

练习案例2: 数组元素逆置

案例描述: 请声明一个5个元素的数组,并且将元素逆置.

(如SEO靠我原数组元素为: 1, 3, 2, 5, 4; 逆置后输出结果为: 4, 5, 2, 3, 1);

#include<iostream> using namespace std;int mSEO靠我ain() {// 1. 创建数组int arr[] = { 1, 3, 2, 5, 4 };// 2. 实现逆置/*2.1 记录起始下标的位置2.2 记录结束下标的位置2.3 起始下标和结束下标的元SEO靠我素互换2.4 起始位置++; 结束位置++2.5 循环执行2.1操作,直到起始位置 >= 结束位置*/int start = 0;int end = sizeof(arr) / sizeof(arr[SEO靠我0]) - 1;int tmp = 0;while (start < end) {// 元素互换tmp = arr[start];arr[start] = arr[end];arr[end] = tmSEO靠我p;// 更新下标start += 1;end -= 1;}// 3. 打印逆置后的数组cout << "数组元素逆置后: " << endl;for (int i = 0; i < sizeof(aSEO靠我rr) / sizeof(arr[0]); i++){cout << arr[i] << ", "; // 4, 5, 2, 3, 1,}cout << endl;system("pause");reSEO靠我turn 0; }

思路2:

#include<iostream> using namespace std;int main() {// 1. 创建数组int arr[] SEO靠我= { 1, 3, 2, 5, 4 };int length = sizeof(arr) / sizeof(arr[0]) - 1;// 2. 具体实现for (int i = 0; i <= lenSEO靠我gth / 2; i++) // 注意只走一半{ int tmp = arr[i];arr[i] = arr[length - i];arr[length - i] = tmp;}// 3. 打印逆置SEO靠我后的数组cout << "数组元素逆置后: " << endl;for (int i = 0; i <= length; i++){cout << arr[i] << ", "; // 4, 5, 2SEO靠我, 3, 1,}cout << endl;system("pause");return 0; }

5.2.3 冒泡排序

作用: 最常用的排序算法,对数组内元素进行排序

比较相邻的元素。如果第SEO靠我一个比第二个大,就交换他们两个。对每一对相邻元素做同样的工作,执行完毕后,找到第一个最大值。重复以上的步骤,每次比较次数-1,直到不需要比较

示例: 将数组{ 4, 2, 8, 0, 5, 7, 1, SEO靠我3, 9 }进行升序排序

#include<iostream> using namespace std;int main() {int arr[] = { 4, 2, 8, 0, 5, SEO靠我7, 1, 3, 9 };int n = sizeof(arr) / sizeof(arr[0]) - 1;// 排序前cout << "排序前: " << endl;for (int i = 0; SEO靠我i <= n; i++){cout << arr[i] << " "; // 4 2 8 0 5 7 1 3 9}cout << endl;/*外层: n - 1内层: n - i - 1*/for SEO靠我(int i = 0; i < n - 1; i++) // n - 1轮(外层){for (int j = 0; j < n - i - 1; j++) // 内层{if (arr[j] > arrSEO靠我[j + 1]) {int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}// 排序后cout << "排序后: " << endl;forSEO靠我 (int i = 0; i <= n; i++){cout << arr[i] << " "; // 0 1 2 3 4 5 7 8 9}cout << endl;system("pause");rSEO靠我eturn 0; }

5.3 二维数组

二维数组就是在一维数组上,多加了一个维度。

5.3.1 二维数组定义方式

二维数组定义的四种方式:

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

建议: 以上4种定义方式,利用第二种更加直观,提高代码的可读性

在定义二维数组时,如果初始化了数据,可以省略行数

示例:

#include<iostream> using nameSEO靠我space std;int main() {// 1. 数据类型 数组名[行数][列数];int arr1[2][3];// 赋值for (int i = 0; i < 2; i++) {for (iSEO靠我nt j = 0; j < 3; j++){arr1[i][j] = (i + 1) * (j + 1) * 10;}}// 查看cout << "------ 1. 数据类型 数组名[行数][列数]SEO靠我; ------" << endl;for (int i = 0; i < 2; i++) {for (int j = 0; j < 3; j++){cout << arr1[i][j] << " "SEO靠我;}cout << endl;}// 2. 数据类型 数组名[行数][列数] = { {数据1,数据2},{数据3,数据4 }};int arr2[2][3] = { {10, 20, 30}, {4SEO靠我0, 50, 60} };// 查看cout << "\r\n------ 2. 数据类型 数组名[行数][列数] = { {数据1,数据2},{数据3,数据4 }}; ------" << endlSEO靠我;for (int i = 0; i < 2; i++) {for (int j = 0; j < 3; j++){cout << arr2[i][j] << " ";}cout << endl;}/SEO靠我/ 3. 数据类型 数组名[行数][列数] = {数据1,数据2,数据3,数据4};int arr3[2][3] = { 10, 20, 30, 40, 50, 60 };// 查看cout << "SEO靠我\r\n------ 3. 数据类型 数组名[行数][列数] = {数据1,数据2,数据3,数据4}; ------" << endl;for (int i = 0; i < 2; i++) {forSEO靠我 (int j = 0; j < 3; j++){cout << arr2[i][j] << " ";}cout << endl;}// 4. 数据类型 数组名[][列数] = {数据1,数据2,数据SEO靠我3,数据4};int arr4[][3] = { 10, 20, 30, 40, 50, 60 };// 查看cout << "\r\n------ 4. 数据类型 数组名[][列数] = {数据1,SEO靠我数据2,数据3,数据4}; ------" << endl;for (int i = 0; i < 2; i++) {for (int j = 0; j < 3; j++){cout << arr2[SEO靠我i][j] << " ";}cout << endl;}/*------ 1. 数据类型 数组名[行数][列数]; ------10 20 3020 40 60------ 2. 数据类型 数组名[行SEO靠我数][列数] = { {数据1,数据2},{数据3,数据4 }}; ------10 20 3040 50 60------ 3. 数据类型 数组名[行数][列数] = {数据1,数据2,数据3,数据SEO靠我4}; ------10 20 3040 50 60------ 4. 数据类型 数组名[][列数] = {数据1,数据2,数据3,数据4}; ------10 20 3040 50 60*/systSEO靠我em("pause");return 0; }

5.3.2 二维数组数组名

查看二维数组所占内存空间获取二维数组首地址 #include<iostream> SEO靠我 using namespace std;int main() {// 1. 查看二维数组所占内存空间int arr[2][3] = {{1, 2, 3},{4, 5, 6}};cout << "二维SEO靠我数组占用的内存空间为: " << sizeof(arr) << "字节" << endl; // 24字节cout << "二维数组第一行占用的内存空间为: " << sizeof(arr[0]) <SEO靠我< "字节" << endl; // 12字节cout << "二维数组第一个元素占用的内存空间为: " << sizeof(arr[0][0]) << "字节" << endl; // 4字节// SEO靠我统计出二维数组的行和列cout << "二维数组行数为: " << sizeof(arr) / sizeof(arr[0]) << endl; // 2cout << "二维数组列数为: " << sSEO靠我izeof(arr[0]) / sizeof(arr[0][0]) << endl; // 3// 2. 获取二维数组首地址cout << "二维数组的首地址为: " << arr << endl;cSEO靠我out << "二维数组第一行的首地址为: " << arr[0] << endl;cout << "二维数组第二行的首地址为: " << arr[1] << endl;cout << "二维数组第一SEO靠我个元素的地址为: " << &arr[0][0] << endl;cout << "二维数组第二个元素的地址为: " << &arr[0][1] << endl;/*第一行和第二行首地址差12(因为列SEO靠我=3)二维数组的首地址为: 000000438C4FF648二维数组第一行的首地址为: 000000438C4FF648二维数组第二行的首地址为: 000000438C4FF654二维数组第一个元素的SEO靠我地址为: 000000438C4FF648二维数组第二个元素的地址为: 000000438C4FF64C*/system("pause");return 0; }

5.3.3 二维数组应SEO靠我用案例

考试成绩统计:

案例描述: 有三名同学(张三,李四,王五),在一次考试中的成绩分别如下表,请分别输出三名同学的总成绩。

姓名语文数学英语张三100100100李四9050100王五607080 SEO靠我 #include<iostream> using namespace std; #include<string>// 二维数组案例 —— 考试成绩统计 SEO靠我 int main() {// 1. 创建二维数组int scores[3][3] = {{100, 100, 100},{90, 50, 100},{60, 70, 80},};strinSEO靠我g names[3] = {"张三","李四","王五",};// 2. 统计每个人的总和分数for (int i = 0; i < 3; i++) // 行{int sum = 0; // 统计SEO靠我分数总和for (int j = 0; j < 3; j++) // 列{sum += scores[i][j];}// 打印每个人的总成绩cout << names[i] << "的总分为: " SEO靠我<< sum << endl;}/*张三的总分为: 300李四的总分为: 240王五的总分为: 210*/system("pause");return 0; }

6. 函数

6.1 概述

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

一个较大的程序,一般分为若干个程序块,每个模块实现特定的功能。

6.2 函数的定义

函数的定义一般主要有5个步骤:

返回值类型函数名参数表列函数体语句return表达式

语法SEO靠我:

返回值类型 函数名 (形参1, 形参2, ...) {函数体语句;return表达式; } 返回值类型: 一个函数可以返回一个值。在函数定义中函数名: 给函数起个名称参数列表: 使用该函数时,传SEO靠我入的数据函数体语句: 花括号内的代码,函数内需要执行的语句return表达式: 和返回值类型挂钩,函数执行完后,返回相应的数据

示例:

// 加法函数,实现两个整型相加并返回相加的结果 int add(iSEO靠我nt num1, int num2) {int sum = num1 + num2;return sum; }

6.3 函数的调用

功能: 使用定义好的函数

语法: 函数名(参数1, 参数2, ...)

示例SEO靠我:

#include<iostream> using namespace std;// 加法函数,实现两个整型相加并返回相加的结果 int add(int num1, int num2) {int suSEO靠我m = num1 + num2;return sum; }int main() {int a = 10;int b = 20;int res = add(a, b);cout << "两数之和为: "SEO靠我 << res << endl; // 两数之和为: 30//system("pause"); // 按任意键继续的功能return 0; }

6.4 值传递

所谓值传递,就是函数调用时实参将数值传入SEO靠我给形参值传递时,如果形参发生,并不会影响实参 #include<iostream> using namespace std;// 如果函数不需要返回值,声明的时候可以写void void swap(SEO靠我int num1, int num2) {cout << "交换前: " << "num1: " << num1 << "\t num2: " << num2 << endl;int tmp = nuSEO靠我m1;num1 = num2;num2 = tmp;cout << "交换后: " << "num1: " << num1 << "\t num2: " << num2 << endl; }int mSEO靠我ain() {int a = 10;int b = 20;swap(a, b);/*交换前: num1: 10 num2: 20交换后: num1: 20 num2: SEO靠我10*///system("pause"); // 按任意键继续的功能return 0; }

void: 中文翻译为“无类型”。常用在程序编写中对定义函数的参数类型、返回值、函数中指针类型进行声明。vSEO靠我oid的字面意思是“无类型”。

6.5 函数的常见样式

常见的函数样式有4种:

无参无返有参无返无参有返有参有返 #include<iostream> using namespace std;// 1. SEO靠我无参无返 void test_01() {cout << "1. 无参无返" << endl; }// 2. 有参无返 void test_02(int a) {cout << "2. 有参无返: "SEO靠我;cout << a << endl; }// 3. 无参有返 float test_03() {cout << "3. 无参有返" << endl;return 3.14f; }// 4. 有参有返SEO靠我 double test_04(float a) {cout << "4. 有参有返" << endl;return a; }int main() {// 1. 无参无返test_01(); // SEO靠我1. 无参无返// 2. 有参无返test_02(10086); // 2. 有参无返 10086// 3. 无参有返float return_param_1 = test_03(); // 3.SEO靠我 无参有返cout << "return_param_1: " << return_param_1 << endl; // return_param_1: 3.14// 4. 有参有返double SEO靠我return_param_2 = test_04(6.17f); // 4. 有参有返cout << "return_param_2: " << return_param_2 << endl; /SEO靠我/ return_param_2: 6.17return 0; }

6.6 函数的声明

作用: 告诉编译器函数名称及如何调用函数。函数的实际主体可以单独定义。

函数的声明可以多次,但是函数的定义只能有一次 SEO靠我 #include<iostream> using namespace std; // 让我们可以使用cout在屏幕输出// 提前告诉编译器函数的存在,可以利用函数的声明 // 函数的声明可以有多次SEO靠我,但函数的定义只能有一次! int max(int a, int b); int max(int a, int b); int max(int a, int b);int main() {int a SEO靠我= 10;int b = 20;int max_num = max(a, b);cout << "max_num: " << max_num; // max_num: 20return 0; }//SEO靠我 函数的定义只能有一次! int max(int a, int b) {return a > b ? a : b; }

6.7 函数的分文件编写

作用: 让代码结构更加清晰

函数分文件编写一般有4个步骤:

SEO靠我建后缀名为.h的头文件 -> swap.h创建后缀名为.cpp的源文件 -> swap.cpp在头文件中写函数的声明在源文件中写函数的定义

示例:

1. 创建后缀名为.h的头文件 -> swap.h

2. SEO靠我创建后缀名为.cpp的源文件 -> swap.cpp

3. 在头文件中写函数的声明

#include<iostream> using namespace std;// 函数的声明 void swap(inSEO靠我t num1, int num2);

4. 在源文件中写函数的定义

#include "swap.h"// 函数的定义 void swap(int num1, int num2) {cout << "交换SEO靠我前: " << "num1: " << num1 << "\t num2: " << num2 << endl;int tmp = num1;num1 = num2;num2 = tmp;cout <SEO靠我< "交换后: " << "num1: " << num1 << "\t num2: " << num2 << endl; }

main函数所在.cpp文件

#include<iostream> usinSEO靠我g namespace std; // 让我们可以使用cout在屏幕输出 #include "swap.h"/*函数分文件编写一般有4个步骤:1. 创建后缀名为.h的头文件: swap.h2. 创建SEO靠我后缀名为.cpp的源文件: swap.cpp3. 在头文件中写函数的声明4. 在源文件中写函数的定义 */int main() {int a = 10;int b = 20;swap(a, b);/*SEO靠我交换前: num1: 10 num2: 20交换后: num1: 20 num2: 10*/return 0; }

7. 指针 (pointer)

7.1 指针的基本概念

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

内存编号是从0开始记录的,一般用十六进制数字表示可以利用指针变量保存地址

简单来说,指针就是一个地址

7.2 指针变量的定义和使用

指针变量定义语法: 数据类型 *变量SEO靠我名;

示例:

#include<iostream> using namespace std;int main() {// 1. 定义指针: 数据类型 *指针变量名int a = 10;int* p;; SEO靠我// 这就定义了一个指针// 让指针*p记录变量a的地址p = &a;cout << "a的地址为: " << &a << endl; // 000000F62119F7C4cout << "指针pSEO靠我为: " << p << endl; // 000000F62119F7C4cout << "*p为: " << *p << endl; // 10// 2. 使用指针// 可以通过解引用的方式来SEO靠我找到指针指向的内存// 指针前加一个*代表解引用,即找到指针指向的内存中的数据*p = 1000;cout << "a = " << a << endl; // 1000cout << "*p = SEO靠我" << *p << endl; // 1000return 0; }

7.3 指针所占的内存空间

提问:指针也是一种数据类型,那么这种数据类型占用多少内存空间?

回答:在32位操作系统下,指针都占用4个SEO靠我字节空间;在64位操作系统下,指针占用8个字节空间。

在IDE中可以修改系统环境的位数:

示例:

#include<iostream> using namespace std;int main() {intSEO靠我 a = 10;int* p = &a;cout << "sizeof(int*) = " << sizeof(int*) << "字节" << endl; // 8字节cout << "sizeoSEO靠我f(int*) = " << sizeof(p) << "字节" << endl; // 8字节cout << "sizeof(float*) = " << sizeof(float*) << "字SEO靠我节" << endl; // 8字节cout << "sizeof(double*) = " << sizeof(double*) << "字节" << endl; // 8字节cout << "SEO靠我sizeof(char*) = " << sizeof(char*) << "字节" << endl; // 8字节cout << "sizeof(long*) = " << sizeof(longSEO靠我*) << "字节" << endl; // 8字节cout << "sizeof(long long*) = " << sizeof(long long*) << "字节" << endl; /SEO靠我/ 8字节/* 32位操作系统sizeof(int*) = 4字节sizeof(float*) = 4字节sizeof(double*) = 4字节sizeof(char*) = 4字节sizeof(SEO靠我long*) = 4字节sizeof(long long*) = 4字节*//* 64位操作系统sizeof(int*) = 8字节sizeof(float*) = 8字节sizeof(double*SEO靠我) = 8字节sizeof(char*) = 8字节sizeof(long*) = 8字节sizeof(long long*) = 8字节*/return 0; }

7.4 空指针和野指针

空指针: 指针SEO靠我变量指向内存中编号为0的空间用途: 初始化指针变量注意: 空指针指向的内存是不可以访问的

指针不知道指向哪里好,就指向空

0 ~ 255这块内存是系统占用的,我们不可以访问#include<iostreaSEO靠我m> using namespace std;// 空指针 int main() {// 1. 空指针用于给指针变量进行初始化int* p = NULL;cout << "p: " << p << eSEO靠我ndl; // p: 0000000000000000// 2. 空指针是不可以进行访问的(0 ~ 255的内存编号是系统占用的,因此不可以访问)// *p = 100; // 引发了异常: 写入SEO靠我访问权限冲突。p 是 nullptr。return 0; }野指针:指针变量指向非法的内存空间。

示例:

#include<iostream> using namespace std;// 野指针:在程序SEO靠我中尽量避免出现野指针 int main() {// 没有申请内存就直接让指针指向这个地址int* p = (int*)0x1100;cout << "p: " << p << endl; // p:SEO靠我 0000000000001100cout << "*p: " << *p << endl; // 引发了异常: 读取访问权限冲突。p 是 0x1100。// 因为我们之前没有申请0x1100这个地SEO靠我址,所以C++程序是没有权限去操作这块地址return 0; }

总结:空指针和野指针都不是我们申请的空间,因此不要访问!

7.5 const修饰指针

const修饰指针有三种情况:

const修饰指针 ->SEO靠我 常量指针 -> const int* p = &a;const修饰常量 -> 指针常量 -> int* const p = &a;const即修饰指针,又修饰常量 -> const int* conSEO靠我st p = &a;

记名称:常量=const, 指针=*,这样就好记了

对于常量指针,可以理解为const限制的*,所以 *p 的操作就不可以了

对于指针常量,可以理解为const限制的p,所以 p 的操SEO靠我作就不可以了

const修饰谁,谁就是常量,常量是不可以修改的!

7.5.1 常量指针

const修饰指针 -> 常量指针 -> const int* p = &a;

特点:指针的指向可以修改,但指针指向的值SEO靠我不可以修改,即

int a = 10; int b = 10;// 定义常量指针 const int* p = &a;// 判断 *p = 20; // 不可以,指针不可以修改指向的值 p = &b;SEO靠我 // 可以,指针可以修改指向

7.5.2 指针常量

const修饰常量 -> 指针常量 -> int* const p = &a;

特点:指针的指向不可以改,指针指向的值可以修改。

int a = 10;SEO靠我 int b = 10;// 定义常量指针 int* const p = &a;// 判断 *p = 20; // 可以,指针可以修改指向的值 p = &b; // 不可以,指针不可以修改指向

7.SEO靠我5.2 const即修饰指针,又修饰常量

const即修饰指针,又修饰常量 -> const int* const p = &a;

特点:指针的指向和指向的值都不可以改!

int a = 10; int bSEO靠我 = 10;// 定义常量指针 const int* const p = &a;// 判断 *p = 20; // 不可以,指针不可以修改指向的值 p = &b; // 不可以,指针不可以修改指向SEO靠我

示例:

#include<iostream> using namespace std;int main() {int a = 10;int b = 20;// 1. const修饰指针 -> 常量指针cSEO靠我onst int* p1 = &a;// *p1 = 20; // 报错:“p1” : 不能给常量赋值 指针p1 = &b; // 不报错// 2. const修饰常量 -> 指针常量int* cSEO靠我onst p2 = &a;*p2 = 20; // 不报错// p2 = &b; // 报错:“p2” : 不能给常量赋值// 3. const修饰指针和常量const int* const p3SEO靠我 = &a;// *p3 = 20; // 报错:表达式必须是可修改的左值// p3 = &b; // 报错:“p3” : 不能给常量赋值return 0; }

技巧: 看const右侧紧跟着的是指SEO靠我针还是常量,是指针就是常量指针,是常量就是指针常量

7.6 指针和数组

作用:利用指针访问数组中元素

示例:

#include<iostream> using namespace std;int main()SEO靠我 {// 利用指针访问数组中的元素int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };cout << "第一个元素为: " << arr[0] << endl;SEO靠我 // 1int* p = arr; // 数组名就是数组第一个元素的地址(数组的首地址)cout << "利用指针访问第一个元素: " << *p << endl; // 1p += 1; SEO靠我// 让指针向后偏移4个字节cout << "利用指针访问第二个元素: " << *p << endl; // 1 // 2cout << "\r\n--------利用指针遍历数组-------SEO靠我-" << endl;int* p2 = arr;for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){cout << *p2 << " "; SEO靠我 // 1 2 3 4 5 6 7 8 9 10p2 += 1;}cout << endl;return 0; }

7.7 指针和函数

作用:利用指针作函数参数,可以修改实参的值

#include<iostSEO靠我ream> using namespace std;// 实现两个数字进行交互 void swap_01(int a, int b) {int tmp = a;a = b;b = tmp;cout <SEO靠我< "----形参----" << endl;cout << "[swap_01] a = " << a << endl;cout << "[swap_01] b = " << b << endl; SEO靠我}void swap_02(int* p1, int* p2) {int tmp = *p1;*p1 = *p2;*p2 = tmp;cout << "----形参----" << endl;coutSEO靠我 << "[swap_02] a = " << *p1 << endl;cout << "[swap_02] b = " << *p2 << endl; }int main() {// 1. 值传递:SEO靠我 不会修改实参int a = 10;int b = 20;swap_01(a, b);cout << "----实参----" << endl;cout << "a = " << a << endl;SEO靠我cout << "b = " << b << endl;/*----形参----[swap_01] a = 20[swap_01] b = 10----实参----a = 10b = 20*/// 2SEO靠我. 地址传递: 可以修改实参swap_02(&a, &b);cout << "----实参----" << endl;cout << "a = " << a << endl;cout << "b = SEO靠我" << b << endl;/*----形参----[swap_02] a = 20[swap_02] b = 10----实参----a = 20b = 10*/return 0; }

总结:如果不SEO靠我想修改实参,就用值传递;如果想修改实参,就用地址传递

7.8 指针、数组、函数

案例描述:封装一个函数,利用冒泡排序,实现对整型数组的升序排序。

例如数组: int arr[10] = { 4, 3, 6,SEO靠我 9, 1, 2, 10, 8, 7, 5 }

#include<iostream> using namespace std;void bubble_sort(int* arr, int n) {/**SEO靠我 arr: 数组的首地址(因为要接收一个地址,所以数据类型是int*)* n: 数组的长度*/for (int i = 0; i < n - 1; i++){for (int j = 0; j < nSEO靠我 - i - 1; j++){if (arr[j] > arr[j + 1]) {int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}} SEO靠我 }void print_array(int* arr, int n) {/** arr: 数组的首地址(因为要接收一个地址,所以数据类型是int*)* n: 数组的长度*/for (inSEO靠我t i = 0; i < n; i++){cout << arr[i] << " ";}cout << endl; }int main8() {// 1. 创建数组int arr[10SEO靠我] = { 4, 3, 6, 9, 1, 2, 10, 8, 7, 5 };int len = sizeof(arr) / sizeof(arr[0]);// 2. 创建函数,实现冒泡排序bubbleSEO靠我_sort(arr, len);// 3. 打印排序后的数组print_array(arr, len); // 1 2 3 4 5 6 7 8 9 10return 0; }

8. 结构SEO靠我

8.1 结构体基本概念

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

8.2 结构体定义和使用

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

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

stSEO靠我ruct 结构体名 变量名;struct 结构体名 变量名 = { 成员1值, 成员2值, ... };定义结构体时顺便创建变量

注意

在日常使用时,方法1和方法2用的比较多,第3种用的比较少!在定义结SEO靠我构体变量时,struct关键字可以省略

总结

定义结构体时的关键字是struct,不可省略创建结构体变量时,关键字struct可以省略结构体变量利用操作符 . 访问成员

可以看到,C/C++中的结构体和PSEO靠我ython中的class很像。

示例:

#include<iostream> using namespace std; #include<string>// 1. 创建学生SEO靠我数据类型:姓名,年龄,分数 struct Student {// 成员列表string name;int age;int score; };structSEO靠我 Student2 {// 成员列表string name;int age;int score; }s3; // 在创建结构体的时候创建顺便创建变量int main()SEO靠我 {// 2. 通过学生类型创建具体学生// 2.1 struct 结构体名 变量名;struct Student s1;s1.name = "张三";s1.age = 18;s1.score = 1SEO靠我00;// cout << s1 << endl; // 没有与这些操作数匹配的cout << "姓名: " << s1.name << "\t年龄: " << s1.age << "\t分数: " SEO靠我<< s1.score << endl; // 姓名: 张三 年龄: 18 分数: 100// 2.2 struct 结构体名 变量名 = { 成员1值, 成员2值, ... }; Student sSEO靠我2 = { "李四", 19, 80 }; // 在创建结构体变量时struct关键字可以省略cout << "姓名: " << s2.name << "\t年龄: " << s2.age << "\SEO靠我t分数: " << s2.score << endl; // 姓名: 李四 年龄: 19 分数: 80// 2.3 定义结构体时顺便创建变量s3.name = "王五";s3.age = 20;s3.SEO靠我score = 60;cout << "姓名: " << s3.name << "\t年龄: " << s3.age << "\t分数: " << s3.score << endl; // 姓名: 王SEO靠我五 年龄: 20 分数: 60return 0; }

8.3 结构体数组

作用:将自定义的结构体放入到数组中以方便维护。

语法:struct 结构体名 数组名[元素个数] = { {}, {SEO靠我}, ... }

示例:

#include<iostream> using namespace std; #include<string>// 1. 定义结构体 SEO靠我 struct Student {string name;int age;int score; };int main() {// 2. 创建结构体数组StudentSEO靠我 stuArray[] = {{"张三", 18, 100},{"李四", 20, 99},{"王五", 38, 80},};// 3. 给结构体数组中的元素赋值stuArray[2].name = SEO靠我"赵六";stuArray[2].age = 40;stuArray[2].score = 75;// 4. 遍历结构体数组for (int i = 0; i < 3; i++){cout << "姓SEO靠我名: " << stuArray[i].name << "\t年龄: " << stuArray[i].age << "\t分数: " << stuArray[i].score << endl;}SEO靠我/*姓名: 张三 年龄: 18 分数: 100姓名: 李四 年龄: 20 分数: 99姓名: 赵六 年龄: 40 分数: 75*SEO靠我/return 0; }

8.4 结构体指针

作用:通过指针访问结构体中的成员

利用操作符 -> 可以通过结构体指针访问结构体属性 struct Student {string name;int age;SEO靠我int score; }> 总结:结构体指针可以通过>操作符来访问结构体中的成员int main() {Student s1 = { "张三", 18, 100 };Student* p = &s1;SEO靠我// 利用 -> 访问结构体中的成员变量cout << p->name << endl;cout << p->age << endl;cout << p->score << endl;return 0SEO靠我; }

示例:

#include<iostream> using namespace std; #include<string>// 1. 定义结构体 struct Student {string namSEO靠我e;int age;int score; };int main() {// 2. 创建学生的结构体变量Student s = { "张三", 18, 100 };// 3. 通过指针指向结构体变量//SEO靠我 int* p = &s; // "Student *" 类型的值不能用于初始化Student* p = &s; // 结构体就是我们自定义的数据类型,指针当然也要使用这种数据类型// 4. 通过SEO靠我指针访问结构体变量中的数据cout << "姓名: " << p->name << "\t年龄: " << p->age << "\t分数: " << p->score << endl;// 姓名: SEO靠我张三 年龄: 18 分数: 100return 0; }

8.5 结构体嵌套结构体

作用:结构体中的成员可以是另一个结构体。

例子:每个老师辅导一个学员,一个老师的结构体中,记录一个SEO靠我学生的结构体。

示例:

#include<iostream> using namespace std; #include<string>// 1. 定义学生的结构体 struct Student {strSEO靠我ing name;int age;int score; };// 2. 定义老师的结构体 struct Teacher {int id; // 教师编号string name;int age;StuSEO靠我dent stu; // 辅导的学生 };int main() {// 3. 创建老师Teacher t = { 10086, "王老师", 50, {"小王", 16, 60} };/*TeachSEO靠我er t;t.id = 10086;t.name = "王老师";t.age = 50;t.stu.name = "小王";t.stu.age = 16;t.stu.score = 60;*/coutSEO靠我 << "老师姓名: " << t.name << "\t老师编号: " << t.id << "\t老师年龄: " << t.age << "\n辅导的学生的姓名: " << t.stu.name SEO靠我<< "\t辅导的学生的年龄: " << t.stu.age << "\t辅导的学生的分数" << t.stu.score << endl;/*老师姓名: 王老师 老师编号: 10086SEO靠我 老师年龄: 50辅导的学生的姓名: 小王 辅导的学生的年龄: 16 辅导的学生的分数60*/return 0; }

8.6 结构体做函数参数

作用:将结构体作为参数向函数中传递

传递方式有两种:

SEO靠我传递: 改变形参不会 改变实参地址传递:改变形参 改变实参

总结:如果不想修改主函数中的数据,用值传递,反之用地址传递。

示例:

#include<iostream> using namespace std;SEO靠我 #include<string>// 定义学生结构体 struct Student {string name;int age;int score; };// 打印学生信息的函数 // 1. 值传递 SEO靠我void print_student_1(Student stu) {cout << "---------子函数[print_student_1]中打印---------" << endl;stu.nSEO靠我ame = "[值传递修]改后的姓名";cout << "姓名: " << stu.name << "\t年龄: "<< stu.age << "\t分数: " << stu.score<< endlSEO靠我; }// 2. 地址传递 void print_student_2(Student* p) {cout << "---------子函数[print_student_2]中打印---------" SEO靠我<< endl;p->name = "[地址传递]修改后的姓名";cout << "姓名: " << p->name << "\t年龄: "<< p->age << "\t分数: " << p->scSEO靠我ore<< endl; }int main() {Student stu;stu.name = "张三";stu.age = 20;stu.score = 80;// 将学生传入到一个函数中,打印学生SEO靠我身上所有的信息// 1. 值传递print_student_1(stu);cout << "---------main函数中打印---------" << endl;cout << "姓名: " <<SEO靠我 stu.name << "\t年龄: "<< stu.age << "\t分数: " << stu.score<< endl << endl << endl;// 2. 地址传递print_studSEO靠我ent_2(&stu);cout << "---------main函数中打印---------" << endl;cout << "姓名: " << stu.name << "\t年龄: "<< sSEO靠我tu.age << "\t分数: " << stu.score<< endl;/*---------子函数[print_student_1]中打印---------姓名: [值传递修]改后的姓名 SEO靠我 年龄: 20 分数: 80---------main函数中打印---------姓名: 张三 年龄: 20 分数: 80---------子函数[printSEO靠我_student_2]中打印---------姓名: [地址传递]修改后的姓名 年龄: 20 分数: 80---------main函数中打印---------姓名: [地址传递]SEO靠我修改后的姓名 年龄: 20 分数: 80*/return 0; }

8.7结构体中const使用场景

作用:用const来防止误操作。

示例:

#include<iostream> usiSEO靠我ng namespace std; #include<string>struct Student {string name;int age;int score; };void print_stu_inSEO靠我fo_value_trans(Student stu) {/** 这种值传递的方式会有问题:* 值传递的形参会复制传入的值,因此会带来额外的性能开销。* 如果调用这个函数的次数很多,那么带来的性能开销SEO靠我就会变大!* * 要想减小开销,可以使用地址传递!*/stu.age += 1; // 让年龄增加一岁cout << "姓名: " << stu.name << "\t年龄: " << stu.agSEO靠我e << "\t分数: " << stu.score << endl; }void print_stu_info_pointer_trans(const Student* stu) {/** 值传递因SEO靠我为会复制实参,带来了大量的性能开销,而地址传递* 传入的是指针,一个指针的大小为4字节(32位系统下),因此* 复制指针带来的性能开销明显降低!* * 但是地址传递有一个问题:那就是改变形参会改变实参SEO靠我。* 为了解决这个问题,我们应该使用const关键字!* * 具体实现是给形参加一个const,即const Student+* stu。* const修饰的是*,因此指针指向地址的值是不允许改变的,SEO靠我* 这样stu->age += 1;这行语句写完后就IDE就会报错,告诉* 我们不要修改指针指向地址的值!*///stu->age += 1; // 表达式必须是可修改的左值cout << "姓名:SEO靠我 " << stu->name << "\t年龄: "<< stu->age + 1 << "\t分数: " << stu->score<< endl; }int main() {// 创建结构体变量SEO靠我Student stu = { "张三", 18, 90 };// 通过函数打印结构体变量的信息print_stu_info_value_trans(stu);cout << "-----调用prinSEO靠我t_stu_info_value_trans后-----" << endl;cout << "姓名: " << stu.name << "\t年龄: "<< stu.age << "\t分数: " <SEO靠我< stu.score<< endl << endl << endl;print_stu_info_pointer_trans(&stu);cout << "-----调用print_stu_infoSEO靠我_pointer_trans后-----" << endl;cout << "姓名: " << stu.name << "\t年龄: "<< stu.age << "\t分数: " << stu.scSEO靠我ore<< endl;/*姓名: 张三 年龄: 19 分数: 90-----调用print_stu_info_value_trans后-----姓名: 张三 年龄: SEO靠我18 分数: 90姓名: 张三 年龄: 19 分数: 90-----调用print_stu_info_pointer_trans后-----姓名: 张三 SEO靠我 年龄: 18 分数: 90*/return 0; }

8.8 结构体案例

8.8.1 案例1

案例描述:学校正在做毕设项目,每名老师带领5个学生,总共有3名老师,需求如下:

设计学生和老师的结SEO靠我构体,其中在老师的结构体中,有老师姓名和一个存放5名学生的数组作为成员学生的成员有姓名、考试分数创建数组存放3名老师,通过函数给每个老师及所带的学生赋值最终打印出老师数据以及老师所带的学生数据。

示例:SEO靠我

#include<iostream> using namespace std; #include<string> #include<ctime>// 定义学生的结构体 struct Student {SEO靠我string stu_name;int stu_score; };// 定义老师的结构体 struct Teacher {string teac_name;// 学生数组Student stu_arrSEO靠我ay[5]; };// 给老师和学生赋值的函数 void allocate_space(Teacher teac_array[], int len) {string name_seed = "ABCDSEO靠我E";for (int i = 0; i < len; i++) // 外层:给老师赋值{teac_array[i].teac_name = "Teacher_";teac_array[i].teaSEO靠我c_name += name_seed[i];for (int j = 0; j < 5; j++) // 内层:给学生赋值{teac_array[i].stu_array[j].stu_name SEO靠我= "Student_";teac_array[i].stu_array[j].stu_name += name_seed[j];int random = rand() % 61 + 40; // SEO靠我40 ~ 100teac_array[i].stu_array[j].stu_score = random;}} }void print_info(Teacher teac_arraySEO靠我[], int len) {for (int i = 0; i < len; i++){cout << "老师姓名: " << teac_array[i].teac_name << endl;for SEO靠我(int j = 0; j < 5; j++){cout << "\t学生姓名: " << teac_array[i].stu_array[j].stu_name << "\t考试分数: " << tSEO靠我eac_array[i].stu_array[j].stu_score << endl;}} }int main() {// 加入随机数种子srand((unsigned int)tiSEO靠我me(NULL));// 1. 创建3名老师的数组Teacher teac_array[3];// 2. 通过函数给3名老师的信息赋值,并给老师带的学生赋值int len = sizeof(teac_SEO靠我array) / sizeof(teac_array[0]);allocate_space(teac_array, len);// 3. 打印所有老师及所带学生的信息print_info(teac_aSEO靠我rray, len);/*老师姓名: Teacher_A学生姓名: Student_A 考试分数: 78学生姓名: Student_B 考试分数: 40学生姓名: Student_C 考试分数: 86SEO靠我学生姓名: Student_D 考试分数: 61学生姓名: Student_E 考试分数: 42老师姓名: Teacher_B学生姓名: Student_A 考试分数: 87学生姓名: StudentSEO靠我_B 考试分数: 61学生姓名: Student_C 考试分数: 100学生姓名: Student_D 考试分数: 68学生姓名: Student_E 考试分数: 48老师姓名: Teacher_C学SEO靠我生姓名: Student_A 考试分数: 88学生姓名: Student_B 考试分数: 83学生姓名: Student_C 考试分数: 53学生姓名: Student_D 考试分数: 79学生姓名:SEO靠我 Student_E 考试分数: 90*/return 0; }

8.8.2案例2

案例描述:设计一个英雄的结构体,包括成员姓名,年龄,性别;创建结构体数组,数组中存放5名英雄。

通过冒泡排SEO靠我序的算法,将数组中的英雄按照年龄进行升序排序,最终打印排序后的结果。

五名英雄信息如下:

{"盖伦", 23, "男"}, {"卡特", 22, "女"}, {"赵信", SEO靠我30, "男"}, {"嘉文四世", 25, "男"}, {"瑞文", 24, "女"}, {"亚索", 20, "男"}, {"卡莎"SEO靠我, 26, "女"},

示例:

#include<iostream> using namespace std; #include<string>// 1. 设计英雄结构体 SEO靠我 struct Hero {string name;int age;string gender; };void bubble_sort_for_hero(SEO靠我Hero hero_arr[], int n) {for (int i = 0; i < n - 1; i++){for (int j = 0; j < n - i - 1; j++){if (herSEO靠我o_arr[j].age > hero_arr[j + 1].age) {Hero tmp = hero_arr[j];hero_arr[j] = hero_arr[j + 1];hero_arr[jSEO靠我 + 1] = tmp;}}} }void print_hero(Hero hero_arr[], int n) {cout << "-------排序后的结果-------" << SEO靠我endl;for (int i = 0; i < n; i++){cout << "姓名: " << hero_arr[i].name << "\t年龄: "<< hero_arr[i].age <<SEO靠我 "\t性别: " << hero_arr[i].gender << endl;} }int main() {// 2. 创建数组存放5名英雄Hero hero_arr[] = {{"SEO靠我盖伦", 23, "男"},{"卡特", 22, "女"},{"赵信", 30, "男"},{"嘉文四世", 25, "男"},{"瑞文", 24, "女"},{"亚索", 20, "男"},{"卡莎SEO靠我", 26, "女"},};int n = sizeof(hero_arr) / sizeof(hero_arr[0]);// 3. 对数组进行排序,按照年龄进行升序排序bubble_sort_forSEO靠我_hero(hero_arr, n);// 4. 将排序后的结果打印输出print_hero(hero_arr, n);/*-------排序后的结果-------姓名: 亚索 年龄: 20SEO靠我 性别: 男姓名: 卡特 年龄: 22 性别: 女姓名: 盖伦 年龄: 23 性别: 男姓名: 瑞文 年龄: 24 SEO靠我 性别: 女姓名: 嘉文四世 年龄: 25 性别: 男姓名: 卡莎 年龄: 26 性别: 女姓名: 赵信 年龄: 30 性别: 男*/rSEO靠我eturn 0; }

9. 通讯录管理系统

9.1 系统需求

通讯录是一个可以记录亲人、好友信息的工具。本教程主要利用C++来实现一个通讯录管理系统。系统中需要实现的功能如下:

添加联系人:向通讯录中添加新人SEO靠我,信息包括(姓名、性别、年龄、联系电话、家庭住址)最多记录1000人显示联系人:显示通讯录中所有联系人信息删除联系人:按照姓名进行删除指定联系人查找联系人:按照姓名查看指定联系人信息修改联系人:按照姓SEO靠我名重新修改指定联系人清空联系人:清空通讯录中所有信息退出通讯录:退出当前使用的通讯录

9.2 创建项目

9.3 菜单功能

功能描述:用户选择功能的界面

菜单界面效果如下图:

步骤:

封装函数显示该界面如 voidSEO靠我 showMenu()在main函数中调用封装好的函数

代码:

// 菜单界面 void show_menu() {cout << "*****************************" << eSEO靠我ndl;cout << "*****\t1. 添加联系人\t*****" << endl;cout << "*****\t2. 显示联系人\t*****" << endl;cout << "*****SEO靠我\t3. 删除联系人\t*****" << endl;cout << "*****\t4. 查找联系人\t*****" << endl;cout << "*****\t5. 修改联系人\t*****"SEO靠我 << endl;cout << "*****\t6. 清空联系人\t*****" << endl;cout << "*****\t0. 退出通讯录\t*****" << endl;cout << "SEO靠我*****************************" << endl; }

9.4 退出功能

功能描述:退出通讯录系统

思路:根据用户不同的选择,进入不同的功能,可以选择switch分支结构,将整个SEO靠我架构进行搭建。

当用户选择0时候,执行退出,选择其他先不做操作,也不会退出程序。

代码:

int main() {int select = 0; // 用户选择输入的变量while (true) // SEO靠我大循环{show_menu();cout << "请选择功能: ";cin >> select;// 根据输入做出判断switch (select){case 1: // 1. 添加联系人breakSEO靠我;case 2: // 2. 显示联系人break;case 3: // 3. 删除联系人break;case 4: // 4. 查找联系人break;case 5: // 5. 修改联系人bSEO靠我reak;case 6: // 6. 清空联系人break;case 0: // 0. 退出通讯录cout << "欢迎下次使用!" << endl;system("pause"); // 请按SEO靠我任意键继续return 0; // main函数的return -> 退出main函数break;default:cout << "您的输入无效!" << endl;break;}}system("SEO靠我pause");return 0; // 返回正常退出值 }

9.5 添加联系人

功能描述:实现添加联系人功能,联系人上限为1000人,联系人信息包括(姓名、性别、年龄、联系电话、家庭住址SEO靠我)

添加联系人实现步骤:

设计联系人结构体设计通讯录结构体main函数中创建通讯录封装添加联系人函数测试添加联系人功能

9.5.1 设计联系人结构体

联系人信息包括:姓名、性别、年龄、联系电话、家庭住址

设计如SEO靠我下:

// 设计联系人结构体 struct Person {string p_name;int p_gender; // 1: 男; 2: 女int p_age;striSEO靠我ng p_phone;string p_address; };

9.5.2. 设计通讯录结构体

设计时候可以在通讯录结构体中,维护一个容量为1000的存放联系人的数组,并记录当前通讯录中联SEO靠我系人数量

设计如下:

// 设计通讯录结构体 struct AddressBooks {// 通信录中保存的联系人数组Person person_arr[MAX];// 初SEO靠我始化通讯录中当前人员个数(最后一个联系人的索引)int p_last_idx; };

9.5.3. main函数中创建通讯录

添加联系人函数封装好后,在main函数中创建一个通讯录变量,这SEO靠我个就是我们需要一直维护的通讯录。

int main() {// 创建通讯录结构体变量AddressBooks abs;// 初始化通讯录中当前人员个数(最后一个联系人的索引)abs.p_last_idxSEO靠我 = 0;}

9.5.4. 封装添加联系人函数

思路:添加联系人前先判断通讯录是否已满,如果满了就不再添加,未满情况将新联系人信息逐个加入到通讯录。

添加联系人代码:

// 1. 添加联系人 SEO靠我void add_person(AddressBooks* abs) {// 判断通讯录是否满了if (abs->p_last_idx == MAX) {cout << "通讯录已满,无法添加!" <SEO靠我< endl;return; // 这里的return表明当前函数结束}else {// 添加具体联系人// 姓名string name;cout << "请输入姓名: ";cin >> name;aSEO靠我bs->person_arr[abs->p_last_idx].p_name = name;// 性别int gender = 0;cout << "请输入性别(1为男性, 2为女性): ";whilSEO靠我e (true){cin >> gender;if (gender == 1 || gender == 2) {abs->person_arr[abs->p_last_idx].p_gender = SEO靠我gender;break; // 停止无限循环}else {cout << "您的输入有误,请重新输入: ";}}// 年龄int age = 0;cout << "请输入年龄: ";while (tSEO靠我rue){cin >> age;if (age <= 0 || age >= 150){cout << "您的输入有误,请重新输入: ";}else{abs->person_arr[abs->p_laSEO靠我st_idx].p_age = age;break; // 停止无限循环}}// 电话cout << "请输入联系电话(移动号码或固定号码): ";string phone;while (true){SEO靠我cin >> phone;if (phone.length() != 11 && phone.length() != 7){cout << "您输入的联系方式有误,请重新输入: ";}else{absSEO靠我->person_arr[abs->p_last_idx].p_phone = phone;break; // 停止无限循环}}// 住址cout << "请输入家庭住址: ";string addrSEO靠我ess;cin >> address;abs->person_arr[abs->p_last_idx].p_address = address;// 添加成功后,让最后一个联系的索引+1cout <<SEO靠我 "联系人[" << name << "]添加成功!" << endl;abs->p_last_idx += 1;// 添加清屏操作system("pause"); // 请按任意键继续system(SEO靠我"cls"); // 清屏操作: cls = clear screen} }

9.5.5. 测试添加联系人功能

测试效果如图:

9.6 显示联系人

功能描述:显示通讯录中已有的联系人信息

显示联SEO靠我系人实现步骤:

封装显示联系人函数测试显示联系人功能

9.6.1 封装显示联系人函数

思路:判断如果当前通讯录中没有人员,就提示记录为空,人数大于0,显示通讯录中信息。

显示联系人代码:

// 2. 显示所有联SEO靠我系人 void show_person(AddressBooks* abs) {// 判断通讯录中人数是否为0if (abs->p_last_idx == 0){cout << "通讯SEO靠我录为空,请添加联系人" << endl;}else{for (int i = 0; i < abs->p_last_idx; i++){ cout << "[" << i + 1 << "]: " <SEO靠我< abs->person_arr[i].p_name << endl;cout << "\t性别: " << (abs->person_arr[i].p_gender == 1 ? "男" : "女SEO靠我") << endl;cout << "\t年龄: " << abs->person_arr[i].p_age << endl;cout << "\t电话: " << abs->person_arr[SEO靠我i].p_phone << endl;cout << "\t住址: " << abs->person_arr[i].p_address << endl;cout << "---------------SEO靠我----------------" << endl;}}system("pause");system("cls"); }

9.7 删除联系人

功能描述:按照姓名进行删除指定联系人

删除联系人SEO靠我实现步骤:

封装检测联系人是否存在封装删除联系人函数测试删除联系人功能

9.7.1 封装检测联系人是否存在

设计思路:删除联系人前,我们需要先判断用户输入的联系人是否存在。

如果存在删除不存在提示用户没有要删SEO靠我除的联系人

因此我们可以把检测联系人是否存在封装成一个函数中:

如果存在,返回联系人在通讯录中的位置不存在返回-1。 // 检测联系人是否存在,如果存在则返回对应索引,不存在返回-1 SEO靠我 int is_exist(AddressBooks* abs, string name) {/** abs: 通讯录地址* name: 要删除人的名字*/for (int i = 0; iSEO靠我 < abs->p_last_idx; i++){if (abs->person_arr[i].p_name == name) // 找到了,返回对应的idx{return i;}}// 走完了forSEO靠我循环还是没有找到return -1; }

9.7.2. 封装删除联系人函数

根据用户输入的联系人判断该通讯录中是否有此人查找到进行删除,并提示删除成功

查不到提示查无此人。// 删除指定的联SEO靠我系人 void del_person(AddressBooks* abs) {cout << "请输入您要删除的联系人: ";string delete_name;cin >> delSEO靠我ete_name;int res = is_exist(abs, delete_name);if (res != -1){for (int i = res; i < abs->p_last_idx; SEO靠我i++){// 数据前移abs->person_arr[i] = abs->person_arr[i + 1];}// 更新通讯录最后一个人员的索引abs->p_last_idx -= 1;cout SEO靠我<< "删除成功..." << endl;}else{cout << "查无此人!" << endl;}system("pause");system("cls"); }

9.8 查找联系SEO靠我

功能描述:按照姓名查看指定联系人信息

查找联系人实现步骤:

封装查找联系人函数测试查找指定联系人

9.8.1 封装查找联系人函数

实现思路:判断用户指定的联系人是否存在,如果存在显示信息,不存在则提示查无此SEO靠我人。

查找联系人代码:

// 4. 查找指定联系人信息 void find_person(AddressBooks* abs) {cout << "请输入您要查找的联系人: ";strinSEO靠我g find_name;cin >> find_name;// 判断指定联系人是否存在int res = is_exist(abs, find_name);if (res != -1){cout <<SEO靠我 "[" << res + 1 << "]: " << abs->person_arr[res].p_name << endl;cout << "\t性别: " << (abs->person_arrSEO靠我[res].p_gender == 1 ? "男" : "女") << endl;cout << "\t年龄: " << abs->person_arr[res].p_age << endl;coutSEO靠我 << "\t电话: " << abs->person_arr[res].p_phone << endl;cout << "\t住址: " << abs->person_arr[res].p_addrSEO靠我ess << endl;cout << "-------------------------------" << endl;}else{cout << "查无此人!" << endl;}system(SEO靠我"pause");system("cls"); }

9.9 修改联系人

功能描述:按照姓名重新修改指定联系人

修改联系人实现步骤

封装修改联系人函数测试修改联系人功能

9.9.1 封装修改联系人SEO靠我函数

实现思路:查找用户输入的联系人,如果查找成功进行修改操作,查找失败提示查无此人。

修改联系人代码:

// 5. 修改指定联系人信息 void modify_person(AddressSEO靠我Books* abs) {cout << "请输入您要修改的联系人: ";string name;cin >> name;int res = is_exist(abs, name);if (res !SEO靠我= -1){// 姓名string name;cout << "请输入姓名(不修改输入0): ";cin >> name;if (name != "0"){abs->person_arr[res].pSEO靠我_name = name;}// 性别string gender;while (true){cout << "请输入性别(不修改输入0): ";cin >> gender;if (gender != SEO靠我"0"){if (gender == "1"){abs->person_arr[res].p_gender = 1;break;}else if (gender == "2"){abs->personSEO靠我_arr[res].p_gender = 2;break;}else{cout << "您输入的性别有误(请输入1或2)" << endl;}}else{break;}}// 年龄int age;whSEO靠我ile (true){cout << "请输入年龄(不修改输入0): ";cin >> age;if (age == 0){break;}else{if (age <= 0 || age >= 150SEO靠我){cout << "您的输入有误,请重新输入" << endl;}else{abs->person_arr[res].p_age = age;break;}}}// 电话cout << "请输入电话SEO靠我(不修改输入0): ";string phone;while (true){ cin >> phone;if (phone == "0"){break;}if (phone.length() != 1SEO靠我1 && phone.length() != 7){cout << "您输入的联系方式有误,请重新输入(移动号码或固定号码): " << endl;}else{abs->person_arr[res]SEO靠我.p_phone = phone;break; }}// 地址cout << "请输入地址(不修改输入0): ";string address;cin >> address;if (address !SEO靠我= "0"){abs->person_arr[res].p_address = address;}cout << "修改成功!" << endl;}else{cout << "查无此人!" << enSEO靠我dl;}system("pause");system("cls"); }

9.10 清空联系人

功能描述:清空通讯录中所有信息清空联系人

实现步骤:

封装清空联系人函数测试清空联系人

9.10.SEO靠我1 封装清空联系人函数

实现思路:将通讯录所有联系人信息清除掉,只要将通讯录记录的联系人数量置为0,做逻辑清空即可。

清空联系人代码:

// 6. 清空所有联系人 void clear_alSEO靠我l_persons(AddressBooks* abs) {abs->p_last_idx = 0;cout << "通讯录已清空..." << endl;system("pause");systemSEO靠我("cls"); }

9.11 通讯录系统全部代码

#include <iostream> // 屏幕中输入输出都需要这个头文件 using namespace std; SEO靠我// 使用标准的命名空间 #include <string> #define MAX 1000 // 定义一个宏常量// 设计联系人结构体 structSEO靠我 Person {string p_name;int p_gender; // 1: 男; 2: 女int p_age;string p_phone;string p_address;SEO靠我 };// 设计通讯录结构体 struct AddressBooks {// 通信录中保存的联系人数组Person person_arr[MAX];//SEO靠我 初始化通讯录中当前人员个数(最后一个联系人的索引)int p_last_idx; };// 1. 添加联系人 void add_person(AddressBooksSEO靠我* abs) {// 判断通讯录是否满了if (abs->p_last_idx == MAX) {cout << "通讯录已满,无法添加!" << endl;return; // 这里的return表SEO靠我明当前函数结束}else {// 添加具体联系人// 姓名string name;cout << "请输入姓名: ";cin >> name;abs->person_arr[abs->p_last_iSEO靠我dx].p_name = name;// 性别int gender = 0;cout << "请输入性别(1为男性, 2为女性): ";while (true){cin >> gender;if (gSEO靠我ender == 1 || gender == 2) {abs->person_arr[abs->p_last_idx].p_gender = gender;break; // 停止无限循环}elseSEO靠我 {cout << "您的输入有误,请重新输入: ";}}// 年龄int age = 0;cout << "请输入年龄: ";while (true){cin >> age;if (age <= 0SEO靠我 || age >= 150){cout << "您的输入有误,请重新输入: ";}else{abs->person_arr[abs->p_last_idx].p_age = age;break; /SEO靠我/ 停止无限循环}}// 电话cout << "请输入联系电话(移动号码或固定号码): ";string phone;while (true){cin >> phone;if (phone.lengtSEO靠我h() != 11 && phone.length() != 7){cout << "您输入的联系方式有误,请重新输入: ";}else{abs->person_arr[abs->p_last_idxSEO靠我].p_phone = phone;break; // 停止无限循环}}// 住址cout << "请输入家庭住址: ";string address;cin >> address;abs->persSEO靠我on_arr[abs->p_last_idx].p_address = address;// 添加成功后,让最后一个联系的索引+1cout << "联系人[" << name << "]添加成功!" SEO靠我<< endl;abs->p_last_idx += 1;// 添加清屏操作system("pause"); // 请按任意键继续system("cls"); // 清屏操作: cls = clearSEO靠我 screen} }// 2. 显示所有联系人 void show_person(AddressBooks* abs) {// 判断通讯录中人数是否为0if (abs-SEO靠我>p_last_idx == 0){cout << "通讯录为空,请添加联系人" << endl;}else{for (int i = 0; i < abs->p_last_idx; i++){ coSEO靠我ut << "[" << i + 1 << "]: " << abs->person_arr[i].p_name << endl;cout << "\t性别: " << (abs->person_arSEO靠我r[i].p_gender == 1 ? "男" : "女") << endl;cout << "\t年龄: " << abs->person_arr[i].p_age << endl;cout <<SEO靠我 "\t电话: " << abs->person_arr[i].p_phone << endl;cout << "\t住址: " << abs->person_arr[i].p_address << SEO靠我endl;cout << "-------------------------------" << endl;}}system("pause");system("cls"); }// SEO靠我检测联系人是否存在,如果存在则返回对应索引,不存在返回-1 int is_exist(AddressBooks* abs, string name) {/** abs: 通讯录地址* SEO靠我name: 要删除人的名字*/for (int i = 0; i < abs->p_last_idx; i++){if (abs->person_arr[i].p_name == name) // 找SEO靠我到了,返回对应的idx{return i;}}// 走完了for循环还是没有找到return -1; }// 删除指定的联系人 void del_person(AddrSEO靠我essBooks* abs) {cout << "请输入您要删除的联系人: ";string delete_name;cin >> delete_name;int res = is_exist(absSEO靠我, delete_name);if (res != -1){for (int i = res; i < abs->p_last_idx; i++){// 数据前移abs->person_arr[i] SEO靠我= abs->person_arr[i + 1];}// 更新通讯录最后一个人员的索引abs->p_last_idx -= 1;cout << "删除成功..." << endl;}else{coutSEO靠我 << "查无此人!" << endl;}system("pause");system("cls"); }// 4. 查找指定联系人信息 void find_persoSEO靠我n(AddressBooks* abs) {cout << "请输入您要查找的联系人: ";string find_name;cin >> find_name;// 判断指定联系人是否存在int reSEO靠我s = is_exist(abs, find_name);if (res != -1){cout << "[" << res + 1 << "]: " << abs->person_arr[res].SEO靠我p_name << endl;cout << "\t性别: " << (abs->person_arr[res].p_gender == 1 ? "男" : "女") << endl;cout << SEO靠我"\t年龄: " << abs->person_arr[res].p_age << endl;cout << "\t电话: " << abs->person_arr[res].p_phone << eSEO靠我ndl;cout << "\t住址: " << abs->person_arr[res].p_address << endl;cout << "----------------------------SEO靠我---" << endl;}else{cout << "查无此人!" << endl;}system("pause");system("cls"); }// 5. 修改指定联系人信息 SEO靠我 void modify_person(AddressBooks* abs) {cout << "请输入您要修改的联系人: ";string name;cin >> name;int rSEO靠我es = is_exist(abs, name);if (res != -1){// 姓名string name;cout << "请输入姓名(不修改输入0): ";cin >> name;if (nSEO靠我ame != "0"){abs->person_arr[res].p_name = name;}// 性别string gender;while (true){cout << "请输入性别(不修改输入SEO靠我0): ";cin >> gender;if (gender != "0"){if (gender == "1"){abs->person_arr[res].p_gender = 1;break;}eSEO靠我lse if (gender == "2"){abs->person_arr[res].p_gender = 2;break;}else{cout << "您输入的性别有误(请输入1或2)" << eSEO靠我ndl;}}else{break;}}// 年龄int age;while (true){cout << "请输入年龄(不修改输入0): ";cin >> age;if (age == 0){breaSEO靠我k;}else{if (age <= 0 || age >= 150){cout << "您的输入有误,请重新输入" << endl;}else{abs->person_arr[res].p_age SEO靠我= age;break;}}}// 电话cout << "请输入电话(不修改输入0): ";string phone;while (true){ cin >> phone;if (phone == "SEO靠我0"){break;}if (phone.length() != 11 && phone.length() != 7){cout << "您输入的联系方式有误,请重新输入(移动号码或固定号码): " SEO靠我<< endl;}else{abs->person_arr[res].p_phone = phone;break; }}// 地址cout << "请输入地址(不修改输入0): ";string adSEO靠我dress;cin >> address;if (address != "0"){abs->person_arr[res].p_address = address;}cout << "修改成功!" <SEO靠我< endl;}else{cout << "查无此人!" << endl;}system("pause");system("cls"); }// 6. 清空联系人 voSEO靠我id clear_all_persons(AddressBooks* abs) {cout << "[二次确认]确定要清空通讯录吗?(Y/N): ";string confirmation;whileSEO靠我 (true){cin >> confirmation;if (confirmation == "Y"){// 将最后一个联系人的索引置为0,做逻辑清空操作abs->p_last_idx = 0;coSEO靠我ut << "通讯录已清空..." << endl;break;}else if (confirmation == "N"){cout << "操作取消" << endl;break;}else{coSEO靠我ut << "请输入Y/N: ";}}system("pause");system("cls"); }// 菜单界面 void show_menu() {cout <<SEO靠我 "*****************************" << endl;cout << "*****\t1. 添加联系人\t*****" << endl;cout << "*****\t2.SEO靠我 显示联系人\t*****" << endl;cout << "*****\t3. 删除联系人\t*****" << endl;cout << "*****\t4. 查找联系人\t*****" << SEO靠我endl;cout << "*****\t5. 修改联系人\t*****" << endl;cout << "*****\t6. 清空联系人\t*****" << endl;cout << "****SEO靠我*\t0. 退出通讯录\t*****" << endl;cout << "*****************************" << endl; }int main() {//SEO靠我 创建通讯录结构体变量AddressBooks abs;// 初始化通讯录中当前人员个数(最后一个联系人的索引)abs.p_last_idx = 0;int select = 0; // 用户选择输入SEO靠我的变量while (true) // 大循环{show_menu();cout << "请选择功能: ";cin >> select;// 根据输入做出判断switch (select){case 1SEO靠我: // 1. 添加联系人add_person(&abs); // 用地址传递,以修改实参break;case 2: // 2. 显示联系人show_person(&abs);break;case 3SEO靠我: // 3. 删除联系人del_person(&abs);break;case 4: // 4. 查找联系人find_person(&abs);break;case 5: // 5. 修改联系人moSEO靠我dify_person(&abs);break;case 6: // 6. 清空联系人clear_all_persons(&abs);break;case 0: // 0. 退出通讯录cout << SEO靠我"欢迎下次使用!" << endl;system("pause"); // 请按任意键继续return 0; // main函数的return -> 退出main函数break;default:couSEO靠我t << "您的输入无效!" << endl;break;}}system("pause");return 0; // 返回正常退出值 }
“SEO靠我”的新闻页面文章、图片、音频、视频等稿件均为自媒体人、第三方机构发布或转载。如稿件涉及版权等问题,请与 我们联系删除或处理,客服邮箱:html5sh@163.com,稿件内容仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同 其观点或证实其内容的真实性。

网站备案号:浙ICP备17034767号-2