第一部分 C++语法基础

语言基础简介

本章将会介绍编程相关的知识,包括 C++ 从入门教程.

程序是算法与数据结构的载体,是解决 OI 问题的工具.

在 OI 中,最常用的编程语言是 C++.

学习编程是学习 OI 最基础的部分.

第一章 输入输出

C++ 是 C 的一个超集,事实上,任何合法的 C 程序都是合法的 C++ 程序(入门阶段可以这么认为)。

1.1 基本概念

C++ 是一种静态类型的、编译式的、通用的、大小写敏感的、通用的编程语言,支持过程化编程、面向对象编程和泛型编程。

C++ 被认为是一种中级语言,它综合了高级语言和低级语言的特点。

C++ 是由 Bjarne Stroustrup 于 1979 年在新泽西州美利山贝尔实验室开始设计开发的。C++ 进一步扩充和完善了 C 语言,最初命名为带类的C,后来在 1983 年更名为 C++。

C++ 是 C 的一个超集,事实上,任何合法的 C 程序都是合法的 C++ 程序。

注意:使用静态类型的编程语言是在编译时执行类型检查,而不是在运行时执行类型检查。

1.1.1 面向对象程序设计

C++ 完全支持面向对象的程序设计,包括面向对象开发的四大特性:

  • 抽象 (如果是三大特性就没有 抽象)

  • 封装

  • 继承

  • 多态

减少代码量/提高复用性

1.1.2 标准库

标准的 C++ 由三个重要部分组成:

  • 核心语言,提供了所有构件块,包括变量、数据类型和常量,等等。
  • C++ 标准库,提供了大量的函数,用于操作文件、字符串等。
  • 标准模板库(STL),提供了大量的方法,用于操作数据结构等。
1.1.3 ANSI 标准以及ISO C++

ANSI 标准是为了确保 C++ 的便携性 —— 您所编写的代码在 Mac、UNIX、Windows、Alpha 计算机上都能通过编译。

由于 ANSI 标准已稳定使用了很长的时间,所有主要的 C++ 编译器的制造商都支持 ANSI 标准。

现在 C++ 标准由 ISO 维护(如 C++11、C++14、C++17、C++20 等),ANSI 标准已过时。

1.1.4 学习 C++

学习 C++,关键是要理解概念,而不应过于深究语言的技术细节。

学习程序设计语言的目的是为了成为一个更好的程序员,也就是说,是为了能更有效率地设计和实现新系统,以及维护旧系统。

C++ 支持多种编程风格。您可以使用 Fortran、C、Smalltalk 等任意一种语言的编程风格来编写代码。每种风格都能有效地保证运行时间效率和空间效率。

1.1.5 C++ 的使用

基本上每个应用程序领域的程序员都有使用 C++。

C++ 通常用于编写设备驱动程序和其他要求实时性的直接操作硬件的软件。

C++ 广泛用于教学和研究。

任何一个使用苹果电脑或 Windows PC 机的用户都在间接地使用 C++,因为这些系统的主要用户接口是使用 C++ 编写的。

1.2 C++程序框架

#include<iostream>
using namespace std;

int main()
{

return 0;
}

1.2.1 程序框架意义

1、 # – 预处理指令

2、 include – 包含、包括

3、 <> – 放头文件

4、 iostream 头文件

i – in – 输入

o – out – 输出

stream – 流

5、

using – use – 使用

namespace – 命名空间

std – standar – 标准

; – 结束(相当于句号)

6、 int main() – 主函数 – 程序的入口 – 开始

int – 返回类型

main – 函数名 – 主要的

() – 放传入参数

{} – 代码主题

7、 return 0; – 返回一个0 代表程序正常结束

主函数main和return返还值0为没有错误,非0的一般由系统定义,通常指出系统错误。

1.2.2 程序框架意义2

接下来我们讲解一下上面这段程序:

  • C++ 语言定义了一些头文件,这些头文件包含了程序中必需的或有用的信息。上面这段程序中,包含了头文件 ****。
  • using namespace std; 告诉编译器使用 std 命名空间。命名空间是 C++ 中一个相对新的概念。
  • 下一行 main() 是程序开始执行的地方
  • 下一行 int main() 是主函数,程序从这里开始执行。
  • 下一行 cout << “Hello World”; 会在屏幕上显示消息 “Hello World”。
  • 下一行 return 0; 终止 main( )函数,并向调用进程返回值 0。

1.3 初识C++的输入输出

1.3.1 C++输入输出库

c++语言并未定义任何输入输出(IO)语句,取而代之,包含了一个全面的标准库来提供IO机制(以及很多其他设施),本章只了解一部分基本概念和操作。

1.3.2 C++输入

  1. cin为istream类型的对象,这个对象也被称为==标准输入==。
  2. cout为ostream类型的对象,这个对象也被称为==标准输出==。

系统通常会将程序运行的窗口与这些对象联系起来。因此,当我们通过cin,数据将从程序正在运行的窗口读入,当我们像cout写入数据时,将会写到同一个窗口。

cin — 我们可以认为是 c++ 的 in (输入)

cout 就是 c++ 的 out (输出)

1.3.3 C++输出

想要使用输入出输出(iostream)库必须要添加一个头文件(header)#include指令必须出现在所有函数之外。一般将一个程序的所有#include指令都放在完文件的开始。

1.3.4 输出hello world

#include<iostream>
using namespace std;

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

return 0;
}

其中main的函数体中只有一条语句cout。

cout << "Hello World!" << endl;

这条语句使用了输出运算符(<<)在标准输出上打印消息。

<< 运算符接受两个运算对象:

  • 左侧:运算对象必须是一个ostream对象。

  • 右侧:运算对象为要打印的值。

此运算符将给定的值写到给定的ostream(左侧)对象中,输出运算符的计算结果就是其左侧运算对象(ostream)。

cout << "Hello World!" << endl;

第一个输出运算符是打印一条消息,这个消息是一个字符串字面值常量

字符串字面值常量:是一对用双引号包围的字符序列,在双引号之间的文本被打印到标准输出。

第二个输出运算符打印endl,这是一个被称为操纵符的特殊值。

end –结束

l – line – 行、线

操纵符:是为了结束当前行(相当于换行),并将与设备关联的缓冲区中的内容冲刷到设备中。

1.3.5 使用标准库中的名字

using namespace std;

这句话指出cout和endl等是定义在名为std的命名空间

命名空间: 可以帮助我们避免不经意的名字定义冲突,以及使用库中相同名字导致的冲突。标准库定义的所有名字都在命名空间std中。

通过标准空间使用标准库有一个副作用,当使用标准库中的一个名字时,必须显式说明我们想使用来自命名空间std中的名字。

std::cout << "Hello World!" << endl;

通过(::)作用域运算符来指出我们想使用的定义在命名空间std中的名字cout

而使用

using namespace std;

写在开头可以省略std::

1.4 注释

1.4.1 注释简介

注释是用于解释代码段的意思便于读者理解,但是编译器会忽视。

1.4.2 C++注释种类

c++中注释有两种:单行注释多行注释

  1. 单行注释

    以双斜线(//)开始,以换行符结束。

    也就是说当前行双斜线右侧的所有内容都会被编译器忽略。

    这种注释可以包括任何文本。

    常用于半行和单行注释

  2. 多行注释

    这种注释继承于C语言的两个定界符(/* 和 */)。这种注释以 /* 开始,以 */ 结束,可以包含除了 */ 之外的所有内容(包括换行符)。编译器会将(/* 和 */)中的所有内容忽略。

​ 常用于多行注释,注释时不能嵌套。

#include<iostream>

// 这是单行注释

/*
*
* 简单主函数
* 常用*号分行
*
*/

1.5 题目

hello world

https://www.luogu.com.cn/problem/B2002

字符菱形

https://www.luogu.com.cn/problem/B2025

超级玛丽

https://www.luogu.com.cn/problem/P1000

第二章 变量和输入

2.1 基本数据类型

2.1.1 C++ 数据类型

使用编程语言进行编程时,需要用到各种变量来存储各种信息。变量保留的是它所存储的值的内存位置。这意味着,当您创建一个变量时,就会在内存中保留一些空间。

您可能需要存储各种数据类型(比如字符型、宽字符型、整型、浮点型、双浮点型、布尔型等)的信息,操作系统会根据变量的数据类型,来分配内存和决定在保留内存中存储什么。

2.1.2 基本的内置类型

C++ 为程序员提供了种类丰富的内置数据类型和用户自定义的数据类型。下表列出了七种基本的 C++ 数据类型:

类型 关键字
布尔型 bool
字符型 char
整型 int
浮点型 float
双浮点型 double
无类型 void
宽字符型 wchar_t

其实 wchar_t 是这样来的:

typedef short int wchar_t;

所以 wchar_t 实际上的空间是和 short int 一样(取决于计算机)。

一些基本类型可以使用一个或多个类型修饰符进行修饰:

  • signed
  • unsigned
  • short
  • long

下表显示了各种变量类型在内存中存储值时需要占用的内存,以及该类型的变量所能存储的最大值和最小值。

注意:不同系统会有所差异,一字节为 8 位。

注意:默认情况下,int、short、long都是带符号的,即 signed。

注意:long int 8 个字节,int 都是 4 个字节,早期的 C 编译器定义了 long int 占用 4 个字节,int 占用 2 个字节,新版的 C/C++ 标准兼容了早期的这一设定。

类型 范围
char 1 个字节 -128 到 127 或者 0 到 255
unsigned char 1 个字节 0 到 255
signed char 1 个字节 -128 到 127
int 4 个字节 -2147483648 到 2147483647
unsigned int 4 个字节 0 到 4294967295
signed int 4 个字节 -2147483648 到 2147483647
short int 2 个字节 -32768 到 32767
unsigned short int 2 个字节 0 到 65,535
signed short int 2 个字节 -32768 到 32767
long int 8 个字节 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
signed long int 8 个字节 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
unsigned long int 8 个字节 0 到 18,446,744,073,709,551,615
float 4 个字节 精度型占4个字节(32位)内存空间,+/- 3.4e +/- 38 (~7 个数字)
double 8 个字节 双精度型占8 个字节(64位)内存空间,+/- 1.7e +/- 308 (~15 个数字)
long double 16 个字节 长双精度型 16 个字节(128位)内存空间,可提供18-19位有效数字。
wchar_t 2 或 4 个字节 1 个宽字符

注意,各种类型的存储大小与系统位数有关,但目前通用的以64位系统为主。

以下列出了32位系统与64位系统的存储大小的差别(windows 相同):

img

从上表可得知,变量的大小会根据编译器和所使用的电脑而有所不同。

下面实例会输出您电脑上各种数据类型的大小。

2.1.3 实例

#include<iostream>  
#include <limits>

using namespace std;

int main()
{
cout << "type: \t\t" << "************size**************"<< endl;
cout << "bool: \t\t" << "所占字节数:" << sizeof(bool);
cout << "\t最大值:" << (numeric_limits<bool>::max)();
cout << "\t\t最小值:" << (numeric_limits<bool>::min)() << endl;
cout << "char: \t\t" << "所占字节数:" << sizeof(char);
cout << "\t最大值:" << (numeric_limits<char>::max)();
cout << "\t\t最小值:" << (numeric_limits<char>::min)() << endl;
cout << "signed char: \t" << "所占字节数:" << sizeof(signed char);
cout << "\t最大值:" << (numeric_limits<signed char>::max)();
cout << "\t\t最小值:" << (numeric_limits<signed char>::min)() << endl;
cout << "unsigned char: \t" << "所占字节数:" << sizeof(unsigned char);
cout << "\t最大值:" << (numeric_limits<unsigned char>::max)();
cout << "\t\t最小值:" << (numeric_limits<unsigned char>::min)() << endl;
cout << "wchar_t: \t" << "所占字节数:" << sizeof(wchar_t);
cout << "\t最大值:" << (numeric_limits<wchar_t>::max)();
cout << "\t\t最小值:" << (numeric_limits<wchar_t>::min)() << endl;
cout << "short: \t\t" << "所占字节数:" << sizeof(short);
cout << "\t最大值:" << (numeric_limits<short>::max)();
cout << "\t\t最小值:" << (numeric_limits<short>::min)() << endl;
cout << "int: \t\t" << "所占字节数:" << sizeof(int);
cout << "\t最大值:" << (numeric_limits<int>::max)();
cout << "\t最小值:" << (numeric_limits<int>::min)() << endl;
cout << "unsigned: \t" << "所占字节数:" << sizeof(unsigned);
cout << "\t最大值:" << (numeric_limits<unsigned>::max)();
cout << "\t最小值:" << (numeric_limits<unsigned>::min)() << endl;
cout << "long: \t\t" << "所占字节数:" << sizeof(long);
cout << "\t最大值:" << (numeric_limits<long>::max)();
cout << "\t最小值:" << (numeric_limits<long>::min)() << endl;
cout << "unsigned long: \t" << "所占字节数:" << sizeof(unsigned long);
cout << "\t最大值:" << (numeric_limits<unsigned long>::max)();
cout << "\t最小值:" << (numeric_limits<unsigned long>::min)() << endl;
cout << "double: \t" << "所占字节数:" << sizeof(double);
cout << "\t最大值:" << (numeric_limits<double>::max)();
cout << "\t最小值:" << (numeric_limits<double>::min)() << endl;
cout << "long double: \t" << "所占字节数:" << sizeof(long double);
cout << "\t最大值:" << (numeric_limits<long double>::max)();
cout << "\t最小值:" << (numeric_limits<long double>::min)() << endl;
cout << "float: \t\t" << "所占字节数:" << sizeof(float);
cout << "\t最大值:" << (numeric_limits<float>::max)();
cout << "\t最小值:" << (numeric_limits<float>::min)() << endl;
cout << "size_t: \t" << "所占字节数:" << sizeof(size_t);
cout << "\t最大值:" << (numeric_limits<size_t>::max)();
cout << "\t最小值:" << (numeric_limits<size_t>::min)() << endl;
cout << "string: \t" << "所占字节数:" << sizeof(string) << endl;
// << "\t最大值:" << (numeric_limits<string>::max)() << "\t最小值:" << (numeric_limits<string>::min)() << endl;
cout << "type: \t\t" << "************size**************"<< endl;
return 0;
}
本实例使用了 endl,这将在每一行后插入一个换行符,<< 运算符用于向屏幕传多个值,sizeof() 函数用来获取各种数据类型的大小。

当上面的代码被编译和执行时,它会产生以下的结果,结果会根据所使用的计算机而有所不同:

type: ************size**************
bool: 所占字节数:1 最大值:1 最小值:0
char: 所占字节数:1 最大值: 最小值:?
signed char: 所占字节数:1 最大值: 最小值:?
unsigned char: 所占字节数:1 最大值:? 最小值:
wchar_t: 所占字节数:4 最大值:2147483647 最小值:-2147483648
short: 所占字节数:2 最大值:32767 最小值:-32768
int: 所占字节数:4 最大值:2147483647 最小值:-2147483648
unsigned: 所占字节数:4 最大值:4294967295 最小值:0
long: 所占字节数:8 最大值:9223372036854775807 最小值:-9223372036854775808
unsigned long: 所占字节数:8 最大值:18446744073709551615 最小值:0
double: 所占字节数:8 最大值:1.79769e+308 最小值:2.22507e-308
long double: 所占字节数:16 最大值:1.18973e+4932 最小值:3.3621e-4932
float: 所占字节数:4 最大值:3.40282e+38 最小值:1.17549e-38
size_t: 所占字节数:8 最大值:18446744073709551615 最小值:0
string: 所占字节数:24
type: ************size**************

本实例使用了 endl,这将在每一行后插入一个换行符,**<<** 运算符用于向屏幕传多个值,sizeof() 函数用来获取各种数据类型的大小。

当上面的代码被编译和执行时,它会产生以下的结果,结果会根据所使用的计算机而有所不同:

type:         ************size**************
bool: 所占字节数:1 最大值:1 最小值:0
char: 所占字节数:1 最大值: 最小值:?
signed char: 所占字节数:1 最大值: 最小值:?
unsigned char: 所占字节数:1 最大值:? 最小值:
wchar_t: 所占字节数:4 最大值:2147483647 最小值:-2147483648
short: 所占字节数:2 最大值:32767 最小值:-32768
int: 所占字节数:4 最大值:2147483647 最小值:-2147483648
unsigned: 所占字节数:4 最大值:4294967295 最小值:0
long: 所占字节数:8 最大值:9223372036854775807 最小值:-9223372036854775808
unsigned long: 所占字节数:8 最大值:18446744073709551615 最小值:0
double: 所占字节数:8 最大值:1.79769e+308 最小值:2.22507e-308
long double: 所占字节数:16 最大值:1.18973e+4932 最小值:3.3621e-4932
float: 所占字节数:4 最大值:3.40282e+38 最小值:1.17549e-38
size_t: 所占字节数:8 最大值:18446744073709551615 最小值:0
string: 所占字节数:24
type: ************size**************

2.1.3 typedef 声明(选学)

您可以使用 typedef 为一个已有的类型取一个新的名字。下面是使用 typedef 定义一个新类型的语法:

typedef type newname; 

例如,下面的语句会告诉编译器,feet 是 int 的另一个名称:

typedef int feet;

现在,下面的声明是完全合法的,它创建了一个整型变量 distance:

feet a = 5;

2.1.4 类型别名 C++11之后

与typedef很类似

using type = newname;

更推荐使用 using 的方法typedef是C语言遗留下来的,using可以用于模版中,更符合c++赋值逻辑

2.2 变量

变量的概念:存储数据的容器,可以改变

2.2.1 定义

变量定义就是告诉编译器在何处创建变量的存储,以及如何创建变量的存储。

定义一个变量:

格式 : 数据类型 变量名称;

例如

int a;

创建一个名字叫做 a 的 整数类型(简称整形)(int) 的 变量

其余类型变量也是类似格式

long long int b;
char c;
float d;
double e;

数据类型必须是一个有效的 C++ 数据类型

相同类型的多个变量可以连续定义

int i, j, k, l, m, n;

2.2.2 赋值

从右往左赋值

左侧放变量名 赋值符号= 右侧放值

int a;
a = 5;

char c;
c = 'b';

bool b;
b = true;

什么类型的变量 存储对应 的数据

如果随意赋值会产生数据类型转换

int a;
a = 3.1415;
cout << a;

2.2.3 初始化

定义的同时进行赋值的操作叫做初始化

定义 + 赋值 = 初始化

int a = 10;
double b = 3.1415;

如果不进行初始化 将会得到一个随机数据

int a;
cout << a;

double b;
cout << b;

2.2.4 变量名命名规则

标识符命名规则(变量名、函数名、结构体名、数组名)

1、只能由 26个字母区分大小写 以及 0~9 数字 和 下划线_ 组成

2、不能以数字开头

3、不能使用关键字(保留字)(cout不是关键字,int Int;)

int a1, a2, a3;
int myName;
int _apple;
int my_apple_1;
// 以上这些都可以

int 1a;
int int;
int my&*;
//这些都不可以

2.3 C++ 关键字

下表列出了 C++ 中的保留字。这些保留字不能作为常量名、变量名或其他标识符名称。

asm else new this
auto enum operator throw
bool explicit private true
break export protected try
case extern public typedef
catch false register typeid
char float reinterpret_cast typename
class for return union
const friend short unsigned
const_cast goto signed using
continue if sizeof virtual
default inline static void
delete int static_cast volatile
do long struct wchar_t
double mutable switch while
dynamic_cast namespace template

2.4 输入

通过键盘读取数据存入到指定变量中的过程叫做输入

int a;
cin >> a;

cin 表示c++的输入 >> 输入运算符 与 输出相反需要注意

如有多个变量可以进行连续输入

int a, b, c, d, e;
cin >> a >> b >> c >> d >> e;

通过键盘输入时可以利用空格或回车隔开各个数据

因为cin使用空格或回车作为数据分隔符

2.5 scanf 与 printf

scanfprintf 其实是 C 语言提供的函数.大多数情况下,它们的速度比 cincout 更快,并且能够方便地控制输入输出格式.

#include <cstdio>

int main()
{
int x, y;
scanf("%d%d", &x, &y); // 读入 x 和 y
printf("%d\n%d", y, x); // 输出 y,换行,再输出 x

return 0;
}

其中,%d 表示读入/输出的变量是一个有符号整型(int 型)的变量.

类似地:

  1. %s 表示字符串.
  2. %c 表示字符.
  3. %lf 表示双精度浮点数 (double).
  4. %lld 表示长整型 (long long).根据系统不同,也可能是 %I64d
  5. %u 表示无符号整型 (unsigned int).
  6. %llu 表示无符号长整型 (unsigned long long),也可能是 %I64u

除了类型标识符以外,还有一些控制格式的方式.许多都不常用,选取两个常用的列举如下:

  1. %1d 表示最小宽度为 1 的整型.在读入时,即使没有空格也可以逐位读入数字.在输出时,若指定的长度大于数字的位数,就会在数字前用空格填充.若指定的长度小于数字的位数,就没有效果.
  2. %.6lf,用于输出,保留六位小数.

这两种运算符的相应地方都可以填入其他数字,例如 %.3lf 表示保留三位小数.

2.6 输出格式控制

2.7 数据类型转换

2.7.1 隐式转换

2.7.2 显示转换(强制转换)

2.8 题目

a+b

https://www.luogu.com.cn/problem/P1001

字符三角形

https://www.luogu.com.cn/problem/B2005

苹果采购

https://www.luogu.com.cn/problem/P5703

第三章 运算符和表达式

3.1 算术运算符

下表显示了 C++ 支持的算术运算符。

假设变量 A 的值为 10,变量 B 的值为 20,则:

运算符 描述 实例
+ 把两个操作数相加 A + B 将得到 30
- 从第一个操作数中减去第二个操作数 A - B 将得到 -10
* 把两个操作数相乘 A * B 将得到 200
/ 分子除以分母 B / A 将得到 2
% 取模运算符,整除后的余数 B % A 将得到 0
++ 自增运算符,整数值增加 1 A++ 将得到 11
自减运算符,整数值减少 1 A– 将得到 9

样例

#include <iostream>
using namespace std;

int main(){
int a = 21;
int b = 10;
int c ;
c = a + b;
cout << "Line 1 - c 的值是 " << c << endl;
c = a - b;
cout << "Line 2 - c 的值是 " << c << endl;
c = a * b;
cout << "Line 3 - c 的值是 " << c << endl;
c = a / b;
cout << "Line 4 - c 的值是 " << c << endl;
c = a % b;
cout << "Line 5 - c 的值是 " << c << endl ;
int d = 10; // 测试自增、自减
c = d++;
cout << "Line 6 - c 的值是 " << c << endl ;
d = 10; // 重新赋值
c = d--;
cout << "Line 7 - c 的值是 " << c << endl;

return 0;
}

3.2 比较运算符

下表显示了 C++ 支持的关系运算符。

假设变量 A 的值为 10,变量 B 的值为 20,则:

运算符 描述 实例
== 检查两个操作数的值是否相等,如果相等则条件为真。 (A == B) 不为真。
!= 检查两个操作数的值是否相等,如果不相等则条件为真。 (A != B) 为真。
> 检查左操作数的值是否大于右操作数的值,如果是则条件为真。 (A > B) 不为真。
< 检查左操作数的值是否小于右操作数的值,如果是则条件为真。 (A < B) 为真。
>= 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真。 (A >= B) 不为真。
<= 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真。 (A <= B) 为真。

样例

#include <iostream>
using namespace std;

int main(){
int a = 21; int b = 10; int c ;
if( a == b )
{
cout << "Line 1 - a 等于 b" << endl ; }
else
{
cout << "Line 1 - a 不等于 b" << endl ; }
if ( a < b )
{
cout << "Line 2 - a 小于 b" << endl ; }
else
{
cout << "Line 2 - a 不小于 b" << endl ; }
if ( a > b )
{
cout << "Line 3 - a 大于 b" << endl ; }
else
{
cout << "Line 3 - a 不大于 b" << endl ; }
/* 改变 a 和 b 的值 */
a = 5; b = 20; if ( a <= b )
{
cout << "Line 4 - a 小于或等于 b" << endl ; }
if ( b >= a )
{
cout << "Line 5 - b 大于或等于 a" << endl ; }
return 0;
}

3.3 逻辑运算符

下表显示了 C++ 支持的关系逻辑运算符。

假设变量 A 的值为 1,变量 B 的值为 0,则:

运算符 描述 实例
&& 称为逻辑与运算符。如果两个操作数都非零,则条件为真。 (A && B) 为假。
|| 称为逻辑或运算符。如果两个操作数中有任意一个非零,则条件为真。 (A || B) 为真。
! 称为逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假。 !(A && B) 为真。

样例

#include <iostream>
using namespace std;

int main(){
int a = 5; int b = 20; int c ;
if ( a && b )
{
cout << "Line 1 - 条件为真"<< endl ; }
if ( a || b )
{
cout << "Line 2 - 条件为真"<< endl ; }
/* 改变 a 和 b 的值 */
a = 0; b = 10; if ( a && b )
{
cout << "Line 3 - 条件为真"<< endl ; }
else
{
cout << "Line 4 - 条件不为真"<< endl ; }
if ( !(a && b) )
{
cout << "Line 5 - 条件为真"<< endl ; }
return 0;
}

3.4 复合赋值运算

下表列出了 C++ 支持的赋值运算符:

运算符 描述 实例
= 简单的赋值运算符,把右边操作数的值赋给左边操作数 C = A + B 将把 A + B 的值赋给 C
+= 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数 C += A 相当于 C = C + A
-= 减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数 C -= A 相当于 C = C - A
*= 乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数 C *= A 相当于 C = C * A
/= 除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数 C /= A 相当于 C = C / A
%= 求模且赋值运算符,求两个操作数的模赋值给左边操作数 C %= A 相当于 C = C % A

进阶部分

<<= 左移且赋值运算符 C <<= 2 等同于 C = C << 2
>>= 右移且赋值运算符 C >>= 2 等同于 C = C >> 2
&= 按位与且赋值运算符 C &= 2 等同于 C = C & 2
^= 按位异或且赋值运算符 C ^= 2 等同于 C = C ^ 2
|= 按位或且赋值运算符 C |= 2 等同于 C = C | 2

3.5 位运算 (进阶部分)

位运算符作用于位,并逐位执行操作。&、 | 和 ^ 的真值表如下所示:

p q p & q p | q p ^ q
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1

3.6 逗号运算符

3.7 表达式和优先级

3.8 优先级汇总

来自 C++ 运算符优先级 - cppreference ,有修改.

运算符 描述 例子 可重载性
第一级别
:: 作用域解析符 Class::age = 2; 不可重载
第二级别
++ 后自增运算符 for (int i = 0; i < 10; i++) cout << i; 可重载
-- 后自减运算符 for (int i = 10; i > 0; i--) cout << i; 可重载
type() type{} 强制类型转换 unsigned int a = unsigned(3.14); 可重载
() 函数调用 isdigit('1') 可重载
[] 数组数据获取 array[4] = 2; 可重载
. 对象型成员调用 obj.age = 34; 不可重载
-> 指针型成员调用 ptr->age = 34; 可重载
第三级别 (从右向左结合)
++ 前自增运算符 for (i = 0; i < 10; ++i) cout << i; 可重载
-- 前自减运算符 for (i = 10; i > 0; --i) cout << i; 可重载
+ 正号 int i = +1; 可重载
- 负号 int i = -1; 可重载
! 逻辑取反 if (!done) … 可重载
~ 按位取反 flags = ~flags; 可重载
(type) C 风格强制类型转换 int i = (int) floatNum; 可重载
* 指针取值 int data = *intPtr; 可重载
& 值取指针 int *intPtr = &data; 可重载
sizeof 返回类型内存 int size = sizeof floatNum; int size = sizeof(float); 不可重载
new 动态元素内存分配 long *pVar = new long; MyClass *ptr = new MyClass(args); 可重载
new [] 动态数组内存分配 long *array = new long[n]; 可重载
delete 动态析构元素内存 delete pVar; 可重载
delete [] 动态析构数组内存 delete [] array; 可重载
第四级别
.* 类对象成员引用 obj.*var = 24; 不可重载
->* 类指针成员引用 ptr->*var = 24; 可重载
第五级别
* 乘法 int i = 2 * 4; 可重载
/ 除法 float f = 10.0 / 3.0; 可重载
% 取余数(模运算) int rem = 4 % 3; 可重载
第六级别
+ 加法 int i = 2 + 3; 可重载
- 减法 int i = 5 - 1; 可重载
第七级别
<< 位左移 int flags = 33 << 1; 可重载
>> 位右移 int flags = 33 >> 1; 可重载
第八级别
<=> 三路比较运算符 if ((i <=> 42) < 0) ... 可重载
第九级别
< 小于 if (i < 42) ... 可重载
<= 小于等于 if (i <= 42) ... 可重载
> 大于 if (i > 42) ... 可重载
>= 大于等于 if (i >= 42) ... 可重载
第十级别
== 等于 if (i == 42) ... 可重载
!= 不等于 if (i != 42) ... 可重载
第十一级别
& 位与运算 flags = flags & 42; 可重载
第十二级别
^ 位异或运算 flags = flags ^ 42; 可重载
第十三级别
` ` 位或运算 `flags = flags
第十四级别
&& 逻辑与运算 if (conditionA && conditionB) ... 可重载
第十五级别
` ` 逻辑或运算
第十六级别 (从右向左结合)
? : 条件运算符 int i = a > b ? a : b; 不可重载
throw 异常抛出 throw EClass("Message"); 不可重载
= 赋值 int a = b; 可重载
+= 加赋值运算 a += 3; 可重载
-= 减赋值运算 b -= 4; 可重载
*= 乘赋值运算 a *= 5; 可重载
/= 除赋值运算 a /= 2; 可重载
%= 模赋值运算 a %= 3; 可重载
<<= 位左移赋值运算 flags <<= 2; 可重载
>>= 位右移赋值运算 flags >>= 2; 可重载
&= 位与赋值运算 flags &= new_flags; 可重载
^= 位异或赋值运算 flags ^= new_flags; 可重载
` =` 位或赋值运算 `flags
第十七级别
, 逗号分隔符 for (i = 0, j = 0; i < 10; i++, j++) ... 可重载

需要注意的是,表中并未列出 const_caststatic_castdynamic_castreinterpret_casttypeidsizeof...noexceptalignof 等运算符,因为它们的使用形式与函数调用相同,不会出现歧义.

第四章 分支结构

4.1 if语句

4.1.1 单分支语句

基本 if 语句

以下是基本 if 语句的结构:

if (条件) 
{
主体;
}

if 语句通过对条件进行求值,若结果为真(非 0),执行语句,否则不执行.

如果主体中只有单个语句的话,大括号可以省略.

4.1.2 双分支语句

if…else 语句

if (条件) 
{
主体1;
}
else
{
主体2;
}

if…else 语句和 if 语句类似,else 不需要再写条件.当 if 语句的条件满足时会执行 if 里的语句,if 语句的条件不满足时会执行 else 里的语句.同样,当主体只有一条语句时,可以省略大括号.

4.1.3 多分支语句

else if 语句

if (条件1) 
{
主体1;
}
else if (条件2)
{
主体2;
}
else if (条件3)
{
主体3;
}
else
{
主体4;
}

else if 语句是 if 和 else 的组合,对多个条件进行判断并选择不同的语句分支.在最后一条的 else 语句不需要再写条件.例如,若条件 1 为真,执行主体 1,条件 3 为真而条件 1 和条件 2 都为假,执行主体 3,所有的条件都为假才执行主体 4.

实际上,这一个语句相当于第一个 if 的 else 分句只有一个 if 语句,就将花括号省略之后放在一起了.如果条件相互之间是并列关系,这样写可以让代码的逻辑更清晰.

4.2 三目运算符(条件运算符)

条件运算符可以看作 if 语句的简写,a ? b : c 中如果表达式 a 成立,那么这个条件表达式的结果是 b,否则条件表达式的结果是 c

4.3 switch语句

switch-case语句

switch (选择句) 
{
case 标签1:
主体1;
case 标签2:
主体2;
default:
主体3;
}

switch 语句执行时,先求出选择句的值,然后根据选择句的值选择相应的标签,从标签处开始执行.其中,选择句必须是一个整数类型表达式,而标签都必须是整数类型的常量.例如:

int i = 1;  // 这里的 i 的数据类型是整型 ,满足整数类型的表达式的要求
switch (i)
{
case 1:
cout << "OI WIKI" << endl;
}
char i = 'A'; // 这里的 i 的数据类型是字符型 ,但 char 也是属于整数的类型,满足整数类型的表达式的要求 
switch (i)
{
case 'A':
cout << "OI WIKI" << endl;
}

switch 语句中还要根据需求加入 break 语句进行中断,否则在对应的 case 被选择之后接下来的所有 case 里的语句和 default 里的语句都会被运行.具体例子可看下面的示例.

char i = 'B'; 
switch (i)
{
case 'A':
cout << "OI" << endl;
break;
case 'B':
cout << "WIKI" << endl;
default:
cout << "Hello World" << endl;
}

以上代码运行后输出的结果为 WIKIHello World,如果不想让下面分支的语句被运行就需要 break 了,具体例子可看下面的示例.

char i = 'B'; 
switch (i)
{
case 'A':
cout << "OI" << endl;
break;
case 'B':
cout << "WIKI" << endl;
break;
default:
cout << "Hello World" << endl;
}

以上代码运行后输出的结果为 WIKI,因为 break 的存在,接下来的语句就不会继续被执行了.最后一个语句不需要 break,因为下面没有语句了.

处理入口编号不能重复,但可以颠倒.也就是说,入口编号的顺序不重要.各个 case(包括 default)的出现次序可任意.例如:

char i = 'B'; 
switch (i)
{
case 'B':
cout << "WIKI" << endl;
break;
default:
cout << "Hello World" << endl;
break;
case 'A':
cout << "OI" << endl;
}

switch 的 case 分句中也可以选择性的加花括号.不过要注意的是,如果需要在 switch 语句中定义变量,花括号是必须要加的.例如:

char i = 'B'; 
switch (i)
{
case 'A':
{
int i = 1, j = 2;
cout << "OI" << endl;
ans = i + j;
break;
}
case 'B':
{
int qwq = 3;
int ans;
cout << "WIKI" << endl;
ans = qwq * qwq;
break;
}
default:
{
cout << "Hello World" << endl;
}
}

第五章 循环结构一 while

编程中重复的事情

例如 : 输出100遍 hello world,从100个x相加

可以利用循环解决

5.1 while 循环

以下是 while 语句的结构:

while (判断条件) 
{
循环体;
}

执行顺序:

image-20260516155223109

#include <iostream>
using namespace std;

int main()
{
while (true)
{
cout << "hello" << endl;
}

return 0;
}

可以先运行这段代码 观察输出结果

使用 Ctrl + C 终止程序运行

这种情况称为死循环(无限循环) (一般不可以写出来)

需要添加条件 自动结束循环 (一般使用计数的方式)

#include <iostream>
using namespace std;

int main()
{
int i = 0; // 添加变量 用来计数
while (i < 10) // 添加条件
{
cout << "hello" << endl;
}

return 0;
}

还是死循环,因为条件一直成立,需要添加变化(步长)

最终得到

#include <iostream>
using namespace std;

int main()
{
int i = 0; // 添加变量 用来计数
while (i < 10) // 添加条件
{
cout << "hello" << endl;
i += 1;
}

return 0;
}

5.1.1 循环的三要素

  • 变量:用来计数
  • 条件:用来控制循环的结束
  • 步长:变量变化的间隔(一般1个1个加,也可以5个或者10加)

共同决定了 循环的次数

5.2 do-while 循环

以下是 do…while 语句的结构:

do 
{
循环体;
} while (判断条件);

执行顺序:

image-20260516171109086

与 while 语句的区别在于,do…while 语句是先执行循环体再进行判断的.

第六章 循环结构二 for

以下是 for 语句的结构:

for (初始化; 判断条件; 间隔) 
{
循环体;
}

执行顺序:

image-20260516172223813

for 语句的三个部分中,任何一个部分都可以省略.其中,若省略了判断条件,相当于判断条件永远为真.

第七章 一维数组

数组是存放相同类型对象的容器,数组中存放的对象没有名字,而是要通过其所在的位置访问.数组的大小是固定的,不能随意改变数组的长度

概念:一组具有相同数据类型的元素,元素的本质是变量