备战蓝桥杯,第一章:C++入门

一.第一个C++程序

1.专栏引入和基础程序

在备战蓝桥杯的的道路上,指定是艰辛的。但是只要坚持就一定能得到自己想要的成绩。备战蓝桥杯的历程中,我们会进行C++语言的学习、数据结构的深度剖析、以及一些重要的算法。

在学习C语言时,我们首先学习了打印Hello World的代码,在C++语言入门学习中,依然如此。所以下面给出打印Hello World的代码。

cpp 复制代码
#include <iostream> //头⽂件 
using namespace std; //使⽤std的名字空间 
int main() //main函数 
{
 cout << "hello world!" << endl; //输出:在屏幕打印"hello world!" 
 return 0;
}

上述代码的具体解释:将字符串hello world!打印在屏幕上。

虽然第一次接触C++语言,不懂得什么是头文件?什么是main函数?但是不要担心,请听我一一道来。

2.main函数

main函数是程序的入口,类似于C语言的学习。在C++语言中,所有的程序的开始都会从main函数进入。不论有多少行代码,都是从main函数开始执行的,所以main函数也叫做主函数。主函数前面的int为函数的返回值类型。与程序代码最后的return 0相对应(具体细节在函数章节)。

  • mian函数是程序的入口
  • main函数有且只有一个,在整个项目中不允许拥有多个主函数(程序入口不明确造成编译错误)

3.字符串

在C语言中,使用单引号括起来的一个字符表示字符字面值,比如:'a' '1',使用双引号括起来的多个字符组成的集合叫做字符串,比如"fwxmhm",字符串可以有一个或者多个字符组成,当然也可以没有字符(空字符串)。上面代码打印出来的Hello World就是一个字符串。C语言字符和字符串表示的方法在C++语言中完全支持。但是在C++语言中引入了STL的String来表示字符串,功能很强大,C语言不支持。后续我们将详细讲解。

4.头文件

前面的代码中,写的#include,就是在包含头文件,头文件的名字叫做:iostream,使用尖括号进行文件的包含。iostream文件中的io指的是输入和输出的意思,(分别对应输入输出的英文首字母)。在C++程序中,需要完成输入和输出操作时会涉及到iostream文件中的多个定义,所以就需要包括这个头文件。道理和C语言的头文件是一样的。下面给出一部分C++的头文件展示,具体的详见相关网站:

C++头文件相关网址https://en.cppreference.com/w/cpp/headers.html

头文件的命名格式:

|-----------|-----------|----------------|---------------------------|
| 头文件类型 | 约定 | 实例 | 说明 |
| C++旧风格 | 以.h结尾 | <iostream.h> | C++中可以使用,一些新的编译器不适用 |
| C语言旧风格 | 以.h结尾 | <math.h> | C、C++均可以使用 |
| C++新风格 | 没有扩展名 | <iostream> | C++以使用,需要使用namespace std |
| C++中转换后的C | 加上前缀没有扩展名 | <cmath> | C++可以使用,但是文件内部有可能与C语言改前不同 |

5.cin和cout的初识

cout这句代码在上面的程序中是最重要的代码,其他代码都是为这句代码服务的。代码中的cout是标准输出流对象(针对控制台,也就是屏幕)其实还有标准输入流对象(针对的是键盘)关键字是cin。cout是告诉程序把后面双引号的内容打印到标准输出流对象(屏幕)上,双引号中的内容是可以替换的。(替换成程序员想要打印的内容)

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 int num;
 cin >> num; //获取标准输⼊ 
 cout << num << endl; //对获取到的结果标准输出 
 return 0;
}

上述代码的具体解释:首先创建一个整型变量num,用于接收键盘输入的整型值。随后将输入的num的值打印在屏幕上。

  1. cin和cout是全局的流对象,cin负责输入数据,cout负责输出数据。
  2. endl是C++中一个特殊的操作符,效果是换行和刷新缓冲区,使用时需要包含iostream头文件。
  3. <<是流插入运算符,和cout配合使用;>>是流提取运算符,和cin配合使用,两者容易混淆。
cpp 复制代码
#include <iostream>
using namespace std;
int main() 
{
 float score = 0;
 cin >> score;//直接读取的就是浮点数 
 cout << score;//直接输出的就是浮点数 
 
 return 0;
}

上述代码的解释:C++的输入输出函数不同于C语言的printf和scanf函数,C++语言不需要提前规定变量的数据类型,比较方便。但是在某些特殊时期就不得不用C语言的输入输出函数。

6.名字空间

using namespace std;这句代码的意思是使用命名空间std。为了更好的了解命名空间,接下来我举一个例子:

在学校中,难免有重名的同学。张三也不例外,为了解决老师叫张三不叫错的问题,校长将不同的张三分配到不同的班级,这个班级就是这里的命名空间,张三就是命名空间内的成员。

在C++语言中,变量、函数和类都是大量存在的,这些变量、函数和类的名称如果都不加以规范存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行隔离,以避免命名冲突或名字污染,namespace关键字的出现就是针对这一问题的。std是C++标准库的名字空间名,C++将标准的定义实现都放在这个命名空间中,当我们需要使用标准库的内容时,就需要在使用之前加上using namespace std;当有了这句话时,表明名字空间std的信息都是可见和可用的。

名字空间也可以自己定义,在这里就不详细说明了。详细的请看《C++语言第一章语言的入门》。当直接使用using namespace std;是一种简单粗暴的方法,直接这样使用就意味着std命名空间内所有的成员标识符都可以直接使用,但是我们往往只使用一部分。所以也可以用如下的方法使用:

cpp 复制代码
#incldue <iostream>
int main()
{
 std::cout << "hello world" << std::endl;
 return 0;
}

代码中的std::cout的意思就是使用命名空间std里的cout。 采用std::cout在竞赛中,比较麻烦,所以我们在竞赛中可以直接在开头使用std的命名空间。但是在今后工作时,多数情况下都需要使用这样的格式:std::cout。

7.注释

C++语言中有两种注释形式:单行注释和多行注释,注释的作用是对代码进行解释,注释对代码的编译没有影响。注释是程序员自己看的,编译器会忽略注释,基于注释是被编译器忽略这个特点,在代码书写时,不需要的代码可以通过注释的方式进行屏蔽。

单行注释://

cpp 复制代码
int main()
{
 int num;
 cin >> num;
 //cout << num << endl; //这是单⾏注释 
 return 0;
}

多行注释:/* */

cpp 复制代码
/*
这是多⾏注释 
int main()
{
 int num;
 cin >> num;
 cout << num << endl;
 return 0;
}
*/

8.练习

(1)打印Hello,World!

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 cout << "Hello,World!" << endl;
 return 0;
}

上述代码根据学习的第一个程序,在屏幕上会成功打印Hello,World!。

(2)打印小飞机

cpp 复制代码
#include <iostream>
using namespace std;
int main() 
{
 cout << " ** " << endl;
 cout << " ** " << endl;
 cout << "************" << endl;
 cout << "************" << endl;
 cout << " * * " << endl;
 cout << " * * " << endl;
 return 0;
}

上述代码根据endl可以换行的特性,将会在屏幕上打印出以*字符组成的小飞机图案。

(3)输出第二个整数

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 int n1, n2;
 cin >> n1 >> n2;
 cout << n2 << endl;
 return 0;
}

上述代码根据C++语言的输入输出函数的特性,将会读取输入的两个整数,在输出时,只将第二个整数打印在屏幕上。

(4)字符三角形

cpp 复制代码
#include<iostream>
using namespace std;
int main()
{
 char c = 0;
 cin >> c;
 cout << " " << c << endl;
 cout << " " <<c << c << c << endl;
 cout << c << c << c << c << c <<endl;
 return 0;
}

二.数据类型

C++语言中,提供了丰富的数据类型用于记录生活中的各种数据。所谓类型就是相似的数据所拥有的共同特征,编译器只有知道了数据的类型才会进一步成功的操作数据。下面是即将讲解的数据类型:

1.字符型

cpp 复制代码
char 

在键盘上可以敲出各种字符,字符是由单引号括起来的。为了能说明这些字符,给他们抽象出一种类型,就是字符类型。定义字符类型变量时会用到关键字char

ASCII编码

我们知道在计算机中,所有的数据都是已二进制的形式存储的。字符也不例外,为了更方便的存储美国国家标准学会出台了一个标准ASCII编码,C语言中的字符就遵循了ASCII编码的方式。

ASCII编码相关网址https://zh.cppreference.com/w/cpp/language/ascii

cpp 复制代码
#include<iostream>
using namespace std;
int main()
{
 char c1 = 'Q';
 cout << c1 << endl;
 char c2 = 81;
 cout << c2 << endl; //这⾥的81是字符Q的ASCII码值,也是可以正常打印的 
 return 0;
}

上述代码通过ASCII编码数字的形式在屏幕上打印出了81编码值的字符。证明了字符是以二进制的形式存储的这一道理。

2.整型

整型类型是对所有的证书的抽象,为了能对整数形成统一的类型标识,就有了整型;在C语言和C++语言中整型被分为4类:short、 int 、long 、long long。

cpp 复制代码
short [int] //短整型 
int //整型 
long [int] //⻓整型 
long long [int] //更⻓的整型 

3.浮点型

浮点型是对所有小数的抽象,为了能对实数进行统一的类型标识,就有了浮点型。浮点型有三类:folat、double、long double。

cpp 复制代码
float //单精度浮点型  
double //双精度浮点型 
long double //更⻓的双精度浮点型 

代码演示:

cpp 复制代码
#include<iostream>
using namespace std;
int main()
{
 char c = 'a';
 short s = -10;
 int i = -10;
 long l = -10;
 long long ll = -10;
 float k = 3.14f;
 double d = 3.14;
 long double ld = 3.14;
 
 return 0;
}

3.14; //编译器会默认识别为double类型

3.14f; //编译器会默认识别为float类型

1e5; //这种写法是科学计数法的形式,意思是1.0*10^5

1e5+10; //1*100000+10 == 100010

1.23e5+10; //1.23*100000+10 = 123010

4.Bool类型

C++语言有一种类型叫Bool类型,布尔类型的变量的值可以是true或false,这种类型的变量专门用来表示真假。当然在C和C++中,0表示假,非0表示真。有时候不用bool类型也能表达相同的逻辑。

代码演示:

cpp 复制代码
//代码1 
#include <iostream>
using namespace std;
int main()
{
 bool flag = true;
 if (flag)
 printf("I like C++!\n");
 return 0;
}
//代码2 
#include <iostream>
using namespace std;
int main()
{
 int flag = 0;
 cin >> flag; //如果输⼊⾮零的值,flag就表⽰真 
 if (flag)
 printf("I like C++!\n");
 return 0;
}

上述代码的具体解释:代码1中,用bool 类型创建了变量flag并且初始化为真,然后利用if语句,当flag为真时,打印"I like C++!这个字符串;在代码2中,创建一个bool类型的变量用于接收键盘输入的值(非0为真,0为假)根据输入值的不同,代码处理不同。当输入非0值时,屏幕上打印"I like C++!这个字符串,否则屏幕上什么也不打印。

5.signed和unsigned

signed和unsigned关键字是修饰字符型和整型的。signed关键字表示一个类型带有正负号,包含负值,比如:温度、存款。unsigned关键字表示类型不带有正负号,只能表示0和正整数,比如:年龄。有了signed和unsigned的修饰,字符和整型更加丰富,可以有以下不同的类型:

cpp 复制代码
//字符型 
char
signed char //有符号的字符类型 
unsigned char //⽆符号的字符类型 

//短整型 
short [int]
[signed] short [int] //有符号的短整型 
unsigned short [int] //⽆符号的短整型 

//整型 
int 
[signed] int //有符号的整型 
unsigned [int] //⽆符号的整型 

//⻓整型 
long [int] 
[signed] long [int] //有符号的⻓整型 
unsigned long [int] //⽆符号的⻓整型 

//更⻓的整型 
long long [int]
[signed] long long [int] //有符号的 
unsigned long long [int] //⽆符号的

signed int a; //等同于int a,⼀般不写signed 
unsigned int a; // unsigned int:⽆符号整数类型 
 

变量声明为unsigned的好处是:同样长度的内存能够表示更大的整数值,增大了一倍。比如,16位的signed short int的取值范围是:-32768~32767,最大是32767;而unsigned short int的取值范围:0~65535,最大值增大到了65535。下面是相关数据类型的范围:

cpp 复制代码
#define SHRT_MIN (-32768) //有符号16位整型的最⼩值 
#define SHRT_MAX 32767 //有符号16位整型的最⼤值 
#define USHRT_MAX 0xffffU //⽆符号16位整型的最⼤值 
#define INT_MIN (-2147483647 - 1) //有符号整型的最⼩值 
#define INT_MAX 2147483647 //有符号整型的最⼤值 

注意:字符类型char也可以设置成signed char或者unsigned char。大部分编译器上char就是signed char。这就是说:char不等于signed char;它有可能是signed char,也有可能是unsigned char。这一点与int不同,int就等于signed int。

6.数据类型长度

每一种数据类型都有自己的长度,使用不同的数据类型,能够创建出长度不同的变量,变量长度的不同,存储的数据范围就有所差异。下来介绍数据类型长度的求法。

(1)sizeof操作符

sizeof是一个关键字,也是操作符,专门是用来计算特定的数据类型的长度的,单位是字节。sizeof操作符的操作数可以是类型,也可以是变量名或者表达式,sizeof的操作数如果不是类型,是表达式的时候,可以省略掉后面的括号。下面是相关使用细节:

cpp 复制代码
sizeof( 类型 )
sizeof 表达式

sizeof的计算结果是size_t类型的,size_t指的是无符号整数(该类型包含了所有可能的unsigned int,unsigned long , unsigned long long等类型,具体取决于编译器)。

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 int a = 10;
 cout << sizeof(a) << endl;
 cout << sizeof a << endl; //a是变量的名字,可以省略掉sizeof后边的(),但不
建议去掉 
 cout << sizeof(int) << endl;
 return 0;
}

上述代码的具体解释:代码利用sizeof操作符,计算出了int数据类型的大小。这里的变量和数据类型大小都是四个字节。

(2)各数据类型的长度

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 cout << sizeof(char) << endl;
 cout << sizeof(bool) << endl;
 cout << sizeof(short) << endl;
 cout << sizeof(int) << endl;
 cout << sizeof(long) << endl;
 cout << sizeof(long long) << endl;
 cout << sizeof(float) << endl;
 cout << sizeof(double) << endl;
 cout << sizeof(long double) << endl;
 return 0;
}

上述代码在DevC++中,输出的结果为:1 1 2 4 4 8 4 8 16

7.各数据类型的取值范围

前面的知识已经让我们来了解到了很多的数据类型,不同的数据类型所创建的变量的长度是有差异的,这个长度差异又决定了这种变量中能存储的值的大小。其实每一种数据类型都有自己的取值范围,也就是存储的数值的最大值和最小值的区间,下面是不同的数据类型的取值范围:

|--------------------|--------------------------------------------|---------------------------------------|----------------------------------------|
| 类型 | 取值范围 | 最小值 | 最大值 |
| char | -128~127 | | |
| unsigned char | 0~255 | 0 | |
| short | -32878~32767 | | |
| unsigned short | 0~65535 | 0 | |
| int | -2147483648~ 2147483647 | | |
| unsigned int | 0~4294967295 | 0 | |
| long | -2147483648~2147483647 | | |
| unsigned long | 0~4294967295 | 0 | |
| long long | -9223372036854775808~ 9223372036854775807 | | |
| unsigned long long | 0~18446744073709551615 | 0 | |

8.typedef

在C++中,有一个关键字是和类型有关的,是用来给类型重命名的。当有一个类型比较复杂的时候,可以简化类型。typedef在竞赛中经常使用,可以提升编码速度。typedef使用的基本语法形式:

cpp 复制代码
typedef 旧类型名 新类型名;

比如:
typedef unsigned int uint; 
typedef long long ll;
typedef unsigned long long ull;

应用
uint num1 = 0;//等价于 unsigned int num1 = 0; 
ll num2 = 0; //等价于 long long num2 = 0; 
ull num3 = 0; //等价于 unsigned long long num3 = 0; 

上述代码的具体解释:将unsigned int类型重命名为unit,使用unit创建的变量和使用unsigned int是一样的,其他几个也是一样的道理。创建变量时,uint和unsigned int是相同的,相当于等价替换。

9.练习

(1)整数

cpp 复制代码
#include <iostream>
using namespace std;
int main() 
{
 int a;
 cin >> a;
 cout << a;
 return 0;
}

上述代码的具体解释:创建一个整型变量a,输入一个数字,随后输出这个整数。

(2)打印字符

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 int n = 0;
 cin >> n;
 char ch = n;
 cout << ch << endl;
 return 0;
}

上述代码的具体解释:创建一个整型变量,键盘输入值存在n里,随后创建一个字符变量,将n的ASCII码值以字符的形式打印出来。

(3)倒序

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 int a = 0;
 int b = 0;
 int c = 0;
 cin >> a >> b >> c;
 cout << c << " " << b << " " << a << endl;
 return 0;
}

上述代码的具体解释:创建三个整型变量分别读取键盘输入的三个值,随后将顺序颠倒打印在屏幕上。

(4)整型存储空间的大小

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 int n = 0;
 short s = 0;
 cout << sizeof(n) << " " << sizeof(s) << endl;
 
 return 0;
}

上述代码的具体解释:创建两个整型变量,分别用int 和short创建。之后利用sizeof操作符计算两个数据类型的大小。

四.变量和常量

1.变量的创建

了解完数据结构之后,就可以通过数据结构定义变量。什么是变量呢?把经常变化的值称为变量,不变的值称为常量。变量创建的语法形式如下:

data_type name;

data_type是数据类型

name是变量的名字

下面是创建变量的方式:

cpp 复制代码
int age; //整型变量 
char ch; //字符变量 
double weight; //浮点型变量 

变量命名规则遵循一下规则:

  • 变量名只能由字母、数字和下划线组成,且必须以字母或下划线开头。
  • 变量名不能以纯数字开头,也不能包含特殊字符,如空格、连字符等。
  • 变量名不能使用语言的关键字。
  • 变量名应该具有意义,有助于理解变量的含义和用途。
  • 变量名应该简短明了,避免使用过长的名称。
  • 变量名应该区分大小写。

2.变量初始化

变量在创建的时候就给一个初始化,就叫初始化。

cpp 复制代码
int age = 18;
char ch = 'w';
double weight = 48.0;
unsigned int height = 100;

3.变量的分类

  • 全局变量:在大括号外部定义的变量就是全局变量。全局变量的适用范围更广,整个工程想使用,都有办法使用的。
  • 局部变量:在大括号内部定义的变量就是局部变量。局部变量的使用范围是比较局限,只能在自己所在的局部范围内使用。
cpp 复制代码
#include <iostream>
using namespace std;
int global = 2023; //全局变量 
int main()
{
 int local = 2018; //局部变量 
 cout << local << endl;
 cout << global << endl;
 return 0;
}
cpp 复制代码
#include <iostream>
using namespace std;
int n = 1000;
int main()
{
 int n = 10;
 cout << n << endl; //打印的结果是多少呢? 
 return 0;
}

当局部变量和全局变量名字冲突并且同时调用时,用的是局部变量的值

cpp 复制代码
//未初始化的局部变量 
#include <iostream>
using namespace std;
int main()
{
 //局部变量 
 int a;
 char c;
 float f;
 double d;
 
 cout << "int:" << a << endl;
 cout << "char:" << c << endl;
 cout << "float:" << f << endl;
 cout << "double:" << d << endl;
 return 0;
}

未初始化的局部变量,在某些编译器打印时,会是随机值。在某些编译器,会报错。所以创建局部变量时,应该即使初始化。

cpp 复制代码
//未初始化的全局变量 
#include <iostream>
using namespace std;
//全局变量 
int a;
char c;
float f;
double d;
int main()
{
 cout << "int:" << a << endl;
 cout << "char:" << c << endl;
 cout << "float:" << f << endl;
 cout << "double:" << d << endl;
 return 0;
}

创建全局变量不初始化,在所有的编译器上都不会报错。所以在竞赛过程中,一般都是定义全局变量。

注意:全局变量通常在定义时就被初始化,如果没有明确指定初始值,通常会被初始化为0。局部变量通常不会自动初始化,它们需要在使用之前明确地赋值或初始化。如果没有初始化,它们的值将是未定义的,使用未初始化的局部变量可能会导致不可预测的行为或者运行时错误,因此局部变量建议初始化。

4.常量

常量就是不能改变的值,通常我们会使用三种常量:

  • 字面常量
  • #define定义的常量
  • const定义的常量

下面分别介绍一下:

(1)字面常量

整型常量:100 -5 0 0X123整型常量一般可以写成10进制、8进制、16进制。

字符常量:'a'

浮点常量:3.14 1E6

(2)#define定义常量

cpp 复制代码
//#define 常量名 内容
#include <iostream>
using namespace std;
#define M 100
#define CH 'x'
#define PI 3.14159
int main()
{
 cout << M << endl;
 cout << CH << endl;
 cout << PI << endl;
 return 0;
}

这里的M、CH、PI都是常量,可以直接使用,但是不能被修改。使用#define定义常量的时候不关注类型,只进行简单的替换,以下就是替换之后的代码:

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 cout << 100 << endl;
 cout << 'x' << endl;
 cout << 3.14159 << endl;
 return 0;
}

(3)const定义常量

除了上面的方式外,C++中还可以使用const来定义常量,这种常量会具有具体的类型。比#define更加严谨。语法形式如下:

cpp 复制代码
//const 类型 常量名字 = 常量值;
//const double PI = 3.14159;
#include <iostream>
using namespace std;
const double PI = 3.14159;
int main()
{
 int r = 0;
 cin >> r;
 cout << "周⻓:" << 2 * PI * r << endl;
 cout << "⾯经:" << PI * r * r << endl; 
 
 //PI = 3.14;//这种写法是错误的,常量不能被修改  
 return 0;
}

习惯上,这种常量的名字一般会写成大写,而普通变量的名字不会全大写,这样就可以做一个区分。使用const定义的常量的好处:增加程序的可读性,PI比3.1415926更加容易理解和书写、使用。增加了程序的可维护性,如果改变常量的值,只要在定义的部分修改,使用的地方也就随之改变了,做到了一改全改的效果。常量是不能修改的,当然const定义的常量也不能修改。具有只读属性。

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 const int num = 10;
 num = 20; //修改num,编译器会报错的 
 return 0;
}

5.练习

(1)买票

cpp 复制代码
#include <iostream>
using namespace std;
int main() 
{
 int a = 0;
 cin >> a;
 cout << a * 100 << endl;
 return 0; 
}
//换成全局变量也是可以的 
#include <iostream>
using namespace std;
int a;
int main() 
{
 cin >> a;
 cout << a * 100 << endl;
 return 0;
}

上述代码的具体解释:创建一个整型变量a,用于键盘接收票数,一票100元,输出100*a的值就是买票需要的钱。

(2)A+B问题

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 int a = 0;
 int b = 0;
 cin >> a >> b;
 cout << a + b << endl;
 return 0;
}
//换成全局变量也是可以的 
#include <iostream>
using namespace std;
int a,b;
int main()
{
 cin >> a >> b;
 cout << a + b <<endl;
 return 0;
}

上述代码的具体解释:创建两个整型变量,读取键盘输入的值,随后输出两者的和

(3)鸡兔同笼

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 int j = 0; //鸡的个数 
 int t = 0; //兔的个数 
 int h = 35; //头的个数 
 int f = 94; //脚的个数 
 j = (4 * h - f) / 2;
 t = h - j;
 cout << t << " " << j << endl;
 return 0;
}

五.算术操作符

1.算数操作符

在写代码时,一定会涉及到计算。为了方便运算,提供了一系列操作符,其中有一组操作符叫做:算数操作符。分别是:+ - * / %,这些操作符都是双目操作符。

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 int a = 7 + 2; //加法运算 
 int b = 7 - 2; //减法运算 
 int c = 7 * 2; //乘法运算 
 int d = 7 / 2; //除法运算,得到的是整除后的商 
 int e = 7 % 2; //取余运算,得到的是整除后的余数 
 
 cout << a << endl;
 cout << b << endl;
 cout << c << endl;
 cout << d << endl;
 cout << e << endl;
 
 return 0;
}

易错点:

/:除法的操作符,除数不能是0,如果除数为0,程序会崩溃的。

%:取模操作符的计算结果是两个操作数进行除法运算后的余数。取模操作符的操作数只能是整型,不能是浮点型,这个编译器会报语法错误的。

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 int a = 10;
 int b = 0;
 int c = a / b;
 
 float d = 6.0;
 float e = d % 2;
 return 0;
}

上述代码的两个操作均会引发编译器的报错,这是因为违反了操作符相关的规则,所以如上的易错点要格外小心。

2.浮点数的除法

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 float x = 6 / 4;
 cout << x << endl; // 1
 float y = 6.0 / 4; // 6/4.0结果是⼀样的 
 cout << y << endl; // 1.5
 return 0;
}

浮点数的除法结果才是浮点数,结果要想是精确的小数,操作数必须有一个是浮点数,否则计算结果就会是整形常量。

3.负数的取模

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 cout << 11 % -5 << endl; // 1
 cout << -11 % -5 << endl; // -1
 cout << -11 % 5 << endl; // -1
 return 0;
}

取模运算的正负号取决于第一个操作树的正负,第一个操作为正,取模运算的结果就为正数;第一个操作数为负数,取模运算结果就为负数。

4.数值溢出

我们前面学习了各个数据结构的取值范围,那么超出了这一取值范围输出结果又是什么呢?下面请看下方的代码演示:

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 char a = 'Z';
 char b = a + 'Z';
 cout << b << endl; // 输出了不显⽰的内容 
 
 //printf是格式化输出,后⾯章节会讲,这⾥暂不做讲解 
 printf("%d", b); // -76,char的⼗进制内容 
 return 0;
}

上述代码的具体解释:首先创建了两个字符类型的变量,b的字符变量初始化为a+Z,因为char类型的变量取值范围是-128~127之间,所以变量b数值会溢出,故而第一行输出了不显示的内容。第二行以整形形式打印字符变量b时,结果不会为a+Z的ASCII码值的简单相加,结果为数值移除后循环的结果。下面请看具体解释:

因为char类型的变量的取值范围是-128~127之间,所以不会计算出其余取值范围的数字,当127继续加1时,结果会沿着上述圆形方向进一位,结果不会是128,而是-128。

5.练习

(1)计算(a+b)*c

cpp 复制代码
#include <iostream>
using namespace std;
int a, b, c;
int main()
{
 cin >> a >> b >> c;
 int r = (a + b) * c;
 cout << r << endl;
 return 0;
}

上述代码首先创建了三个全局变量,用于接收键盘输入的三个值。随后用局部变量r接收计算后的结果,之后便在屏幕上输出对应的结果。

(2)带余除法

cpp 复制代码
#include <iostream>
using namespace std;
int a, b;
 
int main() 
{
 cin >> a >> b;
 cout << a / b << " " << a % b << endl;
}

上述代码首先创建了两个全局变量,用于接收键盘输入的两个值。随后在屏幕上输出了两者的商和余数。

(3)整数的个位

cpp 复制代码
#include <iostream>
using namespace std;
int a;
int main() 
{
 cin >> a;
 cout << a % 10 << endl;
 return 0;
}

上述代码根据数学相关原理,知道一个数的个位数是这个数对10取余的结果,所以代码首先创建了一个全局变量用于接收键盘输入的值,随后将其对10取余,将结果打印在屏幕上。

(4)整数的十位

cpp 复制代码
#include <iostream>
using namespace std;
int a;
int main()
{
 cin >> a;
 cout << a % 100 / 10 << endl;
 return 0;
}

上述代码同样是数学相关的知识,一个数的十位是这个数先对100取余之后除以10的结果。所以代码首先创建了全局变量,用于接收键盘输入的值,随后利用相关数学原理进行计算,之后将计算结果打印在屏幕上。

(5)时间转换

cpp 复制代码
#include <iostream>
using namespace std;
int time;
 
int main() 
{
 cin >> time;
 cout << time / 60 / 60 << " " << time / 60 % 60 << " " << time % 60 << 
endl; 
 return 0;
}

上述代码的具体解释:首先创建一个全局变量,输入一个值代表时间的秒数,随后根据生活常识将其化为时分秒,之后将计算结果打印在屏幕上。

(6)小鱼的游泳时间

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 int a, b, c, d;
 cin >> a >> b >> c >> d;
 int h, m;
 int t = c * 60 + d - a * 60 - b;//计算机出时间差,单位是分钟 
 h = t / 60;
 m = t % 60;
 cout << h << " " << m << endl;
 return 0;
}

上述代码的具体解释:这道题需要计算出a时b分到c时d分的时间差,所以首先将其分钟的时间差计算出来,之后再化成时分的形式,最后将计算结果打印在屏幕上。

六.赋值操作符

在变量创建时给一个值,这个动作叫做变量的初始化;之后给这个变量赋予其他值时,叫做赋值操作。

cpp 复制代码
int a = 100; //初始化 
a = 200; //赋值,这⾥使⽤的就是赋值操作符 

赋值操作的意思是:将等号右边的值赋予给左边的变量,这与数学上是不同的,要注意区分。

1.连续赋值

cpp 复制代码
//连续赋值(不推荐)
int a = 3;
int b = 5;
int c = 0;
c = b = a + 3; 
//推荐写法
int a = 3;
int b = 5;
int c = 0;
b = a + 3;
c = b;

上述连续赋值操作的意思是将a+3的值赋值给b,随后将b的值赋值给a。连续赋值的顺序和非连续赋值的顺序是相同的,都是从右向左赋值。但是不建议写成连续赋值的形式。因为那样赋值的话,代码的可读性降低了。不如间断的进行赋值,这样更好理解。

2.复合赋值符

cpp 复制代码
int a = 10;
a = a + 3;
a = a - 2;

int a = 10;
a += 3;
a -= 2;

如果要想像上述操作那样需要将变量进行自己自增自减后赋值给自己,就可以用到下方代码的复合赋值操作符,使代码更加简便。

|-------|---------|
| 复合赋值符 | 例子 |
| += | a+=10 |
| -= | a-=10 |
| *= | a*=10 |
| /= | a/=10 |
| %= | a%=10 |
| >>= | a>>=1 |
| <<= | a<<=1 |
| &= | a&=10 |
| |= | a|=10 |
| ^= | a^=10 |

3.练习

(1)账户余额

题目介绍:小明账户有100元,经过下面操作:存10元,花掉20元,将钱全部取出。请在每次操作后输出账户的余额。

cpp 复制代码
#include <iostream>
using namespace std;
int main() 
{ 
 int balance = 100;
 
 balance += 10;
 cout << balance << endl;
 
 balance -= 20;
 cout << balance << endl;
 
 balance = 0;
 cout << balance << endl;
 
 return 0; 
}

上述代码的具体解释:将余额初始化为100元,随后根据复合赋值符进行值的变化,每次变化将结果打印在屏幕上。

(2)交换值

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 int a = 0;
 int b = 0;
 cin >> a >> b;
 
 int c = a; //c是⼀个临时变量,作为中间变量实现交换的 
 a = b;
 b = c;
 cout << a << " " << b << endl;
 
 return 0;
}

上述代码需要将两个数的值进行交换,当然不能简单地将两个数值互相赋值。而应该引入新的变量,之间进行赋值的转换这样就可以得出交换后的情形。

七.类型转换

在使用C/C++语言写代码时,不同类型的数据进行混合计算时,或者赋值时等号两边的类型不统一时,都会发生类型转换,这个时候就需要根据类型转换的规则转换成合适的类型。

1.混合计算时的类型转换

字符、整数、浮点数可以混合计算,在这种情况下首先将不一致的数据类型进行转换,类型统一后才可以进行计算。这里边一般涉及两类转换:整型提升和算术转换。

整型提升:表达式之中的char和short类型一定会首先转换为int类型,然后参与运算。

算术转换:表达式中出现下面的任意两种类型的值进行计算的时候,需要先将下面的类型转换成另外一种类型才可以计算。这些转换都是隐式自发进行的,有些编译器会报警。

cpp 复制代码
long double
double
float
unsigned long int
long int
unsigned int
int
cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 //案例1 
 char a = 'a';
 int b = 10;
 char c = a + b; //这⾥a会发⽣整型提升,a+b的结果存放到c中,⼜发⽣截断 
 
 //案例2 
 int c = 10;
 double d = 3.14;
 double e = c + d; //c+d的时候,这⾥c会发⽣算数转换,转换为double类型 
 
 return 0;
}

2.赋值时类型转换

当赋值操作符两端的数据类型不一致时候,这时候就需要类型转换,这种转换也是隐式自动发生的。

  1. folat和double赋值给int时,直接截断小数部分,保留整数部分。
  2. 较小类型转换为较大类型时,直接转换值不变。
  3. 较大类型转换为较小类型时,一般会发生截断,按照较小类型的长度,保留低位数据给较小类型。

3.强制类型转换

在C/C++语言中,会有强制类型转换,可以根据实际的需要将某一数据类型转换为指定的数据类型,强制类型转换是临时转换的,不影响变量本身的类型,语法如下:

cpp 复制代码
//语法
//(类型名)表达式

//例子
double d = 3.14;
int a = (int)d;

上述代码的作用是:将3.14浮点类型的值强制类型转换为整型变量,所以a的值最终是3。

4.练习

(1)计算成绩

cpp 复制代码
#include <iostream>
using namespace std;
int a,b,c;
int ret;
int main()
{
 cin >> a >> b >> c;
 ret = (int)(a * 0.2 + b * 0.3 + c * 0.5);//这⾥进⾏了强制类型转换,如果不转换,也会⾃动转换的 
 cout << ret << endl;
 return 0;
}

上述代码输入三个值,随后根据相应的比例进行相加,最后利用强制类型转换将结果化为整数,打印在屏幕上。

(2)浮点数的向0舍入

cpp 复制代码
#include <iostream>
using namespace std;
double x;
int main()
{
 cin >> x;
 cout << (long long)x << endl;//题⽬给的数据较⼤,强制转换为int,存在漏洞  
 return 0;
}

上述代码需要将浮点类型的数据强制类型转换为整型数据,根据数据类型的取值范围,所以选择强制类型转换为long long。

(3)打印字符的ASCII码值

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 char c = 0;
 cin >> c;
 cout << (int)c <<endl; //如果没有强制类型转换,编译器会认为c是字符类型,打印的依然是字符 
 return 0;
}

将字符类型转换为整型,得到的结果就是该字符的ASCII码值。利用这一特性,可以将字符对应的ASCII码值打印在屏幕上。

(4)打印字符

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
 int n = 0;
 cin >> n;
 cout << (char)n <<endl; //利⽤强制类型转换,将ASCII码值按照字符类型打印 
 return 0;
}

这道题目与上道题目反其道而行之,目的是将ASCII码值转换为对应的字符类型。所以需要用到强制类型转换。

八.单目操作符

前面介绍的是双目操作符,也就是拥有两个操作数的意思。接下来,我们介绍单目操作符。

1.++和--

++是一种自增操作符,分为前置和后置;--是自减操作符符,也分为前置和后置。

注意:

  • 前置++和后置++都会使操作数自增1
  • 前置--和后置--都会使操作数自减1

(1)前置++和前置--

cpp 复制代码
//案例1 
int x = 10;
int a = ++x; //++的操作数是x,是放在x的前⾯的,就是前置++ 
cout << x << " " << a << endl;
//案例2 
int x = 10;
int a = x++; //++的操作数是x,是放在x的后⾯的,就是后置++ 
cout << x << " " << a << endl;

前置++:先自增1,随后调用该数的值。

前置--:先自减1,随后调用该数的值。

(2)后置++和后置--

cpp 复制代码
//案例1 
int y = 10;
int b = --y; //--的操作数是y,是放在y的前⾯的,就是前置-- 
cout << y << " " << b << endl;
//案例2 
int y = 10;
int b = y--; //--的操作数是y,是放在y的后⾯的,就是后置-- 
cout << y << " " << b << endl;

后置++:先调用该值,之后进行自增1。

后置--:先调用该值,之后进行自减1。

2.+和-

这里的+是正号,-是符号,也是单目运算符。

运算符+对正负值没有影响,是一个可以忽略的操作符,但是写了也完全没有任何问题。

cpp 复制代码
int a = +10; //等价于 int a = 10; 

运算符-可以用来改变一个值的正负,负数前面加上-就会得到正数;正数前面加上-就会得到负数。

cpp 复制代码
int a = 10;
int b = -a;
int c = -10;
cout << b << c << endl; //这⾥的b和c都是-10 
int a = -10;
int b = -a;
cout << b << endl; //这⾥的b是10 
相关推荐
Sheep Shaun1 小时前
深入理解AVL树:从概念到完整C++实现详解
服务器·开发语言·数据结构·c++·后端·算法
XH华2 小时前
备战蓝桥杯,第二章:C++语言的输入输出(上)
开发语言·c++·蓝桥杯
C++ 老炮儿的技术栈2 小时前
Qt中自定义 QmyBattery 电池组件开发
c语言·开发语言·c++·windows·qt·idea·visual studio
Howrun7772 小时前
Linux_C++_日志实例
linux·运维·c++
梵尔纳多2 小时前
第一个 3D 图像
c++·图形渲染·opengl
xiaoqider2 小时前
C++继承
开发语言·c++
YE1234567_2 小时前
从底层零拷贝到分布式架构:深度剖析现代 C++ 构建超大规模高性能 AI 插件引擎的实战之道
c++·分布式·架构
脏脏a2 小时前
C++ 容器的两把利器:优先级队列与反向迭代器
c++·反向迭代器·优先级队列
张张努力变强2 小时前
C++ 类和对象(三):拷贝构造函数与赋值运算符重载之核心实现
开发语言·c++