N

Norlcayn的博客

A text-focused Halo theme

  • 首页
  • 文章
  • 默认分类
  • 关于
主页 CPP基础内容
文章

CPP基础内容

发表于 2025-06-28 更新于 昨天
作者 Administrator
125~160 分钟 阅读

相关内容来自B站黑马程序员:C++教程从0到1入门编程

C++起步知识

注释

和Java一样,C++的注释分为单行注释和多行注释

单行注释://

多行注释:/* */

例如:

// 1. 这是单行注释

/*
1. 这是多行注释
2. 这是多行注释
3. 这是多行注释
*/

入口函数

在C++中,入口函数为main函数,每个程序有且仅有一个入口函数,对应Java中的public static void main

#include <iostream>

using namespace std;

int main() {
cout << "Hello World" << endl;

return 0;
}

变量

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

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

#include <iostream>

using namespace std;

int main() {
int a = 10;

cout << "a = " << a << endl;

return 0;
}

变量命名规则:

  1. 字母、数字和下划线:变量名可以包含字母(A-Z, a-z)、数字(0-9)和下划线(_)。
  2. 以字母或下划线开头:变量名必须以字母或下划线开头,不能单独使用数字开头。
  3. 区分大小写:C++是区分大小写的语言,因此variable和Variable会被视为两个不同的标识符。
  4. 避免使用保留关键字:避免使用C++的保留关键字作为变量名。例如,int, class, if, for等是C++的关键字,不能用作变量名。
asm do if return typedef
auto double inline short typeid
bool dynamic_cast int signed typename
break else long sizeof union
case enum mutable static unsigned
catch explicit namespace static_cast using
char export new struct virtual
class extern operator switch void
const false private template volatile
const_cast float protected this wchar_t
continue for public throw while
default friend register true
delete goto reinterpret_cast try

常量

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

定义方式:

  1. #define宏常量:#define 常量名 常量值 - 通常在文件上方定义,表示一个常量,常量名一般都是以全部大写命名
  2. const修饰的变量:const 数据类型 常量名 = 常量值 - 通常在变量定义前加关键字const,修饰该变量为常量,不可修改 - 命名规则与变量一样
#include <iostream>
#define PI 3.141

using namespace std;

int main() {
    // PI = 10 报错!

cout << "PI = " << PI << endl;

const int minutesInOneHour = 60;

    // minutesInOneHour = 100 报错!

cout << "一小时有:" << minutesInOneHour << "分钟" << endl;

return 0;
}

数据类型

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

整型

整型也称整数类型,C++有以下几种整型类型:

数据类型 占用空间 取值范围
short(短整型) 2字节 (-2^15 ~ 2^15-1)
int(整型) 4字节 (-2^31 ~ 2^31-1)
long(长整形) Windows为4字节,Linux为4字节(32位),8字节(64位) (-2^31 ~ 2^31-1)
long long(长长整形) 8字节 (-2^63 ~ 2^63-1)

sizeof关键字

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

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

#include <iostream>

using namespace std;

int main() {
char h = 'h';
cout << sizeof(int) << endl;// 4
cout << sizeof(h) << endl;// 1
return 0;
}

浮点型

作用:表示小数

浮点型分为两种:

  1. 单精度float
  2. 双精度double
数据类型 占用空间 有效数字范围
float 4字节 7位有效数字
double 8字节 15~16位有效数字
#include <iostream>

using namespace std;

int main() {
float a = 3.1415f;
double b = 1.01;

float c = 1.0000001f;

cout << a << endl;// 3.1415
cout << b << endl;// 1.01
cout << c << endl;// 1默认情况下,输出一个小数只会显示6位有效数字

// 科学计数法
    float f1 = 3e2;// 表示 3 * 10 ^ 2,即300
    float f2 = 3e-2;// 表示 3 * 0.1 ^ 2,即0.03

return 0;
}

精度丢失问题:

  • 十进制 0.1 的二进制是无限循环小数:
    0.1(十进制) = 0.00011001100110011...(二进制),就像十进制的 1/3 = 0.3333…。

案例:

float count = 0.1 + 0.2;// 如果将小数后全部显示出来,结果是:0.30000000000000004

字符型

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

语法:char ch = 'a';

注意:在显示字符变量时,用单引号将字符括起来,而不是双引号

注意:单引号内只能有一个字符,不能是字符串

  • C和C++中字符型变量只占用1个字节
  • 字符型变量并不是把字符本身放到内存中存储,而是将字符对应的ASCII编码放入到存储单元
#include <iostream>

using namespace std;

int main() {
char c1 = 'h';
cout << c1 << endl;// 输出:h
cout << sizeof(c1) << endl; // 输出:1

//char c2 = "h";报错,不能使用双引号
//char c3 = 'hello'报错,单引号内不能是为字符串
char c4 = 'a';
cout << (int)c4 << endl;// 97

return 0;
}

ASCII表:

ASCII值 控制字符 ASCII值 字符 ASCII值 字符 ASCII值 字符
0 NUT 32 (space) 64 @ 96 、
1 SOH 33 ! 65 A 97 a
2 STX 34 “ 66 B 98 b
3 ETX 35 # 67 C 99 c
4 EOT 36 $ 68 D 100 d
5 ENQ 37 % 69 E 101 e
6 ACK 38 & 70 F 102 f
7 BEL 39 , 71 G 103 g
8 BS 40 ( 72 H 104 h
9 HT 41 ) 73 I 105 i
10 LF 42 * 74 J 106 j
11 VT 43 + 75 K 107 k
12 FF 44 , 76 L 108 l
13 CR 45 - 77 M 109 m
14 SO 46 . 78 N 110 n
15 SI 47 / 79 O 111 o
16 DLE 48 0 80 P 112 p
17 DCI 49 1 81 Q 113 q
18 DC2 50 2 82 R 114 r
19 DC3 51 3 83 S 115 s
20 DC4 52 4 84 T 116 t
21 NAK 53 5 85 U 117 u
22 SYN 54 6 86 V 118 v
23 TB 55 7 87 W 119 w
24 CAN 56 8 88 X 120 x
25 EM 57 9 89 Y 121 y
26 SUB 58 : 90 Z 122 z
27 ESC 59 ; 91 [ 123 {
28 FS 60 < 92 / 124
29 GS 61 = 93 ] 125 }
30 RS 62 > 94 ^ 126 `
31 US 63 ? 95 _ 127 DEL

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

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

转义字符

作用:用于表示一些不能显示出来的ASCII字符

常用转移字符有:\n \\ \t

转义字符 含义 ASCII码值(十进制)
\a 警报 007
\b 退格(BS) ,将当前位置移到前一列 008
\f 换页(FF),将当前位置移到下页开头 012
\n 换行(LF) ,将当前位置移到下一行开头 010
\r 回车(CR) ,将当前位置移到本行开头 013
\t 水平制表(HT) (跳到下一个TAB位置) 009
\v 垂直制表(VT) 011
\ 代表一个反斜线字符”" 092
' 代表一个单引号(撇号)字符 039
" 代表一个双引号字符 034
? 代表一个问号 063
\0 数字0 000
\ddd 8进制转义字符,d范围0~7 3位8进制
\xhh 16进制转义字符,h范围0~~9,a~~f,A~F 3位16进制
#include <iostream>

using namespace std;

int main() {
cout << "Hello World" << endl;
cout << "\t Hello World" << endl;
cout << "\n Hello World" << endl;
cout << "\\ Hello World" << endl;

return 0;
}

字符串型

作用:用于表示一串字符

两种风格:

  1. C风格字符串:char 变量名[] = "字符串值";
  2. C++风格字符串:string 变量名 = "字符串值";
#include <iostream>

using namespace std;

int main() {
string s1 = "Hello World";
char s2[] = "Hello World";

cout << s1 << endl;
cout << s2 << endl;

cout << sizeof(s1) << endl;// 40
cout << sizeof(s2) << endl;// 12

return 0;
}

注意:字符串一定要用双引号括起来

注意:虽然string和char数组都可以表示字符串,但是所占的内存大小并不一样

类型 string类对象(s1) char[]数组(s2)
内存布局 类实例,含指针、容量、大小等元数据 连续字符序列,结尾可能含\0
sizeof结果 固定元数据大小(与字符串无关) 整个数组的字节数(包含所有元素)

布尔类型

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

布尔类型只有两种值:

  1. true:表示值为真,本质是1
  2. false:表示值为假,本质是0
#include <iostream>

using namespace std;

int main() {
bool flag_1 = true;
bool flag_2 = false;

cout << flag_1 << endl;// 1
cout << flag_2 << endl;// 0
cout << sizeof(flag_1) << endl; // 1

return 0;
}

数据输入

作用:通过键盘输入数据

语法:cin >> 变量

#include <iostream>

using namespace std;

int main() {
int number = 0;

cout << "请输入数据:" << endl;
cin >> number;

cout << "您输入的是数字:" << number << endl;

return 0;
}

数据类型之间的转换

#include <iostream>
#include <string>// 引入string库,用于处理string数据类型
#include <typeinfo> // 引入typeinfo,用于判断数据类型

using namespace std;

int main() {
// 字符串转整数
string s1 = "123";
int n1 = stoi(s1);
n1++;
cout << n1 << endl;// 124

// 整数转字符串
int n2 = 11;
string s2 = to_string(n2) + to_string(n2);
cout << s2 << endl;// 1111

// 浮点数转整数
float f1 = 3.11f;
int n3 = (int)f1;
cout << n3 << endl;// 3向下取整,也称为小数部分截断

// 整数转浮点数
int n4 = 10;
float f2 = (float)n4;
f2 += 0.1;
cout << f2 << endl;// 10.1

// 浮点数转字符串
float f3 = 0.5f;
string s3 = to_string(f3) + to_string(f3);
cout << s3 << endl;// 0.5000000.500000

// 字符串转浮点数
string s4 = "0.345";
float f4 = stof(s4);
f4 += 0.1;
cout << f4 << endl;// 0.445

return 0;
}

运算符

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

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

算数运算符

运算符 术语 示例 结果
+ 正号 +3 3
- 负号 -3 -3
+ 加 10 + 5 15
- 减 10 - 5 5
* 乘 10 * 5 50
/ 除 10 / 5 2
% 取模(取余) 10 % 3 1
++ 前置递增 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=1; b=2;

注意:整数与整数相除,结果一定是整数,如果除不尽则向下取整,如10 / 3 = 3

注意:整数与浮点数进行加减乘除,结果一定是浮点数

注意:小数不能做取模运算

赋值运算符

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

运算符 术语 示例 结果
= 赋值 a=2; b=3; a=2; b=3;
+= 加等于 a=0; a+=2; a=2;
-= 减等于 a=5; a-=3; a=2;
*= 乘等于 a=2; a*=2; a=4;
/= 除等于 a=4; a/=2; a=2;
%= 模等于 a=3; a%2; a=1;

比较运算符

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

运算符 术语 示例 结果
== 相等于 4 == 3 0
!= 不等于 4 != 3 1
< 小于 4 < 3 0
> 大于 4 > 3 1
<= 小于等于 4 <= 3 0
>= 大于等于 4 >= 1 1
#include <iostream>

using namespace std;

int main() {
int num_01 = 10;
int num_02 = 20;

cout << (num_01 < num_02) << endl;// 1
cout << (num_01 > num_02) << endl;// 0
cout << (num_01 == num_02) << endl;// 0
cout << (num_01 <= num_02) << endl;// 1
cout << (num_01 >= num_02) << endl;// 0

return 0;
}

逻辑运算符

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

运算符 术语 示例 结果
! 非 !a 如果a为假,则!a为真; 如果a为真,则!a为假。
&& 与 a && b 如果a和b都为真,则结果为真,否则为假。
或
#include <iostream>

using namespace std;

int main() {
int num_01 = 10;
int num_02 = 20;
int num_03 = 30;

cout << !(num_01 < num_02) << endl;// 0
cout << !(num_01 > num_02) << endl; // 1

cout << (num_01 < num_02 && num_02 < num_03) << endl;// 1
cout << (num_01 < num_02 && num_02 > num_03) << endl;// 0

cout << (num_01 > num_02 || num_02 > num_03) << endl;// 0
cout << (num_01 < num_02 || num_02 < num_03) << endl;// 1

return 0;
}

程序流程结构

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

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

选择结构

if语句

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

if语句的三种形式:

  • 单行格式if语句
  • 多行格式if语句
  • 多条件的if语句
  1. 单行格式if语句:if (条件) {条件满足执行的语句}

clip_image002

#include <iostream>

using namespace std;

int main() {
int num = 0;
cout << "请输入一个数字:" << endl;
cin >> num;

if (num < 10) {
cout << "你输入的数字比10小" << endl;
}

if (num >= 10 && num <= 20) {
cout << "你输入的数字在10 ~ 20之间" << endl;
}

if (num > 20) {
cout << "你输入的数字比20大" << endl;
}

return 0;
}
  1. 多行格式if语句:if (条件) {条件满足执行的语句} else { 条件不满足执行的语句 };

clip_image002-1541662519170

#include <iostream>

using namespace std;

int main() {
int num = 0;
cout << "请输入一个数字:" << endl;
cin >> num;

if (num < 10) {
cout << "你输入的数字比10小" << endl;
}
else {
cout << "你输入的数字比10大" << endl;
}

return 0;
}
  1. 多条件if语句:if (条件1) {条件1满足执行的语句} else if (条件2) {条件2满足执行的语句} ... else {都不满足执行的语句}
#include <iostream>

using namespace std;

int main() {
int num = 0;
cout << "请输入一个数字:" << endl;
cin >> num;
/*
if (num > 0) {
cout << "你输入的数字比0大" << endl;// 只要数字比0大,就只会执行部这一条,后面的条件都会跳过
}
else if (num > 10){
cout << "你输入的数字比10大" << endl;
}
else if (num > 20) {
cout << "你输入的数字比20大" << endl;
}
else {
cout << "你输入的数字很大" << endl;
}
*/

if (num < 10) {
cout << "你输入的数字比10小" << endl;
}
else if (num < 20) {
cout << "你输入的数字比10大比20小" << endl;
}
else if (num < 30) {
cout << "你输入的数字比20大比30小" << endl;
}
else {
cout << "你输入的数字大于等于30" << endl;
}

return 0;
}
  1. if语句嵌套
#include <iostream>
using namespace std;

int main() {
    int age;
    double height;

    cout << "请输入年龄: ";
    cin >> age;
    cout << "请输入身高(cm): ";
    cin >> height;

    // 外层判断年龄
    if (age >= 18) {
        // 内层判断身高
        if (height >= 160.0) {
            cout << "符合条件,允许乘坐过山车!" << endl;
        } else {
            cout << "年龄达标,但身高不足160cm,不可乘坐" << endl;
        }
    } else {
        cout << "年龄未满18岁,禁止乘坐" << endl;
    }

    return 0;
}

三目运算符

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

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

解释:

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

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

#include <iostream>

using namespace std;

int main() {

int a = 10;
int b = 20;
int c = 0;

a < b ? cout << "a小于b" << endl : cout << "a大于b" << endl;

c = a > b ? a : b;// 三目运算符能返回结果,所以可以用于赋值
cout << "c的值为:" << c << endl;

return 0;
}

switch语句

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

语法:

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

示例:

#include <iostream>

using namespace std;

int main() {
int a = 0;

cout << "请输入一个数:" << endl;
cin >> a;

switch (a) {
case 1:
cout << "值为1" << endl;
break;
case 2:
cout << "值为2" << endl;
break;
default:
cout << "值不为1也不为2" << endl;
break;
}

return 0;
}

如果不写break,switch会继续向下寻找符合条件的case并执行语句,这也称为case穿透:

#include <iostream>

using namespace std;

int main() {
int a = 0;

cout << "请输入一个数:" << endl;
cin >> a;

switch (a) {
case 0:;
case 1:;
case 2:;
case 3:;
case 4:
cout << "值在0到4之间";
break;
case 5:;
case 6:;
case 7:;
case 8:;
case 9:
cout << "值在5到9之间";
break;
default:
cout << "值大于等于10";
break;
}

return 0;
}

循环结构

while循环语句

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

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

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

clip_image002-1541668640382

示例:

#include <iostream>

using namespace std;

int main() {
int i = 0;
while (i < 10) {
cout << "我今年" << i << "岁了" << endl;
i++;
}

i = 0;

while (i < 100) {
if (i == 18) {
cout << "我成年啦" << endl;
break;// 跳出循环
}
else {
cout << "我今年" << i << "岁了" << endl;
i++;
}
}

i = 0;

while (i < 100) {
if (i > 30 && i < 50) {
i++;
cout << "我要开始认真工作了" << endl;
continue;// 跳过一次循环
}
cout << "我今年" << i << "岁了" << endl;
i++;
}

return 0;
}

注意:一定要注意避免死循环,如while (1),如果循环体中没有中断循环的代码,程序会一直运行直到内存资源消耗殆尽

do…while循环语句

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

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

解释:在循环前先执行一次操作再判断循环条件

#include <iostream>

using namespace std;

int main() {
int password;
do {
cout << "请输入密码(必须>0):";
cin >> password;
} while (password <= 0);  // 强制用户至少输入一次

return 0;
}

练习案例——水仙花数

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

例如:1^3 + 5^3 + 3^3 = 153

利用do…while求出三位数中所有的水仙花数

#include <iostream>

using namespace std;

int main() {
int num = 100;

do {
int ge = num % 100 % 10;
int shi = num / 10 % 10;
int bai = num / 100;

if (pow(ge, 3) + pow(shi, 3) + pow(bai, 3) == num) {
cout << num << "是水仙花数" << endl;
num++;
continue;
}

num++;

} while (num < 1000);

return 0;
}

for循环语句

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

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

int main() {
for (int i = 0;i < 10; i++) {
cout << i << endl;
}

return 0;
}

嵌套循环

作用:在循环体中再嵌套一层循环

示例:

#include <iostream>

using namespace std;

int main() {

for (int i = 1; i < 10; i++)
{
for (int j = 1; j <= i; j++) {
cout << j << "x" << i << "=" << i * j << " ";

}

        /*
        // 下面这种写法更繁琐,消耗资源更多,但是好理解
        for (int j = 1; j < 10; j++) {
        if (j > i) {continue;}
cout << j << "x" << i << "=" << i * j << " ";
}
        */
cout << " " << endl;
}

return 0;
}

goto语句

作用:可以无条件跳转到语句

语法:goto 标记;

解释:如果标记的名称存在

#include <iostream>

using namespace std;

int main() {

cout << "1" << endl;
goto Flag;
cout << "2" << endl;
cout << "3" << endl;
cout << "4" << endl;
Flag:
cout << "5" << endl;
cout << "6" << endl;
cout << "7" << endl;
cout << "8" << endl;

return 0;
}

注意:由于goto代码会打乱代码的执行顺序,导致代码可读性变差,所以尽量避免使用

数组

数组就是一个集合,里面存放了相同类型的数据元素

特点1:数组中的每个数据元素都是相同的数据类型

特点2:数组是由连续的内存位置组成的

静态初始化

方式1(静态显式初始化):

语法:数据类型 数组名[数组长度] = {值1,值2,...,不能超过数组最大长度} ;

int arr_01[5] = {1,2,3,4,5};// 完全显式初始化
int arr_02[5] = {1,2,3};// 部分显式初始化,没有声明具体值的部分记为0
int arr_03[5] = {1,2,3,4,5,6};// 报错!超过数组最大长度
int arr_04[5]{1,2,3}// C++11统一初始化,没有声明具体值的部分记为0

方式2(零初始化):

当前不考虑局部作用域

语法:数据类型 数组名[数组长度];

int arr_01[5];
int arr[5]{};         // C++11统一初始化(推荐)
arr_01[0] = 1;
arr_01[1] = 2;
arr_01[2] = 3;
arr_01[3] = 4;
arr_01[4] = 5;
arr_01[5] = 6;// 报错!超过数组最大长度

方式3(推导式静态显式初始化):

语法:数据类型 数组名[] = {1,2,3,4,...,没有长度限制}

int arr_01[] = {1,2,3,4,5};
int arr_02[] = {1,2};
int arr_03[] = {1,2,3,4,5,6,7,8,9,10,11,...}

获取数组长度

C++17以前没有Python中len(数组名)或Java中数组名.length()来快速获取数组长度,需要进行单独的计算

计算公式:sizeof(数组名) / sizeof(数组数据类型)

解释:sizeof(数组名)表示数组中所有元素在内存中所占的大小,sizeof(数组数据类型)表示数组的数据类型所占内存空间大小

例如:

int arr[] = {1,2,3,4,5,6,7,8,9};

int len_01 = sizeof(arr) / sizeof(int);
// 或者
int len_02 = sizeof(arr) / sizeof(arr[0]);// 用于当不能确定数组的具体数据类型时(推荐)

C++17之后可以使用size()快速获取数组长度:

#include <iostream>
using namespace std;

int main() {

int arr[]{ 5,2,3,6,9,7,8,1,4 };
cout << size(arr) << endl;

return 0;
}

冒泡排序

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

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

using namespace std;

void coutArr(int arr[],int length) {
for (int i = 0; i < length; i++)
{
cout << arr[i];
}
}

int main() {

int arr[]{ 5,2,3,6,9,7,8,1,4 };

int length = sizeof(arr) / sizeof(arr[0]);

for (int i = 0; i < length - 1; i++)
{
for (int j = 0; j < length - 1 - i; j++) {// 这里-1-i的原因是假设第一轮比完后最后一位一定是最大的,可以跳过检测
if (arr[j] > arr[j + 1]) {// 改变符号就等于改变排序
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}

coutArr(arr, length);

return 0;
}

二维数组

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

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

推荐使用第二种方式,更加直观,提升代码可读性

示例:

#include <iostream>

using namespace std;

int main() {
int arr[2][3] = {
{1,2,3},
{4,5,6}
};

int row = sizeof(arr) / sizeof(arr[0]);
int col = sizeof(arr[0]) / sizeof(arr[0][0]);
cout << "col列:" << col << endl;
cout << "row行:" << row << endl;

for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++) {
cout << "第" << i + 1 << "行" << "第" << j + 1<< "列的数字是" << arr[i][j] << endl;
}
}

return 0;
}

案例

将下表内容输出的控制台中:

语文 数学 英语
张三 100 100 100
李四 90 50 100
王五 60 70 80

答案:

#include <iostream>

using namespace std;

int main() {
// 输出成绩
int score[3][3] = {
{100,100,100},
{90,50,100},
{60,70,80}
};

string name[] = {"张三","李四","王五"};

int row = sizeof(score) / sizeof(score[0]);
int col = sizeof(score[0]) / sizeof(score[0][0]);

cout << "    语文  数学  英语" << endl;

for (int i = 0; i < row; i++)
{
cout << name[i] << "  ";
for (int j = 0; j < col; j++) {

cout << score[i][j] << "  ";
}
cout << endl;
}

return 0;
}

函数

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

函数的定义

  1. 返回值类型
  2. 函数名
  3. 参数列表
  4. 函数体语句
  5. return 表达式

语法:

返回值类型 函数名 (参数列表)
{
函数体语句;
return 表达式;
}

基本使用案例:

#include <iostream>

using namespace std;

void saySomeThing(string strs) {
cout << strs << endl;
};

int sum(int num1, int num2) {
return num1 + num2;
}

int main() {

saySomeThing("Hello World");
saySomeThing("你好!!");
//saySomeThing(12345); 报错,实参数据类型与形参不匹配

int count = sum(1, 2);// 有返回值可以用变量接收
cout << sum(5, 6) << endl;// 也可以直接打印

return 0;
}

注意:函数必须在main之前声明,否则运行时会检测不到函数而引起报错

int main() {
func();// 报错
}

void func() {...};// 后声明

但是以下写法是可以的:

void func();// 先声明

int main() {
func();// 正确运行
}

void func() {
cout << "Hello World" << endl;// 再实现
}

函数的调用

以上代码已经包含了函数的调用,简单来说,调用一个函数只需要函数名(函数参数)即可

如:sum(1,2)、sayHello()、checkMission()

函数的值传递

函数定义时,括号里的参数表示形参,函数调用时,括号里的参数表示实参

值的传递流程就是:调用函数 => 修改/添加实参 => 对应位置上的形参被替换为实参 => 执行函数体内容

所以,只要实参和形参的类型相同,形参名是什么都无所谓,只要每个形参之间不重名即可

函数的常见形式

常见的函数样式有4种:

  1. 无参无返
  2. 有参无返
  3. 无参有返
  4. 有参有反
#include <iostream>

using namespace std;

// 无参无返
void test_01() { cout << "无参无返" << endl; }

// 有参无返
void test_02(int nums[]) {
for (int i = 0; i < sizeof(nums) / sizeof(nums[0]); i++)
{
cout << nums[i] << "  ";
}
}
// 无参有返
bool test_03() { return true; }
// 有参有返
string test_04(string s1,string s2,string s3) {
return s1 + s2 + s3;
}

int main() {

cout << "无参无返调用结果:";
test_01();

cout << "有参无返调用结果:";
int arr[]{ 1,2,3,4,5 };
test_02(arr);
cout << endl;

cout << "无参有返调用结果:";
bool b1 = test_03();
cout << b1 << endl;

cout << "有参有返调用结果:";
string s1 = test_04("你好", "世界", "Hello World");
cout << s1 << endl;

return 0;
}

函数的声明

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

  • 函数的声明可以多次,但是函数的定义只能一次
// 声明可以多次,定义只能一次
int max(int a,int b);
int max(int a,int b);

// 定义
int max(int a,int b)
{
return a > b ? a : b;
}

int main() {
cout << max(1,2) << endl;
}

函数的重载

虽然正常情况下函数定义只能定义一次,但实际上只要形参数量不重复就可以多次定义,当实参数对应到了函数的形参数就调用哪个函数

int max(int a,int b) {// 这个函数暂时可以叫做函数一
return a > b ? a : b;
}

int max(int a,int b,int c) {// 这个函数暂时叫做函数二
return max(max(a,b),c);
}

int main() {
max(1,2);// 这里调用的是函数一
max(1,2,3);// 这里调用的是函数二
}

函数的分文件编写

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

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

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

示例:

// swap.h文件
#include<iostream>
using namespace std;

// 实现两个数字交换的函数声明
void swap(int a, int b);
// swap.cpp文件
#include "swap.h"

void swap(int a, int b)
{
int temp = a;
a = b;
b = temp;

cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
// main函数文件
#include "swap.h"
int main() {

int a = 100;
int b = 200;
swap(a, b);

system("pause");

return 0;
}

指针

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

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

指针变量的定义和使用

指针变量定义语法:数据类型 * 变量名

#include <iostream>

using namespace std;

int main() {
// 1. 定义指针
int a = 10;

// 指针定义的语法:数据类型 * 指针变量名
int* p;
// 让指针记录变量a的地址
p = &a;// & 表示取址符号
cout << "a的内存地址为:" << &a << endl;// 控制台输出:000000C7B31CF894
cout << "指针p的值为:" << p << endl;// 控制台输出:000000C7B31CF894
// // *指针名 表示解引用
cout << "指针p指向内存地址的具体值为:" << *p << endl; // 控制台输出:10

// 通过 *p 修改a的值
*p = 255;
cout << "*p修改a的值后,a当前的值为:" << a << endl;// 控制台输出:255

return 0;
}
  1. &表示取值符号
  2. *指针名 = 值表示对指针所指的变量的值进行修改
int a = 10;// 将整数值10存入变量a的内存空间,此时a对应的内存地址中存储的值为10
int* p = &a;// &a获取变量a的内存地址,并将其赋值给指针变量p。此时p保存的是a的内存地址
*p = 255;// 通过解引用操作符*访问p指向的内存地址(即a的地址),修改该地址存储的值为20。此时a的值变为20。

指针所占内存空间

#include <iostream>

using namespace std;

int main() {
int a = 10;
int* p = &a;

cout << sizeof(p) << endl;// 8
cout << sizeof(char*) << endl;// 8
cout << sizeof(float*) << endl;// 8
cout << sizeof(double*) << endl;// 8

return 0;
}
系统架构 地址总线宽度 指针大小 寻址空间
32位 32位 4字节 4GB(2^32)
64位 64位 8字节 16EB(2^64)
  • 64位系统:指针统一占用 8字节(无论指向何种数据类型)。
  • 32位系统:指针统一占用 4字节。
  • 原理:指针存储的是内存地址,其大小由 系统寻址能力 决定(64位系统地址总线为64位,需8字节存储)

空指针和野指针

空指针:指针变量指向内存中编号为0的空间

用途:初始化指针变量

注意:空指针指向的内存是不可以访问的

示例:

#include <iostream>

using namespace std;

int main() {
int* p= NULL;
cout << p << endl;// 报错
cout << *p << endl;// 报错

return 0;
}

野指针:指针变量指向非法的内存空间

示例:

#include <iostream>

using namespace std;

int main() {
int* p = (int *)0x1100;
cout << *p << endl;// 报错

return 0;
}

const修饰指针

const修饰指针有三种情况:

  1. const修饰指针 - 称为:常量指针 - 语法:const int * p = a; - 特点:指针的指向可以修改,但是指针指向的值不可以该。如p = &b是可以的,但是*p = 20是错误的
  2. const修饰常量 - 称为:指针常量 - 语法:int * const p = a; - 特点:与常量指针正好相反。p = &b是错误的,*p = 20是可以的
  3. const即修饰指针,又修饰常量 - 无特定名称 - 语法:const int * const p = a; - 特点:指针的指向、指针指向的值都不可以修改。*p = 20、p = &b都是错误的

记忆技巧:

  1. const在*之前,表示对*进行了限制,当操作*时就是错误的,如*p = 20
  2. const在*之后,表示对指针变量进行了限制,当操作指针变量时就是错误的,如p = &b
类型 术语 特性总结
const int *p 指向常量的指针 值不可改,地址可改
int *const p 指针常量 地址不可改,值可改
const int *const p 指向常量的指针常量 值和地址均不可改

示例:

#include <iostream>

using namespace std;

int main() {
int a = 10;
int b = 20;

const int* p1 = &a;
*p1 = 20;// 编译器直接报错,提示表达式必须是可以修改的左值
p1 = &b;

int* const p2 = &a;
*p2 = 20;
p2 = &b;// 编译器直接报错,提示表达式必须是可以修改的左值

const int* const p3 = &a;
*p3 = 20;// 编译器直接报错,提示表达式必须是可以修改的左值
p3 = &b;// 编译器直接报错,提示表达式必须是可以修改的左值

return 0;
}

指针和数组

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

示例:

#include <iostream>

using namespace std;

int main() {
int arr[]{ 1,2,3,4,5,6,7,8,9,10 };
int* p = arr;// arr存储的就是地址,不用取址符号

for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
cout << "数组中索引为" << i << "的值是:" << *p << endl;// 打印的是具体的值
cout << "数组中索引为" << i << "的值的地址是:" << p << endl;
p++;// p++等价于 p = p + sizeof(int)
}

return 0;
}

关于p++的详细说明:

机制 说明
类型依赖步长 指针加减运算根据指向类型自动调整步长(int→4字节,double→8字节)
编译器隐式转换 p+1实际执行 p + 1*sizeof(int)

指针和函数

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

示例:

#include <iostream>

using namespace std;

// 值传递函数
void swap_01(int a, int b) {
int tmp = a;
a = b;
b = tmp;
}

// 地址传递函数
void swap_02(int* p1, int* p2) {
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}

// 无效的指针交换(错误原因:交换指针副本)
void swap_03(int* p1, int* p2) {
int* tmp = p1;
p1 = p2;
p2 = tmp;
}

int main() {
int a = 10;
int b = 20;

// 调用值传递函数,a和b的值并不会发生改变
swap_01(a, b);
cout << "a的值为:" << a << endl;// 10
cout << "b的值为:" << b << endl;// 20

// 调用地址传递函数,a和b的值是会发生改变的
swap_02(&a, &b);
cout << "a的值为:" << a << endl;// 20
cout << "b的值为:" << b << endl;// 10

swap_03(&a, &b);
cout << "a的值为:" << a << endl;// 20
cout << "b的值为:" << b << endl;// 10

return 0;
}

指针、函数、数组

案例:利用冒泡排序,编写一个函数对数组进行从小到大的排序

示例:

#include <iostream>

using namespace std;

void coutArr(int arr[],int length) {
for (int i = 0; i < length; i++)
{
cout << arr[i];
}
}

void BubbleSort(int arr[], int length) {
for (int i = 0; i < length - 1; i++)
{
for (int j = 0; j < length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}

int main() {

int arr[]{ 5,2,3,6,9,7,8,1,4 };

int length = sizeof(arr) / sizeof(arr[0]);

BubbleSort(arr, length);

coutArr(arr, length);

return 0;
}

结构体

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

结构体定义和使用

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

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

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

示例:

#include <iostream>

using namespace std;

// 1. 创建学生数据类型:学生包括(姓名、年龄、分数)
struct Student
{
// 成员列表
string name;
int age;
int score;
string gender;
};

/*
// 创建具体的学生(方式3)不推荐,了解即可
struct Student
{
// 成员列表
string name;
int age;
int score;
string gender;
} s3;
*/

int main() {
// 创建具体的学生(方式1)
struct Student s1 = { "zhangsan",5,200,"男" };// 按照顺序赋值

cout << "学生叫做:" << s1.name << ";学生年龄为:" << s1.age << ";学生的成绩为:" << s1.score << ";学生的性别是:" << s1.gender << endl;

// 创建具体的学生(方式2)
struct Student s2;
s2.name = "李四";
s2.age = 8;
s2.gender = "男";
s2.score = 180;
cout << "学生叫做:" << s2.name << ";学生年龄为:" << s2.age << ";学生的成绩为:" << s2.score << ";学生的性别是:" << s2.gender << endl;

return 0;
}

注意1:当定义结构体时,struct关键字是不可以被省略的

注意2:创建结构体变量时,如struct Student s1可以省略struct=>Student s1

访问结构体变量的成员时,可以用操作符"."访问成员

结构体数组

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

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

示例:

#include <iostream>
#include <string>

using namespace std;

// 1. 创建学生数据类型:学生包括(姓名、年龄、分数)
struct Student
{
// 成员列表
string name;
int age;
int score;
string gender;
};

int main() {
Student stuArry[] = {
{"张三",18,172,"男"},
{"李四",18,178,"女"},
{"王五",17,180,"女"},
{"赵六",17,180,"男"},
};

cout << sizeof(stuArry) / sizeof(stuArry[0]) << endl;// 4
cout << size(stuArry) << endl;// 4

for (int i = 0; i < size(stuArry); i++)
{
stuArry[i].name = stuArry[i].name + to_string(i);
cout << "姓名:" << stuArry[i].name << " ";
cout << "年龄:" << stuArry[i].age << " ";
cout << "分数:" << stuArry[i].score << " ";
cout << "性别:" << stuArry[i].gender << " " << endl;
}

return 0;
}

结构体指针

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

  • 利用操作符->可以通过结构体指针访问结构体数学

示例:

#include <iostream>

using namespace std;

struct Subject {
string name;
string level;
int point;
bool isOpened;
};

int main() {
Subject s1 = { "英语","高",5,true };

// 通过指针指向结构体变量
Subject* p = &s1;

// 通过指针访问结构体变量中的数据
cout << p->name << endl;

return 0;
}

结构体嵌套结构体

当结构体内存在另一个结构体,就称之为结构体嵌套结构体

示例:

#include <iostream>

using namespace std;

struct Teacher
{
string name;
int age;
string gender;
};

struct Student
{
string name;
int age;

// 在结构体内直接声明
struct Subject {
string name;
string level;
int point;
bool isOpened;
} subject;

// 先在结构体外声明,最后在结构体中使用
struct Teacher teacher;
};

int main() {
Student s1;
s1.age = 18;
s1.name = "张三";
s1.subject.level = "中等";
s1.subject.name = "体育";
s1.subject.point = 3;
s1.subject.isOpened = false;

s1.teacher = { "老王",42,"男" };

cout << s1.name << "今年" << s1.age << "岁了," 
<< "他/她的班主任是" << s1.teacher.name << ",他/她是一名" << (s1.teacher.age > 35 ? "有经验的" : "年轻的") <<  s1.teacher.gender << "老师。" 
<< s1.name << "同学喜欢" << s1.subject.name << "这门课,难度属于" << s1.subject.level << "水平,可以获得" << s1.subject.point << "点学分,这门课现在" << (s1.subject.isOpened ? "已经停止开放了" : "已经开放了") << endl;

// 张三今年18岁了,他/她的班主任是老王,他/她是一名有经验的男老师。张三同学喜欢体育这门课,难度属于中等水平,可以获得3点学分,这门课现在已经开放了

return 0;
}

结构体做函数参数

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

传递方式有两种:

  1. 值传递
  2. 地址传递

示例:

#include <iostream>
#include <string>// 引入string库,用于处理string数据类型
#include <typeinfo> // 引入typeinfo,用于判断数据类型

using namespace std;

struct Student
{
int id;
string name;
int age;
string province;
};

// 类型自动匹配函数
void coutStudent(Student s) {
cout << "姓名:" << s.name << "   ";
cout << "年龄:" << s.age << "   ";
cout << "学号:" << s.id << "   ";
cout << "所在省份:" << s.province << endl;

s.name += "值传递";
s.age += 100;
s.id += 100000;
s.province += "值传递";
}

// 类型自动匹配函数
void coutStudent(Student* s) {
cout << "姓名:" << s -> name << "   ";
cout << "年龄:" << s -> age << "   ";
cout << "学号:" << s -> id << "   ";
cout << "所在省份:" << s -> province << endl;

s->name = (s->name) + "地址传递";
s->age = (s->age) + 100;
s->id = (s->id) + 100000;
s->province = (s->province) + "地址传递";
}

int main() {
Student s1 = { 10001,"张三",14,"江苏" };

// 值传递
cout << endl;
coutStudent(s1);
cout << endl;
cout << "值传递函数执行后的结果为:";
cout << "姓名:" << s1.name << "   ";
cout << "年龄:" << s1.age << "   ";
cout << "学号:" << s1.id << "   ";
cout << "所在省份:" << s1.province << endl;

// 地址传递
Student* p1 = &s1;
cout << endl;
coutStudent(p1);
cout << endl;
cout << "值传递函数执行后的结果为:";
cout << "姓名:" << s1.name << "   ";
cout << "年龄:" << s1.age << "   ";
cout << "学号:" << s1.id << "   ";
cout << "所在省份:" << s1.province << endl;

return 0;
}

结构体中const使用场景

作用:用const来防止误操作

示例:

#include <iostream>
#include <string>// 引入string库,用于处理string数据类型
#include <typeinfo> // 引入typeinfo,用于判断数据类型

using namespace std;

struct Student
{
int id;
string name;
int age;
string province;
};

// 类型自动匹配函数
void coutStudent(const Student* s) {

//s->age = 1000;// 报错

cout << "姓名:" << s -> name << "   ";
cout << "年龄:" << s -> age << "   ";
cout << "学号:" << s -> id << "   ";
cout << "所在省份:" << s -> province << endl;
}

int main() {
Student s1 = { 10001,"张三",14,"江苏" };

// 地址传递
Student* p1 = &s1;
coutStudent(p1);
cout << "值传递函数执行后的结果为:";
cout << "年龄:" << s1.age << "   ";

return 0;
}

结构体案例练习

案例1:

共有两个结构体,分别是学生和老师,老师结构体中有姓名和学生数组(结构体嵌套,一共三个老师,每个老师共5名学生);

学生结构体中有姓名和分数;利用函数将老师和对应的学生进行赋值;最后将所有结构体打印出来:

#include <iostream>
#include <string>// 引入string库,用于处理string数据类型
#include <typeinfo> // 引入typeinfo,用于判断数据类型

using namespace std;

// 学生结构体
struct Student
{
string name;
int score;
};

// 老师结构体
struct Teacher
{
string name;
Student student[5];
};

// 对老师进行赋值的函数
void createTeacher(Teacher* t,string tname,Student s[]) {
t->name = tname;
for (int i = 0; i < size(t->student); i++)
{
t->student[i] = s[i];
}
}

// 对学生进行赋值的函数
void createStudent(Student* s,string name,int score) {
s->name = name;
s->score = score;
}

int main() {
Teacher t[3];
// 第一层循环表示的是对老师的赋值
for (int i = 0; i < size(t); i++)
{
string name;
cout << "请输入第" << i + 1 << "个老师的姓名:";
cin >> name;
cout << endl;
Student s[5];
// 第二层循环表示对学生数组进行赋值
for (int j = 0; j < size(s); j++)
{
string stuName;
int score;
cout << "请输入该老师带领的第" << j + 1 << "个学生的信息:" << endl;
cout << "学生姓名:";
cin >> stuName;
cout << endl;
cout << "学生分数:";
cin >> score;
Student* p = &s[j];
createStudent(p, stuName, score);
}
// 学生结构体数组创建完成后,进行老师结构体赋值
Teacher* p = &t[i];
createTeacher(p, name, s);
}

// 打印数据
for (int i = 0; i < size(t); i++)
{
cout << "第" << i+1 <<"名老师是:" << t[i].name << "老师" << endl;

for (int j = 0; j < size(t[i].student); j++)
{
cout << "他的第" << j + 1 << "名学生叫:" << t[i].student[j].name << ",他得分是:" << t[i].student[j].score << endl;
}
}

return 0;
}

案例2:

设计一个人物的结构体,结构体成员有:姓名、年龄、性别;创建结构体数组,数组中存放5名人物

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

五名人物的信息如下:

{"刘备",23,"男"},
{"关羽",22,"男"},
{"张飞",20,"男"},
{"赵云",21,"男"},
{"貂蝉",19,"女"}

示例:

#include <iostream>
#include <string>// 引入string库,用于处理string数据类型
#include <typeinfo> // 引入typeinfo,用于判断数据类型

using namespace std;

struct Person {
string name;
int age;
string gender;
};

int main() {
Person p[] = {
{"刘备",23,"男"},
{"关羽",22,"男"},
{"张飞",20,"男"},
{"赵云",21,"男"},
{"貂蝉",19,"女"}
};

    // 冒泡排序算法
for (int i = 0; i < size(p) - 1; i++)
{
for (int j = 0; j < size(p) - 1 - i; j++)
{
if (p[j].age > p[j + 1].age) {
Person tmp = p[j];
p[j] = p[j + 1];
p[j + 1] = tmp;
}
}
}

    // 打印结果
for (int i = 0; i < size(p); i++)
{
cout << "第" << i + 1 << "位人物是:" << p[i].name << ",年龄是:" << p[i].age << ",性别是:" << p[i].gender << endl;
}

return 0;
}
CPP
自学系列 编程语言 CPP基础
许可协议:  CC BY 4.0
分享

相关文章

6月 28, 2025

CPP错误案例

数组倒序 将一组数组倒序排序,如{1,2,3,4,5}=>{5,4,3,2,1} 错误写法: #include <iostream> using namespace std; int main() { // 数组倒序 int arr_02[] = { 1,2,3,4,5 }; length =

6月 28, 2025

CPP基础案例

通讯录管理系统 系统需求 通讯录是一个可以记录亲人、好友信息的工具 本案例主要利用C++来实现基础的通讯录管理系统 系统中需要实现的主要功能如下: 添加联系人:向通讯录中添加新人,信息包括姓名、性别、年龄、联系电话、家庭住址,最多记录1000人 显示联系人:显示通讯录中所有联系人信息 删除联系人:按

6月 28, 2025

CPP文件操作

C++文件操作 关键字:ifstream、ofstream、ios:: 程序运行时产生的数据都属于临时数据,程序一旦运行结束都会被释放 通过文件可以将数据持久化 C++中对文件操作需要包含头文件 文件类型分为两种: 文本文件 - 文件以文本的ASCII码形式存储在计算机中 二进制文件 - 文件以文本

下一篇

CPP核心内容

上一篇

vscode_CPP环境搭建

最近更新

  • Hello Halo
  • 状态机
  • 数据表设计规范
  • 缓存优化
  • 事务失效

热门标签

Halo 异常处理 Redisson 并行 Vue 并发 递归 请求限流 SpringAMQP 类加载器

目录

©2026 Norlcayn的博客. 保留部分权利。

使用 Halo 主题 Chirpy