C++是一种静态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言、支持过程化编程、面向对象编程和泛型编程。
C++被认为是一种中级语言,它综合了高级语言和低级语言的特点。
C++是由 Bjarne Stroustrup于1979年在贝尔实验室开始设计开发的。C++进一步扩充和完善科C语言,最初命名为带类的C,后来在1983年更名为C++。
C++是C的一个超集,事实上,任何合法的C程序都是合法的C++程序。
注意: 使用静态类型的编程语言是在编译时执行类型检查,而不是在运行时执行类型检查。
C++完全支持面向对象的程序设计,包括面向对象开发的四大特性:
标准的C++有三个重要部分组成:
实例:
#include
using namespace std;
int main()
{
cout << "Hello,World!" << endl; //可以用"\n"代替代码里的endl
return 0;
}
注意: C++中"\n"与"endl"的区别:
“\n"表示内容为一个回车符的字符串。std::endl是流操作子,输出的作用和输出”\n"类似,但可能略有区别。
std::endl输出一个换行符,并立即刷新缓冲区。
例如:
std::cout << std::endl;
相当于:
std::cout << '\n' << std::flush;
或者
std::cout << '\n'; std::fflush(stdout);
由于流操作符 << 的重载,对于 ‘\n’ 和 “\n”,输出效果相同。
对于有输出缓冲的流(例如cout、clog),如果不手动进行缓冲区刷新操作,将在缓冲区满后自动刷新输出。不过对于 cout 来说(相对于文件输出流等),缓冲一般体现得并不明显。但是必要情况下使用 endl 代替 ‘\n’ 一般是个好习惯。
对于无缓冲的流(例如标准错误输出流cerr),刷新是不必要的,可以直接使用 ‘\n’。
如果想显示多行文本,如下:
#include
using namespace std;
int main()
{
cout<<"...............\n"
<<"Hello, world!\n"
<<"Welcome to c++\n"
<<"...............\n";
return 0;
}
不用一直这样cout多行输出。
C++程序可以定义为对象的集合,这些对象通过调用彼此的方法进行交互。
让我们来看一段简单的代码,可以输出单词Hello World。
实例:
#include
using namespace std;
//main()是程序开始执行的地方
int main()
{
cout <<"Hello World"; //输出Hello World
return 0;
}
接下来讲解一下上面这段代码:
在C++中,分号是语句结束符。也就是说,每个语句必须以分号结束。它表明一个逻辑实体的结束。
例如,下面是三个不同的语句:
x = y;
y = y+1;
add(x, y);
语句块是一组使用大括号括起来的按逻辑连接的语句。例如:
{
cout << "Hello World"; // 输出 Hello World
return 0;
}
C++不以行末作为结束符的标识,因此,可以在一行上放置多个语句。例如:
x = y;
y = y+1;
add(x, y);
等同于
x = y; y = y+1; add(x, y);
C++标识符是用来标识变量、函数、类、模块,或任何其他用户自定义项目的名称。一个标识符以字母A-Z或a-z或下划线_开始,后跟零个或多个字母、下划线和数字(0–9)。
C++标识符内不允许出现标点字符,比如@、&和%。C++是区分大小写的编程语言。因此,在C++中,Manpower和manpower是两个不同的标识符。
下面列出了几个有效的标识符:
mohd zara abc move_name a_123
myname50 _temp j a23b9 retVal
下表列出了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 |
三字符组就是用于表示另一个字符的三个字符序列,又称三字符序列。三字符序列总是以两个问号开头。
三字符序列不太常见,但C++标准允许把某些字符指定为三字符序列。以前为了表示键盘上没有的字符,这是必不可少的一种方法。
三字符序列可以出现在任何地方,包括字符串、字符序列、注释和预处理指令。
下面列出了最常见的三字符序列:
三字符组 | 替换 |
---|---|
??= | # |
??/ | \ |
??’ | ^ |
??( | [ |
??) | ] |
??! | l |
??< | { |
??> | } |
??- | ~ |
如果希望在源程序中有两个连续的问号,且不希望被预处理器替换,这种情况出现在字符常量、字符串字面值或者是程序注释中,可选办法使用字符串的自动连接:"…?""?..“或者转义序列:”…??.."。
只包含空格的行,被称为空白行,可能带有注释,C++编译器会完全忽略它。
在C++中,空格用于描述空白行、制表符、换行符和注释。空格分割语句的各个部分,让编译器能识别语句中的某个元素(比如int)在哪里结束,下一个元素在哪里开始。因此,在下面的语句中:
int age;
在这里,int和age之间必须至少有一个空格字符(通常是一个空白符),这样编译器才能够区分它们。另一方面,在下面的语句中:
fruit = apples + oranges; // 获取水果的总数
fruit和=,或者=和apples之间的空格字符不是必需的,但是为了增强可读性,可以根据需要适当增加一些空格。
C++中 int main() 和 int main(void) 的区别:
int main(void) 指的是次函数的参数为空,不能传入参数,如果你传入参数,就会出错。
int main() 表示可以传入参数。
// 这样是正确的
int main()
{
if (0) main(42);
}
// 这样会出错
int main(void)
{
if (0) main(42);
}
在C++中int main() 和 int main(void) 是等效的,但在C中让括号空着代表编译器对是否接受参数保持沉默。在C语言中main()省略返回类型也就相当说明返回类型为int型。
程序的注释是解释性语句,可以在C++代码中包含注释,这将提高代码的可读性。所有的编程语言都允许某种形式的注释。
C++支持单行注释和多行注释。主时钟所有字符会被C++编译器忽略。
C++注释以/开始,以/结束。例如:
/*这是注释*/
/*C++注释也可以
*跨行
*/
注释也能以//开始,知道行末为止。例如:
实例:
#include
using namespace std;
int main()
{
cout << "Hello World"; // 输出 Hello World
return 0;
}
当上面的代码被编译和执行时,编译器会忽略 //输出Hello World, 最后会产生以下结果:
Hello World
在/* 和 */注释内部,//字符没有特殊含义。在//注释内,/ * 和 */字符也没有特殊的含义。因此,可以再一种注释内嵌套另一种注释。例如:
/* 用于输出 Hello World 的注释
cout << "Hello World"; // 输出 Hello World
*/
此外,我们还可以使用#if 0 ... #endif
来实现注释,且可以实现嵌套,格式为:
#if 0
code
#endif
可以把#if 0
改成#if 1
来执行code的代码。
这种形式对程序调试也有帮助,测试时使用#if 1
来执行测试代码。发布后使用#if 0
来屏蔽测试代码。
#if后可以是任意的条件语句。
下面的代码如果condition条件为true执行code1,否则执行code2。
#if condition
code1
#else
code2
#endif
使用编程语言进行编程时,需要用到各种变量来存储各种信息。变量保留的是它所存储的值的内存位置。这意味着,当你创建一个变量时,就会在内存中保留一些空间。
可能序言存储各种数据类型(比如字符型、宽字符型、整型、浮点型、双浮点型、布尔型等)的信息,操作系统会根据变量的数据类型,来分配内存和决定在保留内存中存储什么。
C++为程序员提供了种类丰富的内置数据类型和用户自定义的数据类型。下表列出了其中基本的C++数据类型:
类型 | 关键字 |
---|---|
布尔型 | bool |
字符型 | char |
整型 | int |
浮点型 | float |
双浮点型 | double |
无类型 | void |
宽字符型 | wchar_t |
其实wchar_t是这样来的:
typedef short int wchar_t;
所以wchar_t实际上的空间是short int一样。
一些基本类型可以使用一个或多个类型修饰符进行修饰:
下表显示了各种变量类型在内存中存储值时需要占用的内存,以及该类型的变量所能存储的最大值和最小值。
注意: 不同系统之间有差异。
类型 | 位 | 范围 |
---|---|---|
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 个字节 | +/- 3.4e +/- 38 (~7 个数字) |
double | 8 个字节 | +/- 1.7e +/- 308 (~15 个数字) |
long double | 16 个字节 | +/- 1.7e +/- 308 (~15 个数字) |
wchar_t | 2 或 4 个字节 | 1 个宽字符 |
从上表可得知,变量的大小会根据编译器和所使用的的电脑而有所不同。
下面实例会输出你电脑上各种数据类型的大小。
实例:
#include
#include
#include
using namespace std;
int main()
{
cout << "type: \t\t" << "************size**************"<< endl;
cout << "bool: \t\t" << "所占字节数:" << sizeof(bool);
cout << "\t最大值:" << (numeric_limits::max)();
cout << "\t\t最小值:" << (numeric_limits::min)() << endl;
cout << "char: \t\t" << "所占字节数:" << sizeof(char);
cout << "\t最大值:" << (numeric_limits::max)();
cout << "\t\t最小值:" << (numeric_limits::min)() << endl;
cout << "signed char: \t" << "所占字节数:" << sizeof(signed char);
cout << "\t最大值:" << (numeric_limits::max)();
cout << "\t\t最小值:" << (numeric_limits::min)() << endl;
cout << "unsigned char: \t" << "所占字节数:" << sizeof(unsigned char);
cout << "\t最大值:" << (numeric_limits::max)();
cout << "\t\t最小值:" << (numeric_limits::min)() << endl;
cout << "wchar_t: \t" << "所占字节数:" << sizeof(wchar_t);
cout << "\t最大值:" << (numeric_limits::max)();
cout << "\t\t最小值:" << (numeric_limits::min)() << endl;
cout << "short: \t\t" << "所占字节数:" << sizeof(short);
cout << "\t最大值:" << (numeric_limits::max)();
cout << "\t\t最小值:" << (numeric_limits::min)() << endl;
cout << "int: \t\t" << "所占字节数:" << sizeof(int);
cout << "\t最大值:" << (numeric_limits::max)();
cout << "\t最小值:" << (numeric_limits::min)() << endl;
cout << "unsigned: \t" << "所占字节数:" << sizeof(unsigned);
cout << "\t最大值:" << (numeric_limits::max)();
cout << "\t最小值:" << (numeric_limits::min)() << endl;
cout << "long: \t\t" << "所占字节数:" << sizeof(long);
cout << "\t最大值:" << (numeric_limits::max)();
cout << "\t最小值:" << (numeric_limits::min)() << endl;
cout << "unsigned long: \t" << "所占字节数:" << sizeof(unsigned long);
cout << "\t最大值:" << (numeric_limits::max)();
cout << "\t最小值:" << (numeric_limits::min)() << endl;
cout << "double: \t" << "所占字节数:" << sizeof(double);
cout << "\t最大值:" << (numeric_limits::max)();
cout << "\t最小值:" << (numeric_limits::min)() << endl;
cout << "long double: \t" << "所占字节数:" << sizeof(long double);
cout << "\t最大值:" << (numeric_limits::max)();
cout << "\t最小值:" << (numeric_limits::min)() << endl;
cout << "float: \t\t" << "所占字节数:" << sizeof(float);
cout << "\t最大值:" << (numeric_limits::max)();
cout << "\t最小值:" << (numeric_limits::min)() << endl;
cout << "size_t: \t" << "所占字节数:" << sizeof(size_t);
cout << "\t最大值:" << (numeric_limits::max)();
cout << "\t最小值:" << (numeric_limits::min)() << endl;
cout << "string: \t" << "所占字节数:" << sizeof(string) << endl;
// << "\t最大值:" << (numeric_limits::max)() << "\t最小值:" << (numeric_limits::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: 所占字节数:2 最大值:65535 最小值:0
short: 所占字节数:2 最大值:32767 最小值:-32768
int: 所占字节数:4 最大值:2147483647 最小值:-2147483648
unsigned: 所占字节数:4 最大值:4294967295 最小值:0
long: 所占字节数:4 最大值:2147483647 最小值:-2147483648
unsigned long: 所占字节数:4 最大值:4294967295 最小值:0
double: 所占字节数:8 最大值:1.79769e+308 最小值:2.22507e-308
long double: 所占字节数:8 最大值:1.79769e+308 最小值:2.22507e-308
float: 所占字节数:4 最大值:3.40282e+38 最小值:1.17549e-38
size_t: 所占字节数:4 最大值:4294967295 最小值:0
string: 所占字节数:28
type: ************size**************
可以使用typedef为一个已有的类型去一个新的名字。下面是使用typedef定义一个新类型的语法:
typedef type newname;
例如:下面的语句会告诉编译器,feet是int的另一个名称:
typrdef int feet;
现在,下面的声明时完全合法的,它创建了一个整型变量distance:
feet distance;
枚举类型是C++中的一种派生数据类型,它是由用户定义的若干枚举常量的集合。
如果一个变量只有几种可能的值,可以定义为枚举类型。所谓“枚举”是指将变量的值一一列举出来,变量的值只能在列举出来的值的范围内。
创建枚举,需要使用关键字enum。枚举类型的一般形式为:
enum 枚举名{
标识符[=整型常数],
标识符[=整型常数],
...
标识符[=整型常数]
} 枚举变量;
如果枚举没有初始化,即省掉"=整型常数"时,则从第一个标识符开始。
例如,下面的代码定义了一个颜色枚举,变量c的类型为color。最后,c被赋值为"blue"。
enum color {red,green,blue}c;
c=blue;
默认情况下,第一个名称的值是0,第二个名称的值是2,第三个名称的值为2,以此类推。但是,也可以给名称赋予一个特殊的值,只需要添加一个初始值即可。例如,在下面的枚举中,green的值为5。
enum color {red,green=5,blue};
在这里,blue的值为6,因为默认情况下,每个名称都会比它前面一个名称大1,但red的值依然为0。
实例:
#include
using namespace std;
int main(){
enum days{one, two, three}day;
day = one;
switch(day){
case one:
cout << "one" << endl;
break;
case two:
cout << "two" << endl;
break;
default:
cout << "three" << endl;
break;
}
return 0;
}
但是,枚举类型不一定在main中定义:
#include
using namespace std;
enum time
{
first,second,
third,forth,fifth
};
int main()
{
enum time a=fifth;
if (a==fifth)
{
cout << "Succeed!";
}
return 0;
}
变量其实只不过是程序可操作性的存储区的名称,C++中每个变量都有指定的类型,类型决定了变量存储的大小和布局,该范围内的值都可以存储在内存中,运算符可应用在变量上。
变量的名称可以有字母、数字和下划线字符组成,它必须以字母或下划线开头。大写字母和小写字母是不同的,因为C++是大小写敏感的。
有以下几种基本的变量类型:
类型 | 描述 |
---|---|
bool | 存储值true或false。 |
char | 通常是一个字符(八位)。这是一个整数类型。 |
int | 对机器而言,整数的最自然的大小。 |
float | 单精度浮点值。单精度是这样的格式,1位符号,8位指数,23位小数。![]() |
double | 双精度浮点值。双精度是1位符号,11位指数,52位小数。![]() |
void | 表示类型的缺失。 |
wchar_t | 宽字符类型。 |
C++也允许定义各种其他类型的变量,比如枚举、指针、数组、引用、数据结构、类等等,
变量定义就是告诉编译器在何处创建变量的存储,以及如何创建变量的存储。变量定义指定一个数据类型,并包含了该类型的一个或多个变量的列表,如下所示:
type variable_list;
在这里,type必须是一个有效的C++数据类型,可以是char、wchar_t、int、float、double、bool或任何用户自定义的对象,variable_list可以有一个或多个标识符名称组成,多个标识符之间用逗号分隔。下面列出了几个有效的声明:
int i, j, k;
char c, ch;
float f, salary;
double d;
行int i,j,k; 声明并定义了变量i、j和k,这指示编译器创建类型为int的名为i、j、k的变量。
变量可以在声明的时候被初始化(指定一个初始值)。初始化器有一个等号,后跟一个常量表达式组成,如下所示:
type variable_name = value;
下面列举几个实例:
extern int d = 3, f = 5; // d 和 f 的声明
int d = 3, f = 5; // 定义并初始化 d 和 f
byte z = 22; // 定义并初始化 z
char x = 'x'; // 变量 x 的值为 'x'
不带初始化的定义:带有静态存储持续时间的变量会被隐式初始化为NULL(所有字节的值都是0),其他所有变量的初始值是未定义的。
变量声明向编译器保证变量以给定的类型和名称存在,这样编译器在不需要知道变量完整细节的情况下也能继续进一步的编译。变量声明只在编译时有它的意义,在程序连接时编译器需要实际的变量声明。
当使用多个文件且只在其中一个文件中定义变量时(定义变量的文件在程序连接时是可用的),变量声明就显得非常有用。可以使用extern关键字在任何地方声明一个变量。虽然可以再C++程序中多次声明一个变量,但变量只能在某个文件、函数或代码块中被定义一次。
实例:
下面的实例,其中,变量在头部就已经被声明,但它们是在主函数内被定义和初始化的:
#include
using namespace std;
// 变量声明
extern int a, b;
extern int c;
extern float f;
int main ()
{
// 变量定义
int a, b;
int c;
float f;
// 实际初始化
a = 10;
b = 20;
c = a + b;
cout << c << endl ;
f = 70.0/3.0;
cout << f << endl ;
return 0;
}
当上面的代码被编译和执行时,会产生下列结果:
30
23.3333
同样的,在函数声明时,提供一个函数名,而函数的实际定义则可以在任何地方进行。例如:
// 函数声明
int func();
int main()
{
// 函数调用
int i = func();
}
// 函数定义
int func()
{
return 0;
}
C++中有两种类型的表达式:
int g=20;
但是下面这个就不是一个有效的语句,会生成编译时错误:
10 = 20;
变量的类型间是可以互相转换的,转换又分为自动转换和强制转换。
自动转换规则:
int a=1;
double b=2.5;
a=b;
cout << a; //输出为 2,丢失小数部分
int a = 1;
double b = 2.1;
cout << "a + b = " << a + b << endl; //输出为a + b = 3.1
强制类型转换原则:
强制类型转换是通过类型转换运算来实现对的。其一般形式为:(类型说明符)(表达式),其功能是把表达式的运算结果强制转换成类型说明符所表示的类型
int a = 1;
double b = 2.1;
cout << "a + b = " << a + (int)b << endl; //输出为a + b = 3
作用域是程序的一个区域,一般来说有三个地方可以定义变量:
在函数或一个代码块内部声明的变量,称为局部变量。它们只能被函数内部或者代码块内部的语句使用。下面的实例使用了局部变量:
实例:
#include
using namespace std;
int main ()
{
// 局部变量声明
int a, b;
int c;
// 实际初始化
a = 10;
b = 20;
c = a + b;
cout << c;
return 0;
}
再所有函数外部定义的变量(通常是在程序的头部),称为全局变量。全局变量的值在程序的整个生命周期内都有效。
全局变量可以被任何函数访问。也就是说,全局变量一旦声明,在整个程序中都是可用的。下面的实例使用了全局变量和局部变量:
实例:
#include
using namespace std;
// 全局变量声明
int g;
int main ()
{
// 局部变量声明
int a, b;
// 实际初始化
a = 10;
b = 20;
g = a + b;
cout << g;
return 0;
}
在程序中,局部变量和全局变量的名称可以相同,但是在函数内,局部变量的值会覆盖全局变量的值。下面是一个实例:
#include
using namespace std;
// 全局变量声明
int g = 20;
int main ()
{
// 局部变量声明
int g = 10;
cout << g;
return 0;
}
当上面的代码被编译和执行时,会产生下列结果:
10
当局变量被定义时,系统不会对其初始化,必须自行对其初始化。定义全局变量时,系统会自动初始化为下列值:
数据类型 | 初始化默认值 |
---|---|
int | 0 |
char | ‘\0’ |
float | 0 |
double | 0 |
pointer | NULL |
正确地初始化变量是一个良好的编程习惯,否则有时候程序可能会产生意想不到的结果。
常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量。
常量可以是任何的基本数据类型,可分为整型数字、浮点数字、字符、字符串和布尔值。
常量就像是常规的变量,只不过常量的值在定义后不能进行修改。
整数常量可以是十进制、八进制或十六进制的常量。前缀指定基数:0x或0X表示十六进制,0表示八进制,不带前缀则默认表示十进制。
整数常量也可以带一个后缀,后缀是U和L的组合。U表示无符号整数,L表示长整数。后缀可以大写,也可以小写,U和L的顺序任意。
下面列举几个整数常量的实例:
212 // 合法的
215u // 合法的
0xFeeL // 合法的
078 // 非法的:8 不是八进制的数字
032UU // 非法的:不能重复后缀
以下是各种类型的整数常量的实例:
85 // 十进制
0213 // 八进制
0x4b // 十六进制
30 // 整数
30u // 无符号整数
30l // 长整数
30ul // 无符号长整数
浮点常量由整数部分、小数点、小数部分和指数部分组成。可以使用小数形式或指数形式来表示浮点常量。
当使用小数形式表示时,必须包含整数部分、小数部分、或同时包含两者。当使用指数形式表示时,必须包含小数点,指数,或同时包含两者。带符号的指数是用e或E引入的。
下面列举几个浮点常量的实例:
3.14159 // 合法的
314159E-5L // 合法的
510E // 非法的:不完整的指数
210f // 非法的:没有小数或指数
.e55 // 非法的:缺少整数或分数
布尔常量共有两个,它们都是标准的C++关键字:
字符常量是括在单引号中。如果常量以L开头,则表示它是一个宽字符常量(例如L’x’),此时它必须存储在wchar_t类型的变量中。否则,它就是一个窄字符常量(例如’x’),此时它可以存储在char类型的简单变量中。
字符常量可以是一个普通的字符(例如’x’)、一个转义序列(例如’\t’),或一个通用字符(例如’\u02c0’)。
在C++中,有一些特定的字符,当它们前面有反斜杠时,它们就具有特殊的含义,被用来表示如换行符(\n)或制表符(\t)等。下表列出了一些这样的转义序列码:
转义序列 | 含义 |
---|---|
\ | \ 字符 |
’ | ’ 字符 |
" | " 字符 |
? | ? 字符 |
\a | 警报铃声 |
\b | 退格键 |
\f | 换页符 |
\n | 换行符 |
\r | 回车 |
\t | 水平制表符 |
\v | 垂直制表符 |
\ooo | 一到三位的八进制数 |
\xhh . . . | 一个或多个数字的十六进制数 |
下面的实例显示了一些转义序列字符:
实例:
#include
using namespace std;
int main()
{
cout << "Hello\tWorld\n\n";
return 0;
}
当上面的代码被编译和执行时,会产生下列结果:
Hello World
字符串字面值或常量时括在双引号""中的,一个字符串包含类似于字符常量的字符:普通的字符、转义字符和通用的字符。
可以使用空格做分隔符,把一个很长的字符串常量进行分行。
下面的实例显示了一些字符串常量。下面这三种形式所显示的字符串是相同的。
"hello, dear"
"hello, \
dear"
"hello, " "d" "ear"
在C++中,有两种简单的定义常量的方式:
下面是使用#define预处理器定义常量的形式:
#define identifier value
具体看下面的实例:
#include
using namespace std;
#define LENGTH 10
#define WIDTH 5
#define NEWLINE '\n'
int main()
{
int area;
area = LENGTH * WIDTH;
cout << area;
cout << NEWLINE;
return 0;
}
当上面的代码被编译和执行时,会产生下列结果:
50
可以使用const前缀声明指定类型的常量,如下所示:
const type variable = value;
实例:
#include
using namespace std;
int main()
{
const int LENGTH = 10;
const int WIDTH = 5;
const char NEWLINE = '\n';
int area;
area = LENGTH * WIDTH;
cout << area;
cout << NEWLINE;
return 0;
}
当上面的代码被编译和执行时,会产生下列结果:
50
注意:把常量定义为大写字母形式,是一个很好的编程实践。
C++允许在char、int和double数据类型前放置修饰符。修饰符用于改变基本类型的含义,所以它能满足各种情境的需求。
下面列出了数据类型修饰符:
unsigned x;
unsigned int y;
为了理解C++解释有符号整数和无符号整数修饰符之间的差别,请看下面的实例:
#include
using namespace std;
/*
- 这个程序演示了有符号整数和无符号整数之间的差别
*/
int main()
{
short int i; // 有符号短整数
short unsigned int j; // 无符号短整数
j = 50000;
i = j;
cout << i << " " << j;
return 0;
}
当上面的程序运行时,会输出下列结果:
-15536 50000
上述结果中,无符号短整数50000的位模式被解释为有符号短整数-15536
类型限定符提供了变量的额外信息。
限定符 | 含义 |
---|---|
const | const类型的对象在程序执行期间不能被改变。 |
volatile | 修饰符volatile告诉编译器不需要优化volatile声明的变量,让程序可以直接从内存中读取变量。对于一般的变量编译器会对变量进行优化,将内存中的变量值存放在寄存器中以加快读取效率。 |
restrict | 有restrict修饰的指针是唯一一种访问它所指向的对象的方式。只有C99增加了新的类型限定符restrict。 |
存储类定义C++程序中变量/函数的范围(可见性)和生命周期。这些说明符放置在它们所修饰的类型之前。下面列出C++程序中可用的存储类:
自C++11以来,auto关键字用于两种情况:生命变量时根据初始化表达式自动推动该变量的类型、声明函数时返回值的占位符。
C++98标准中auto关键字用于自动变量的声明,但由于使用极少且多余,且在C++11中已经删除这一用法。
根据初始化表达式自动推断被声明的变量的类型,如:
auto f=3.14; //double
auto s("hello"); //const char*
auto z = new auto(9); // int*
auto x1 = 5, x2 = 5.0, x3='r';//错误,必须是初始化为同一类型
register存储类用于定义存储在寄存器中而不是RAM中的局部变量。这意味着变量的最大尺寸等于寄存器的大小(通常是一个词),且不能对它应用一元的’&'运算符(因为它没有内存位置)。
{
register int miles;
}
寄存器只用于需要快速访问的变量,比如计数器。还应注意的是,定义’register’并不意味着变量将被存储在寄存器中,它意味着变量可能存储在寄存器中,这取决了硬件和实现的限制。
static存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用static修饰局部变量可以再函数调用之间保持局部变量的值。
static修饰符也可以应用于全局变量。当static修饰全局变量时,会使变量的作用域限制在声明它的文件内。
在C++中,当static用在类数据成员上时,会导致仅有一个该成员的副本被类的所有对象共享。
实例:
#include
// 函数声明
void func(void);
static int count = 10; /* 全局变量 */
int main()
{
while(count--)
{
func();
}
return 0;
}
// 函数定义
void func( void )
{
static int i = 5; // 局部静态变量
i++;
std::cout << "变量 i 为 " << i ;
std::cout << " , 变量 count 为 " << count << std::endl;
}
当上面的代码被编译和执行时,会产生下列结果:
变量 i 为 6 , 变量 count 为 9
变量 i 为 7 , 变量 count 为 8
变量 i 为 8 , 变量 count 为 7
变量 i 为 9 , 变量 count 为 6
变量 i 为 10 , 变量 count 为 5
变量 i 为 11 , 变量 count 为 4
变量 i 为 12 , 变量 count 为 3
变量 i 为 13 , 变量 count 为 2
变量 i 为 14 , 变量 count 为 1
变量 i 为 15 , 变量 count 为 0
注意:std::cout << "Count is " << count << std::endl;
在前面的学习的代码中没有std::,而在这一节出现了上面的代码。std是标准库函数使用的命名空间。using namespace std它声明了命名空间std这样就可以使用 cin、cout、vector等。 假设你不使用预处理 using namespace std;,就要加上 std::cin 或者 std::cout。
cin 用于从控制台获取用户输入,cout 用于将数据输出到控制台。
cin 是输入流对象,cout 是输出流对象,它们分别可以用 >> 和 <<,是因为分别在其类中对相应运算符进行了重载。
extern存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。当你使用’extern’时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。
当你有多个文件且定义了一个可以在其他文件中使用extern来得到已定义的变量或函数的引用。可以这么理解,extern是用来在另一个文件中声明一个全局变量或函数。
extern修饰符通常用于当有两个或多个文件共享相同的全局变量或函数时,如下所示:
第一个文件:main.cpp
#include
int count ;
extern void write_extern();
int main()
{
count = 5;
write_extern();
}
第二个文件:support.cpp
#include
extern int count;
void write_extern(void)
{
std::cout << "Count is " << count << std::endl;
}
在这里,第二个文件中的extern关键字用于声明已经在第一个文件main.cpp中定义的count。现在,编译这两个文件,如下所示:
Count is 5
mutable说明符仅适用于类的对象,它允许对象的成员替代常量。也就是说,mutable成员可以通过const成员函数修改。
使用thread_local说明符声明的变量仅可在它创建的线程上访问。变量在创建线程时创建,并在销毁线程时销毁。每个线程都有其自己的变量副本。
thread_local说明符可以与static或extern合并。
可以将thread_local仅用于数据声明与定义,thread_local不能用于函数声明或定义。
以下演示了可以被声明为thread_local的变量:
thread_local int x; // 命名空间下的全局变量
class X
{
static thread_local std::string s; // 类的static成员变量
};
static thread_local std::string X::s; // X::s 是需要定义的
void foo()
{
thread_local std::vector v; // 本地变量
}
运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。C++内置了丰富的运算符,并提供以下类型的运算符:
下表显示了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 |
自增运算符++会把操作数加1,自减运算符- -会把操作数减1.因此:
x = x+1;
等同于
x++;
同样的:
x = x-1;
等同于
x--;
无论是自增运算符还是自减运算符,都可以放在操作数的前面(前缀)或后面(后缀)。例如:
x = x+1;
可以写成:
++x; // 前缀形式
或者:
x++; // 后缀形式
前缀形式和后缀形式之间有一点不同。如果使用前缀形式,则会在表达式计算之前完成自增或自减,如果使用后缀形式,则会在表达式计算之后完成自增或自减。
自增运算符++会把操作数加1,自减运算符- - 会把操作数减1.因此:
x = x+1;
等同于
x++;
同样的:
x = x-1;
等同于
x--;
无论是自增运算符还是自减运算符,都可以放在操作数的前面(前缀)或后面(后缀)。例如:
x = x+1;
可以写成:
++x; // 前缀形式
或者:
x++; // 后缀形式
前缀形式与后缀形式之间有一点不同。如果使用前缀形式,则会在表达式计算之前完成自增或自减,如果使用后缀形式,则会在表达式计算之后完成自增或自减。
实例:
#include
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;
}
当上面的代码被编译和执行时,会产生下列结果:
Line 1 - c 的值是 31
Line 2 - c 的值是 11
Line 3 - c 的值是 210
Line 4 - c 的值是 2
Line 5 - c 的值是 1
Line 6 - c 的值是 10
Line 7 - c 的值是 10
下表显示了C++支持的关系运算符。
假设变量A的值为10,变量B的值为20,则:
运算符 | 描述 | 实例 |
---|---|---|
== | 检查两个操作数是否相等,如果相等则条件为真。 | (A==B)不为真。 |
!= | 检查两个操作数的值是否相等,如果不相等则条件为真 | (A!=B)为真。 |
> | 检查左操作数的值是否大于右操作数的值,如果是则条件为真。 | (A>B)不为真。 |
< | 检查左操作数的值1是否小于右操作数的值,如果是则条件为真。 | (A < B) 为真。 |
>= | 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真。 | (A >= B) 不为真。 |
<= | 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真。 | (A <= B) 为真。 |
实例:
注意下面的实例,编译并运行程序:
#include
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;
}
当上面的代码被编译和执行时,会产生下列结果:
Line 1 - a 不等于 b
Line 2 - a 不小于 b
Line 3 - a 大于 b
Line 4 - a 小于或等于 b
Line 5 - b 大于或等于 a
下表显示了C++支持的关系逻辑运算符。
假设变量A的值为1,变量B的值为0,则:
运算符 | 描述 | 实例 |
---|---|---|
&& | 称为逻辑与运算符。如果两个操作数都非零,则条件为真。 | (A&&B)为假。 |
ll | 称为逻辑或运算符。如果两个操作数中有任意一个非零,则条件为真。 | (AllB)为真。 |
! | 称为逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假。 | !(A&&B)为真 |
实例:
看下面的实例,编译并执行程序:
#include
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;
}
当上面的代码被编译和执行时,会产生下列结果:
Line 1 - 条件为真
Line 2 - 条件为真
Line 4 - 条件不为真
Line 5 - 条件为真
位运算符作用于位,并逐位执行操作。&、l和^的真值表如下:
p | q | p&q | plq | p^q |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
假设如果 A = 60,且 B = 13,现在以二进制格式表示,它们如下所示:
A = 0011 1100
B = 0000 1101
A&B = 0000 1100
A|B = 0011 1101
A^B = 0011 0001
~A = 1100 0011
下表显示了 C++ 支持的位运算符。假设变量 A 的值为 60,变量 B 的值为 13,则:
运算符 | 描述 | 实例 |
---|---|---|
& | 如果同时存在于两个操作数中,二进制 AND 运算符复制一位到结果中。 | (A & B) 将得到 12,即为 0000 1100 |
l | 如果存在于任一操作数中,二进制 OR 运算符复制一位到结果中。 | (A l B) 将得到 61,即为 0011 1101 |
^ | 如果存在于其中一个操作数中但不同时存在于两个操作数中,二进制异或运算符复制一位到结果中。 | (A ^ B) 将得到 49,即为 0011 0001 |
~ | 二进制补码运算符是一元运算符,具有"翻转"位效果,即0变成1,1变成0。 | (~A ) 将得到 -61,即为 1100 0011,一个有符号二进制数的补码形式。 |
<< | 二进制左移运算符。左操作数的值向左移动右操作数指定的位数。 | A << 2 将得到 240,即为 1111 0000 |
>> | 二进制右移运算符。左操作数的值向右移动右操作数指定的位数。 | A >> 2 将得到 15,即为 0000 1111 |
实例:
#include
using namespace std;
int main()
{
unsigned int a = 60; // 60 = 0011 1100
unsigned int b = 13; // 13 = 0000 1101
int c = 0;
c = a & b; // 12 = 0000 1100
cout << "Line 1 - c 的值是 " << c << endl ;
c = a | b; // 61 = 0011 1101
cout << "Line 2 - c 的值是 " << c << endl ;
c = a ^ b; // 49 = 0011 0001
cout << "Line 3 - c 的值是 " << c << endl ;
c = ~a; // -61 = 1100 0011
cout << "Line 4 - c 的值是 " << c << endl ;
c = a << 2; // 240 = 1111 0000
cout << "Line 5 - c 的值是 " << c << endl ;
c = a >> 2; // 15 = 0000 1111
cout << "Line 6 - c 的值是 " << c << endl ;
return 0;
}
当上面的代码被编译和执行时,会产生下列结果:
Line 1 - c 的值是 12
Line 2 - c 的值是 61
Line 3 - c 的值是 49
Line 4 - c 的值是 -61
Line 5 - c 的值是 240
Line 6 - c 的值是 15
下表列出了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 |
l= | 按位或且赋值运算符 | C l= 2 等同于 C = C l 2 |
实例:
#include
using namespace std;
int main()
{
int a = 21;
int c ;
c = a;
cout << "Line 1 - = 运算符实例,c 的值 = : " <>= 2;
cout << "Line 8 - >>= 运算符实例,c 的值 = : " <
当上面的代码被编译和执行时,会产生下列结果:
Line 1 - = 运算符实例,c 的值 = 21
Line 2 - += 运算符实例,c 的值 = 42
Line 3 - -= 运算符实例,c 的值 = 21
Line 4 - *= 运算符实例,c 的值 = 441
Line 5 - /= 运算符实例,c 的值 = 21
Line 6 - %= 运算符实例,c 的值 = 11
Line 7 - <<= 运算符实例,c 的值 = 44
Line 8 - >>= 运算符实例,c 的值 = 11
Line 9 - &= 运算符实例,c 的值 = 2
Line 10 - ^= 运算符实例,c 的值 = 0
Line 11 - |= 运算符实例,c 的值 = 2
下表列出了C++支持的其他一些重要的运算符。
运算符 | 描述 |
---|---|
sizeof | sizeof 运算符返回变量的大小。例如,sizeof(a) 将返回 4,其中 a 是整数。 |
Condition ? X : Y | 条件运算符。如果 Condition 为真 ? 则值为 X : 否则值为 Y。 |
, | 逗号运算符会顺序执行一系列运算。整个逗号表达式的值是以逗号分隔的列表中的最后一个表达式的值。 |
.(点)和 ->(箭头) | 成员运算符用于引用类、结构和共用体的成员。 |
Cast | 强制转换运算符把一种数据类型转换为另一种数据类型。例如,int(2.2000) 将返回 2。 |
& | 指针运算符 & 返回变量的地址。例如 &a; 将给出变量的实际地址。 |
* | 指针运算符 * 指向一个变量。例如,*var; 将指向变量 var。 |
sizeof是一个关键字,它是一个编译时运算符,用于判断变量或数据类型的字节大小。
sizeof运算符可用于获取类、结构、共用体和其他用于自定义数据类型的大小。
使用sizeof的语法如下:
sizeof (data type)
其中,data type是要计算大小的数据类型,包括类、结构、共用体和其他用户自定义数据类型。
实例:
#include
using namespace std;
int main()
{
cout << "Size of char : " << sizeof(char) << endl;
cout << "Size of int : " << sizeof(int) << endl;
cout << "Size of short int : " << sizeof(short int) << endl;
cout << "Size of long int : " << sizeof(long int) << endl;
cout << "Size of float : " << sizeof(float) << endl;
cout << "Size of double : " << sizeof(double) << endl;
cout << "Size of wchar_t : " << sizeof(wchar_t) << endl;
return 0;
}
当上面的代码被编译和执行时,会产生下列结果,结果会根据使用的机器而有所不同:
Size of char : 1
Size of int : 4
Size of short int : 2
Size of long int : 4
Size of float : 4
Size of double : 8
Size of wchar_t : 4
Exp1 ? Exp2 : Exp3;
其中,Exp1、Exp2和Exp3是表达式。注意冒号的使用和位置。?:表达式的值取决于 Exp1的计算结果。如果Exp1为真,则计算Exp2的值,且Exp2的计算结果为整个?:表达式的值。如果Exp1为真,则计算Exp2的值,且Exp2的计算结果则为整个?:表达式的值。如果Exp1为假,则计算Exp3的值,且Exp3的计算结果为整个?:表达式的值。
?被称为三元运算符,因为它需要三个操作数,可以用来代替如下所示的if–else语句:
if(condition){
var = X;
}else{
var = Y;
}
例如:
if(y < 10){
var = 30;
}else{
var = 40;
}
上面的代码可以写成下列形式:
var = (y < 10) ? 30 : 40;
在这里,如果y小于10,则var被赋值为30,如果y不小于10,则var被赋值为40。看下面实例:
#include
using namespace std;
int main ()
{
// 局部变量声明
int x, y = 10;
x = (y < 10) ? 30 : 40;
cout << "value of x: " << x << endl;
return 0;
}
当上面的代码被编译和执行时,会产生下列结果:
value of x: 40
使用逗号运算符是为了把几个表达式放在一起。
整个逗号表达式的值为系列中最后一个表达式的值。
从本质上来讲,逗号的作用是将一系列运算按顺序执行。
最右边的那个表达式的值将作为整个逗号表达式的值,其他表达式的值将会被抛弃。例如:
var = (count=19, incr=10, count+1);
在这里,首先把count赋值为19,把incr赋值为10,然后把count加1,最后,把最右边表达式count+1的计算结果20赋给var。上面表达式中的括号时必须的,因为逗号运算符的优先级低于赋值操作符。
实例:
#include
using namespace std;
int main()
{
int i, j;
j = 10;
i = (j++, j+100, 999+j);
cout << i;
return 0;
}
当上面的代码被编译和执行时,会产生下列结果:
1010
.(点)运算符和 ->(箭头)运算符用于引用类、结构和共用体的成员。
点运算符应用于实际对象。箭头运算符与一个指向对象的指针一起使用。例如,假设有下面的结构:
struct Employee {
char first_name[16];
int age;
} emp;
下面的代码把值"zara"赋给对象emp的first_name成员:
strcpy(emp.first_name, "zara");
如果p_emp是一个指针,指向类型为Employee的对象,则要把值"zara"赋给对象emp的first_name成员,需要编写下面代码:
strcpy(p_emp->first_name, "zara");
->称为箭头运算符,它有一个减号加上一个大于符号组成。
简而言之,访问架构的成员是使用点运算符,而通过指针访问结构的成员时,则使用箭头运算符。
强制转换运算符是一种特殊的运算符,它把一种数据类型转换为另一种数据类型。强制转换运算符是一元运算符,它的优先级与其他一元运算符相同。
大多数的C++编译器都支持大部分通用的强制转换运算符:
(type) expression
其中,type是转换后的数据类型。下面列出了C++支持的其他几种强制转换运算符:
#include
using namespace std;
int main()
{
double a = 21.09399;
float b = 10.20;
int c ;
c = (int) a;
cout << "Line 1 - Value of (int)a is :" << c << endl ;
c = (int) b;
cout << "Line 2 - Value of (int)b is :" << c << endl ;
return 0;
}
当上面的代码被编译和执行时,会产生下列结果:
Line 1 - Value of (int)a is :21
Line 2 - Value of (int)b is :10
C++提供了两种指针运算符,一种是取地址运算符&,一种是间接寻址运算符 *。
指针是一个包含了另一个变量地址的变量,可以把一个包含了另一个变量地址的变量说成是"指向"另一个变量。变量可以是任意的数据类型,包括对象、结构和指针。
&是一元运算符,返回操作数的内存地址,例如,如果var是一个整型变量,则&var是它的地址。该运算符与其他一元运算符具有相同的优先级,在运算时它是从左向右的顺序进行的。
可以把&运算符读作"取地址运算符",这意味着,&var读作"var的地址"。
第二个运算符是间接寻址运算符 *,它是&运算符的补充。 *是一元运算符,返回操作数所指定地址的变量的值。
实例:
#include
using namespace std;
int main ()
{
int var;
int *ptr;
int val;
var = 3000;
// 获取 var 的地址
ptr = &var;
// 获取 ptr 的值
val = *ptr;
cout << "Value of var :" << var << endl;
cout << "Value of ptr :" << ptr << endl;
cout << "Value of val :" << val << endl;
return 0;
}
当上面的代码被编译和执行时,会产生下列结果:
Value of var :3000
Value of ptr :0xbff64494
Value of val :3000
运算符的优先级确定表大会中项的组合。这会影响到一个表达式如何计算。某些运算符比其他运算符有更高的优先级,例如,乘除运算符具有比加减运算符更高的优先级。
例如x=7+3 * 2,在这里,x被赋值为13,而不是20,因为运算符 * 具有比+更高的优先级,所以首先计算乘法3*2,然后再加上7。
下表将按运算符的优先级从高到低列出各个运算符,具有较高优先级的运算符出现在表格上面,具有较低优先级的运算符出现在表格下面。在表达式中,较高优先级的运算符会优先被计算。
类别 | 运算符 | 结合性 |
---|---|---|
后缀 | () [] -> . ++ - - | 从左到右 |
一元 | + - ! ~ ++ - - (type)* & sizeof | 从右到左 |
乘除 | * / % | 从左到右 |
加减 | + - | 从左到右 |
移位 | << >> | 从左到右 |
关系 | < <= > >= | 从左到右 |
相等 | == != | 从左到右 |
位与 AND | & | 从左到右 |
位异或 XOR | ^ | 从左到右 |
位或 OR | l | 从左到右 |
逻辑与 AND | && | 从左到右 |
逻辑或 OR | ll | 从左到右 |
条件 | ?: | 从右到左 |
赋值 | = += -= *= /= %=>>= <<= &= ^= | = |
逗号 | , | 从左到右 |
实例:
对比有括号和没有括号时的区别,这将产生不同的结果。因为()、/、*和+有不同的优先级,高优先级的操作符将优先计算。
#include
using namespace std;
int main()
{
int a = 20;
int b = 10;
int c = 15;
int d = 5;
int e;
e = (a + b) * c / d; // ( 30 * 15 ) / 5
cout << "(a + b) * c / d 的值是 " << e << endl ;
e = ((a + b) * c) / d; // (30 * 15 ) / 5
cout << "((a + b) * c) / d 的值是 " << e << endl ;
e = (a + b) * (c / d); // (30) * (15/5)
cout << "(a + b) * (c / d) 的值是 " << e << endl ;
e = a + (b * c) / d; // 20 + (150/5)
cout << "a + (b * c) / d 的值是 " << e << endl ;
return 0;
}
当上面的代码被编译和执行时,会产生下列结果:
(a + b) * c / d 的值是 90
((a + b) * c) / d 的值是 90
(a + b) * (c / d) 的值是 90
a + (b * c) / d 的值是 50
注意:
& :只有2个都为1,那么结果是1,否则为0;例如:1&1=1,1&0=0,0&0=0,0&1=0;
11 & 3 = 3
00001011
& 00000011
= 00000011 = 3
| :只要有一个是1,那么结果为1,否则为0;例如:1&1=1,1&0=1,0&0=0,0&1=1;
11 | 3 = 11
00001011
| 00000011
= 00001011 = 11
>> :向右位移,就是把尾数去掉位数,例如:153 >> 2,153的二进制是:10011001,屁股后面去掉 2 位 100110,100110 转化成十进制就是 38,153 = 10011001,38 =100110,“01” 去掉了。
<< :向左位移,就是把开头两位数去掉,尾数加位数00,例如:
107 = 0110 1011 <<2
<<
172 = 1010 1100
在计算机中由于是32位的
107 = 0000 0000 0000 0000 0000 0000 0110 1011 <<2
<<
428 = 0000 0000 0000 0000 0000 0001 1010 1100
^ :两个相同的数会变成0,反之是1,例如:1&1=0,1&0=1,0&0=0,0&1=1;
11^3 = 8
00001011
^ 00000011
= 00001000 = 8
有的时候,可能需要多次执行同一块代码。一般情况下,语句是顺序执行的:函数中的第一个语句限制性,接着是第二个语句,依次类推。
编程语言提供了允许更为复杂的执行路径的多种控制结构。
循环语句允许我们多次执行一个语句或语句组,下面是大多数编程语言中循环语句的一般形式:
C++编程语言提供了一下几种循环类型。
循环类型 | 描述 |
---|---|
while循环 | 当给定条件为真时,重复语句或语句组。它会在执行循环主体之前测试条件。 |
for循环 | 多次执行一个语句序列,简化管理循环变量的代码。 |
do…while循环 | 除了它是在循环主体结尾测试条件外,其他与while语句类似。 |
嵌套循环 | 可以再while、for或do…while循环内使用一个或多个循环。 |
只要给定条件为真,while循环语句会重复执行一个木匾语句。
C++中while循环的语法:
while(condition)
{
statement(s);
}
在这里,statement(s) 可以是一个单独的语句,也可以是几个语句组成的代码块。condition可以是任意的表达式,当为任意非零值时都为真。当条件为真时执行循环。
当条件为假时,程序流将继续执行紧接着循环的下一条语句。
流程图
在这里,while循环的关键点是循环可能一次都不会执行。当条件被测试且结果为假时,会跳过循环主体,直接执行紧接着while循环的下一条语句。
实例:
#include
using namespace std;
int main ()
{
// 局部变量声明
int a = 10;
// while 循环执行
while( a < 20 )
{
cout << "a 的值:" << a << endl;
a++;
}
return 0;
}
当上面的代码被编译和执行时,会产生下列结果:
a 的值: 10
a 的值: 11
a 的值: 12
a 的值: 13
a 的值: 14
a 的值: 15
a 的值: 16
a 的值: 17
a 的值: 18
a 的值: 19
for循环允许编写一个执行特定次数的循环的重复控制结构。
C++中for循环的语法:
for ( init; condition; increment )
{
statement(s);
}
下面是for循环的控制流:
#include
using namespace std;
int main()
{
//for循环执行
for(int a=10;a<20;a=a+1)
{
cout<<"a的值:"<
当上面的代码被编译和执行时,会产生下列结果:
a 的值: 10
a 的值: 11
a 的值: 12
a 的值: 13
a 的值: 14
a 的值: 15
a 的值: 16
a 的值: 17
a 的值: 18
a 的值: 19
基于范围的for循环
for语句允许简单的范围迭代:
int my_array[5]={1,2,3,4,5};
//每个数组元素乘以2
for(int &x:my_array)
{
x*=2;
cout<
上面for语句的第一部分定义被用来做范围迭代的变量,就像被声明在一般for循环的变量一样,其作用域仅只于循环的范围。而在":"之后的第二区块,代表将被迭代的范围。
实例:
#include
#include
#include
using namespace std;
int main()
{
string str("some string");
// range for 语句
for(auto &c : str)
{
c = toupper(c);
}
cout << str << endl;
return 0;
}
上面的程序使用Range for语句遍历一个字符串,并将所有字符全部变为大写,然后输出结果为:
SOME STRING
不想for和while循环,它们是在循环头部测试循环条件。do…while循环是在循环的尾部检查它的条件。
do…while循环与while循环会确保至少执行一次循环。
C++中do…while循环的语法:
do
{
statement(s);
}while(condition);
请注意,条件表达式出现在循环的尾部,所以循环中的statement(s)会在条件被测试之前至少执行一次。
如果条件为真,控制流会跳转回上面的do,然后重新执行循环中的statement(s)。这个过程会不断重复,知道给定条件变为假为止。
流程图
实例:
#include
using namespace std;
int main ()
{
// 局部变量声明
int a = 10;
// do 循环执行
do
{
cout << "a 的值:" << a << endl;
a = a + 1;
}while( a < 20 );
return 0;
}
当上面的代码被编译和执行时,会产生下列结果:
a 的值: 10
a 的值: 11
a 的值: 12
a 的值: 13
a 的值: 14
a 的值: 15
a 的值: 16
a 的值: 17
a 的值: 18
a 的值: 19
一个循环内可以嵌套另一个循环。C++允许至少256个嵌套层次。
C++中嵌套for循环语句的语法:
for ( init; condition; increment )
{
for ( init; condition; increment )
{
statement(s);
}
statement(s); // 可以放置更多的语句
}
C++中嵌套while循环语句的语法:
while(condition)
{
while(condition)
{
statement(s);
}
statement(s); // 可以放置更多的语句
}
C++中嵌套do…while循环语句的用法:
do
{
statement(s); // 可以放置更多的语句
do
{
statement(s);
}while( condition );
}while( condition );
关于嵌套循环有一点值得注意,可以再任何类型的循环内嵌套其他任何类型的循环。比如,一个for循环可以嵌套在一个while循环内,反之亦然。
实例:
下面的程序使用了一个嵌套的for循环来查找2到100中的质数:
#include
using namespace std;
int main ()
{
int i, j;
for(i=2; i<100; i++) {
for(j=2; j <= (i/j); j++) {
if(!(i%j)) {
break; // 如果找到,则不是质数
}
}
if(j > (i/j)) {
cout << i << " 是质数\n";
}
}
return 0;
}
上面的代码被编译和执行时,会产生下列结果:
2 是质数
3 是质数
5 是质数
7 是质数
11 是质数
13 是质数
17 是质数
19 是质数
23 是质数
29 是质数
31 是质数
37 是质数
41 是质数
43 是质数
47 是质数
53 是质数
59 是质数
61 是质数
67 是质数
71 是质数
73 是质数
79 是质数
83 是质数
89 是质数
97 是质数
循环控制语句更改执行的正常序列。当执行离开一个范围时,所有在该范围中创建的自动对象都会被销毁。
C++提供下列的控制语句。
控制语句 | 描述 |
---|---|
break语句 | 终止loop或switch语句,程序流将继续执行紧接着loop或switch的下一条语句。 |
continue语句 | 引起循环跳过主体的剩余部分,立即重新开始测试条件。 |
goto语句 | 将控制转移到被标记的语句,但是不建议在程序中使用goto语句。 |
C++中break语句有以下两种用法:
C++中break语句的语法:
break;
#include
using namespace std;
int main ()
{
// 局部变量声明
int a = 10;
// do 循环执行
do
{
cout << "a 的值:" << a << endl;
a = a + 1;
if( a > 15)
{
// 终止循环
break;
}
}while( a < 20 );
return 0;
}
当上面的代码被编译和执行时,会产生下列结果:
a 的值: 10
a 的值: 11
a 的值: 12
a 的值: 13
a 的值: 14
a 的值: 15
C++中的continue语句有点像break语句。但它不是强迫终止,continue会跳过当前循环中的代码,强迫开始下一次循环。
对于for循环,continue语句会导致执行条件测试和循环增量部分。对于while和do…while循环,continue语句会导致程序控制回到条件测试上。
C++中的continue语句的语法:
continue;
#include
using namespace std;
int main()
{
//局部变量声明
int a = 10;
//do循环执行
do
{
if (a == 15)
{
//跳过迭代
a = a + 1;
continue;
}
cout << "a的值:" << a << endl;
a = a + 1;
} while (a < 20);
return 0;
}
当上面的代码被编译和执行时,会产生下列结果:
a 的值: 10
a 的值: 11
a 的值: 12
a 的值: 13
a 的值: 14
a 的值: 16
a 的值: 17
a 的值: 18
a 的值: 19
goto语句允许把控制无条件转义到同一函数内的被标记的语句。
注意: 在任何编程语言中,都不建议使用goto语句。因为它使得程序的控制流难以跟踪,是程序难以理解和难以修改。任何使用沟通的程序可以改写成不需要使用goto语句的写法。
C++中goto语句的语法:
goto label;
..
.
label:statement;
在这里,label 是识别被标记语句的标识符,可以是任何除 C++ 关键字以外的纯文本。标记语句可以是任何语句,放置在标识符和冒号(:)后边。
实例:
#include
using namespace std;
int main ()
{
// 局部变量声明
int a = 10;
// do 循环执行
LOOP:do
{
if( a == 15)
{
// 跳过迭代
a = a + 1;
goto LOOP;
}
cout << "a 的值:" << a << endl;
a = a + 1;
}while( a < 20 );
return 0;
}
当上面的代码被编译和执行时,会产生下列结果:
a 的值: 10
a 的值: 11
a 的值: 12
a 的值: 13
a 的值: 14
a 的值: 16
a 的值: 17
a 的值: 18
a 的值: 19
goto 语句一个很好的作用是退出深嵌套例程。例如,请看下面的代码片段:
for(...) {
for(...) {
while(...) {
if(...) goto stop;
.
.
.
}
}
}
stop:
cout << "Error in program.\n";
消除 goto 会导致一些额外的测试被执行。一个简单的 break 语句在这里不会起到作用,因为它只会使程序退出最内层循环。
如果条件永远不为假,则循环将变成无限循环。for 循环在传统意义上可用于实现无限循环。由于构成循环的三个表达式中任何一个都不是必需的,您可以将某些条件表达式留空来构成一个无限循环。
实例:
#include
using namespace std;
int main ()
{
for( ; ; )
{
printf("This loop will run forever.\n");
}
return 0;
}
当条件表达式不存在时,它被假设为真。您也可以设置一个初始值和增量表达式,但是一般情况下,C++ 程序员偏向于使用 for(;; ) 结构来表示一个无限循环。
注意: 可以按 Ctrl + C 键终止一个无限循环。