C++ 基础语法01
C++ 是一种静态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言,支持过程化编程、面向对象编程和泛型编程。
C++ 被认为是一种中级语言,它综合了高级语言和低级语言的特点。
C++ 是由 Bjarne Stroustrup 于 1979 年在新泽西州美利山贝尔实验室开始设计开发的。C++ 进一步扩充和完善了 C 语言,最初命名为带类的C,后来在 1983 年更名为 C++。
C++ 是 C 的一个超集,事实上,任何合法的 C 程序都是合法的 C++ 程序。
注意:使用静态类型的编程语言是在编译时执行类型检查,而不是在运行时执行类型检查。
面向对象程序设计
C++ 完全支持面向对象的程序设计,包括面向对象开发的四大特性:
- 封装
- 数据隐藏
- 继承
- 多态
标准库
标准的 C++ 由三个重要部分组成:
- 核心语言,提供了所有构件块,包括变量、数据类型和常量,等等。
- C++ 标准库,提供了大量的函数,用于操作文件、字符串等。
- 标准模板库(STL),提供了大量的方法,用于操作数据结构等。
ANSI 标准
ANSI 标准是为了确保 C++ 的便携性 —— 您所编写的代码在 Mac、UNIX、Windows、Alpha 计算机上都能通过编译。
由于 ANSI 标准已稳定使用了很长的时间,所有主要的 C++ 编译器的制造商都支持 ANSI 标准。
学习 C++
学习 C++,关键是要理解概念,而不应过于深究语言的技术细节。
学习程序设计语言的目的是为了成为一个更好的程序员,也就是说,是为了能更有效率地设计和实现新系统,以及维护旧系统。
C++ 支持多种编程风格。您可以使用 Fortran、C、Smalltalk 等任意一种语言的编程风格来编写代码。每种风格都能有效地保证运行时间效率和空间效率。
C++ 的使用
基本上每个应用程序领域的程序员都有使用 C++。
C++ 通常用于编写设备驱动程序和其他要求实时性的直接操作硬件的软件。
C++ 广泛用于教学和研究。
任何一个使用苹果电脑或 Windows PC 机的用户都在间接地使用 C++,因为这些系统的主要用户接口是使用 C++ 编写的。
C++ 环境设置
本地环境设置
如果您想要设置 C++ 语言环境,您需要确保电脑上有以下两款可用的软件,文本编辑器和 C++ 编译器。
文本编辑器
这将用于输入您的程序。
文本编辑器的名称和版本在不同的操作系统上可能会有所不同。例如,Notepad 通常用于 Windows 操作系统上,vim/vi 可用于 Windows 和 Linux/UNIX 操作系统上。
通过编辑器创建的文件通常称为源文件,源文件包含程序源代码。C++ 程序的源文件通常使用扩展名 .cpp、.cp 或 .c。
在开始编程之前,请确保您有一个文本编辑器,且有足够的经验来编写一个计算机程序,然后把它保存在一个文件中,编译并执行它。
C++ 编译器
写在源文件中的源代码是人类可读的源。它需要"编译",转为机器语言,这样 CPU 可以按给定指令执行程序。
C++ 编译器用于把源代码编译成最终的可执行程序。
大多数的 C++ 编译器并不在乎源文件的扩展名,但是如果您未指定扩展名,则默认使用 .cpp。
最常用的免费可用的编译器是 GNU 的 C/C++ 编译器,
以下部分将指导您如何在不同的操作系统上安装 GNU 的 C/C++ 编译器。这里同时提到 C/C++,主要是因为 GNU 的 gcc 编译器适合于 C 和 C++ 编程语言。
安装 GNU 的 C/C++ 编译器
UNIX/Linux 上的安装
如果您使用的是 Linux 或 UNIX,请在命令行使用下面的命令来检查您的系统上是否安装了 GCC:
$ g++ -v
如果您的计算机上已经安装了 GNU 编译器,则会显示如下消息:
如果未安装 GCC,那么请按照 http://gcc.gnu.org/install/ 上的详细说明安装 GCC。
Mac OS X 上的安装
如果您使用的是 Mac OS X,最快捷的获取 GCC 的方法是从苹果的网站上下载 Xcode 开发环境,并按照安装说明进行安装。一旦安装上 Xcode,您就能使用 GNU 编译器。
Xcode 目前可从 developer.apple.com/technologies/tools/ 上下载。
C++ 基本语法
C++ 程序可以定义为对象的集合,这些对象通过调用彼此的方法进行交互。现在让我们简要地看一下什么是类、对象,方法、即时变量。
- 对象 - 对象具有状态和行为。例如:一只狗的状态 - 颜色、名称、品种,行为 - 摇动、叫唤、吃。对象是类的实例。
- 类 - 类可以定义为描述对象行为/状态的模板/蓝图。
- 方法 - 从基本上说,一个方法表示一种行为。一个类可以包含多个方法。可以在方法中写入逻辑、操作数据以及执行所有的动作。
- 即时变量 - 每个对象都有其独特的即时变量。对象的状态是由这些即时变量的值创建的。
C++ 程序结构
让我们看一段简单的代码,可以输出单词 hello beyond。
#include <iostream>
using namespace std;
// main() 是程序开始执行的地方
int main()
{
cout << "hello beyond" << endl; // 输出 hello beyond return 0;
}
接下来我们讲解一下上面这段程序:
- C++ 语言定义了一些头文件,这些头文件包含了程序中必需的或有用的信息。上面这段程序中,包含了头文件 <iostream>。
- 行 using namespace std; 告诉编译器使用 std 命名空间。命名空间是 C++ 中一个相对新的概念。
- 下一行 // main() 是程序开始执行的地方 是一个单行注释。单行注释以 // 开头,在行末结束。
- 下一行 int main() 是主函数,程序从这里开始执行。
- 下一行 cout << "hello beyond"; 会在屏幕上显示消息 "hello beyond"。
- 下一行 return 0; 终止 main( )函数,并向调用进程返回值 0。
编译 & 执行 C++ 程序
接下来让我们看看如何把源代码保存在一个文件中,以及如何编译并运行它。下面是简单的步骤:
- 打开一个文本编辑器,添加上述代码。
- 保存文件为 01_hello.cpp。
- 打开命令提示符,进入到保存文件所在的目录。
- 键入 'g++ 01_hello.cpp ',输入回车,编译代码。如果代码中没有错误,命令提示符会跳到下一行,并生成 a.out 可执行文件。
- 现在,键入 ' a.out' 来运行程序。
- 您可以看到屏幕上显示 ' hello beyond '。
$ g++ hello.cpp
$ ./a.out
hello beyond
请确保您的路径中已包含 g++ 编译器,并确保在包含源文件 hello.cpp 的目录中运行它。
您也可以使用 makefile 来编译 C/C++ 程序。
C++ 中的分号 & 块
在 C++ 中,分号是语句结束符。也就是说,每个语句必须以分号结束。它表明一个逻辑实体的结束。
例如,下面是三个不同的语句:
x = y;
y = y+1;
add(x, y);
块是一组使用大括号括起来的按逻辑连接的语句。例如:
{
cout << "hello beyond"; // 输出 hello beyond return 0;
}
C++ 不以行末作为结束符的标识,因此,您可以在一行上放置多个语句。例如:
x = y;
y = y+1;
add(x, y);
等同于
x = y; y = y+1; add(x, y);
C++ 标识符
C++ 标识符是用来标识变量、函数、类、模块,或任何其他用户自定义项目的名称。一个标识符以字母 A-Z 或 a-z 或下划线 _ 开始,后跟零个或多个字母、下划线和数字(0-9)。
C++ 标识符内不允许出现标点字符,比如 @、$ 和 %。C++ 是区分大小写的编程语言。因此,在 C++ 中,username 和 userName 是两个不同的标识符。
下面列出几个有效的标识符:
isGirl beyond love user_id abc_123
beyond133 _modelArr lj pre_eminent resultSet
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 |
三字符组
三字符组就是用于表示另一个字符的三个字符序列,又称为三字符序列。三字符序列总是以两个问号开头。
三字符序列不太常见,但 C++ 标准允许把某些字符指定为三字符序列。以前为了表示键盘上没有的字符,这是必不可少的一种方法。
三字符序列可以出现在任何地方,包括字符串、字符序列、注释和预处理指令。
下面列出了最常用的三字符序列:
三字符组 | 替换 |
---|---|
??= | # |
??/ | \ |
??' | ^ |
??( | [ |
??) | ] |
??! | | |
??< | { |
??> | } |
??- | ~ |
所有的编译器都不支持三字符组,为避免造成混乱,不建议使用三字符组。那你还介绍个锤子
C++ 中的空格
只包含空格的行,被称为空白行,可能带有注释,C++ 编译器会完全忽略它。
在 C++ 中,空格用于描述空白符、制表符、换行符和注释。空格分隔语句的各个部分,让编译器能识别语句中的某个元素(比如 int)在哪里结束,下一个元素在哪里开始。因此,在下面的语句中:
int age;
在这里,int 和 age 之间必须至少有一个空格字符(通常是一个空白符),这样编译器才能够区分它们。另一方面,在下面的语句中:
fruit = apples + oranges; // 获取水果的总数
fruit 和 =,或者 = 和 apples 之间的空格字符不是必需的,但是为了增强可读性,您可以根据需要适当增加一些空格。
C++ 注释
程序的注释是解释性语句,您可以在 C++ 代码中包含注释,这将提高源代码的可读性。所有的编程语言都允许某种形式的注释。
C++ 支持单行注释和多行注释。注释中的所有字符会被 C++ 编译器忽略。
C++ 注释以 /* 开始,以 */ 终止。例如:
/* 这是注释 */
/* C++ 注释也可以
* 跨行
*/
注释也能以 // 开始,直到行末为止。例如:
#include <iostream>
using namespace std;
main()
{
cout << "hello beyond"; // 输出 hello beyond return 0;
}
当上面的代码被编译时,编译器会忽略 // 后面的注释,最后会产生以下结果:
hello beyond
在 /* 和 */ 注释内部,// 字符没有特殊的含义。在 // 注释内,/* 和 */ 字符也没有特殊的含义。因此,您可以在一种注释内嵌套另一种注释。
一言概括就是注释可以嵌套,例如:
/* 用于输出 Hello World 的注释
cout << "Hello World"; // 输出 Hello World */
C++ 数据类型
使用编程语言进行编程时,需要用到各种变量来存储各种信息。变量其实就是保留它所存储的值在内存中的位置。这意味着,当您创建一个变量时,就会在内存中保留一些空间。
您可能需要存储各种数据类型(比如字符型、宽字符型???、整型、浮点型、双精度浮点型、布尔型等)的信息,操作系统会根据变量的数据类型,来分配内存和决定在保留内存中存储什么。
基本的内置类型
C++ 为程序员提供了种类丰富的内置数据类型和用户自定义的数据类型。下表列出了七种基本的 C++ 数据类型:
类型 | 关键字 |
---|---|
布尔型 | bool |
字符型 | char |
整型 | int |
浮点型 | float |
双浮点型 | double |
无类型 | void |
宽字符型 | wchar_t |
一些基本类型可以使用一个或多个类型修饰符进行修饰:
- signed
- unsigned
- short
- long
下表显示了各种变量类型在内存中存储值时需要占用的内存,以及该类型的变量所能存储的最大值和最小值。
类型 | 位宽度 | 范围 |
---|---|---|
char | 1 个字节(8位) | -127 到 127 或者 0 到 255 |
unsigned char | 1 个字节 | 0 到 255 |
signed char | 1 个字节 | -127 到 127 |
int | 4 个字节 | -2147483648 到 2147483647 |
unsigned int | 4 个字节 | 0 到 4294967295 |
signed int | 4 个字节 | -2147483648 到 2147483647 |
short int | 2 个字节 | -32768 到 32767 |
unsigned short int | Range | 0 到 65,535 |
signed short int | Range | -32768 到 32767 |
long int | 4 个字节 | -2,147,483,647 到 2,147,483,647 |
signed long int | 4 个字节 | 与 long int 相同 |
unsigned long int | 4 个字节 | 0 到 4,294,967,295 |
float | 4 个字节 | +/- 3.4e +/- 38 (~7 个数字) |
double | 8 个字节 | +/- 1.7e +/- 308 (~15 个数字) |
long double | 8 个字节 | +/- 1.7e +/- 308 (~15 个数字) |
wchar_t | 2 或 4 个字节 | 1 个宽字符 |
从上表可得知,变量的大小会根据编译器和所使用的电脑而有所不同。
下面实例会输出您电脑上各种数据类型的大小。
#include <iostream>
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;
}
本实例使用了 endl,这将在每一行后插入一个换行符,<< 运算符用于向屏幕传多个值。我们也使用 sizeof()函数来获取各种数据类型的大小。
当上面的代码被编译和执行时,它会产生以下的结果,结果会根据所使用的计算机而有所不同:
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
typedef 声明
您可以使用 typedef 为一个已有的类型取一个新的名字。下面是使用 typedef 定义一个新类型的语法:
typedef type newname;
例如,下面的语句会告诉编译器,feet 是 int 的另一个名称:
typedef int feet;
现在,下面的声明是完全合法的,它创建了一个整型变量 distance:
feet distance;
枚举类型
枚举类型声明一个可选的类型名称和一组标识符,用来作为该类型的值。 每个枚举数是一个枚举类型的常数。
创建枚举,需要使用关键字 enum。枚举类型的一般形式为:
enum enum_type_name { list of names } local_var;
在这里,enum_type_name 是枚举类型的名称。名称列表 { list of names } 是用逗号分隔的。
例如,下面的代码定义了一个颜色枚举,变量 bgColor 的类型为 SGColor。最后,bgColor 被赋值为 "Blue"。
enum SGColor { Red, Green, Blue } bgColor;
bgColor = Blue;
默认情况下,第一个名称的值为 0,第二个名称的值为 1,第三个名称的值为 2,以此类推。但是,您也可以给名称赋予一个特殊的值,只需要添加一个初始值即可。例如,在下面的枚举中,green 的值为 5。
enum SGColor { Red, Green=5, Blue };
在这里,Blue 的值为 6,因为默认情况下,每个名称都会比它前面一个名称大 1。
C++ 变量类型
变量其实只不过是程序可操作的存储区的名称。C++ 中每个变量都有指定的类型,类型决定了变量存储的大小和布局,该范围内的值都可以存储在内存中,运算符可应用于变量上。
变量的名称可以由字母、数字和下划线字符组成。它必须以字母或下划线开头。大写字母和小写字母是不同的,因为 C++ 是大小写敏感的。
有以下几种基本的变量类型:
类型 | 描述 |
---|---|
bool | 存储值 true 或 false。 |
char | 通常是一个八位字节(一个字节)。这是一个整数类型。 |
int | 对机器而言,整数的最自然的大小。 |
float | 单精度浮点值。 |
double | 双精度浮点值。 |
void | 表示类型的缺失。 |
wchar_t | 宽字符类型。 |
C++ 也允许定义各种其他类型的变量,比如枚举、指针、数组、引用、数据结构、类等等,这将会在后面写到。
下面我们将讲解如何定义、声明和使用各种类型的变量。
C++ 中的变量定义
变量定义就是告诉编译器在何处创建变量的存储,以及如何创建变量的存储。变量定义指定一个数据类型,并包含了该类型的一个或多个变量的列表,如下所示:
type variable_list;
在这里,type 必须是一个有效的 C++ 数据类型,可以是 char、w_char、int、float、double、bool 或任何用户自定义的对象,variable_list 可以由一个或多个标识符名称组成,多个标识符之间用逗号分隔。下面列出几个有效的声明:
int i, j, k;
char c, ch;
float result, salary;
double sum;
行 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),其他所有变量的初始值是未定义的。
这里的「静态存储持续」的变量指的是全局或static关键字修饰的变量
C++ 中的变量声明
变量声明向编译器保证变量以给定的类型和名称存在,这样编译器在不需要知道变量完整细节的情况下也能继续进一步的编译。变量声明只在编译时有它的意义,因为在程序连接时编译器需要实际的变量声明。
当您使用多个文件且只在其中一个文件中定义变量时(定义变量的文件在程序连接时是可用的),变量声明就显得非常有用。您可以使用 extern 关键字在任何地方声明一个变量。虽然您可以在 C++ 程序中多次声明一个变量,但变量只能在某个文件、函数或代码块中被定义一次。???
实例
尝试下面的实例,其中,变量在头部就已经被声明,但它们是在主函数内被定义和初始化的:
#include <iostream>
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++ 中的左值(Lvalues)和右值(Rvalues)
C++ 中有两种类型的表达式:
- 左值(lvalue):指向内存位置的表达式被称为左值(lvalue)表达式。左值可以出现在赋值号的左边或右边。
- 右值(rvalue):指的是存储在内存中某些地址的数值。右值是不能对其进行赋值的表达式,也就是说,右值可以出现在赋值号的右边,但不能出现在赋值号的左边。
变量是左值,因此可以出现在赋值号的左边。数值型的字面值是右值,因此不能被赋值,不能出现在赋值号的左边。下面是一个有效的语句:
int age = 16;
但是下面这个就不是一个有效的语句,会生成编译时错误:
10 = 20;
C++ 变量作用域
作用域是程序的一个区域,一般来说有三个地方可以声明变量:
- 在函数或一个代码块内部声明的变量,称为局部变量。
- 在函数参数的定义中声明的变量,称为形式参数。
- 在所有函数外部声明的变量,称为全局变量。
先来讲解什么是局部变量和全局变量。
局部变量
在函数或一个代码块内部声明的变量,称为局部变量。它们只能被函数内部或者代码块内部的语句使用。下面的实例使用了局部变量a,b,c:
#include <iostream>
using namespace std;
int main ()
{
// 局部变量声明
int a, b;
int c;
// 实际初始化
a = 10;
b = 20;
c = a + b;
cout << c; return 0;
}
全局变量
在所有函数外部定义的变量(通常是在程序的头部),称为全局变量。全局变量的值在程序的整个生命周期内都是有效的。
全局变量可以被任何函数访问。也就是说,全局变量一旦声明,在整个程序中都是可用的。下面的实例使用了全局变量和局部变量:
#include <iostream>
using namespace std;
// 全局变量声明
int global_sum;
int main ()
{
// 局部变量声明
int a, b;
// 实际初始化
a = 10;
b = 20;
global_sum = a + b;
cout << global_sum; return 0;
}
在程序中,局部变量和全局变量的名称可以相同,但是在函数内,局部变量的值优先级高,会覆盖全局变量的值。下面是一个实例:
#include <iostream>
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 |
正确地初始化变量是一个良好的编程习惯,否则有时候程序可能会产生意想不到的结果。
C++ 常量
常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量。
常量可以是任何的基本数据类型,可分为整型数字、浮点数字、字符、字符串和布尔值。
常量就像是常规的变量,只不过常量的值在定义后不能进行修改。
整数常量
整数常量可以是十进制、八进制或十六进制的常量。前缀指定基数:0x 或 0X 表示十六进制,0 表示八进制,不带前缀则默认表示十进制。
整数常量也可以带一个后缀,后缀是 U 和 L 的组合,U 表示无符号整数(unsigned),L 表示长整数(long)。后缀可以是大写,也可以是小写,U 和 L 的顺序任意。
下面列举几个整数常量的实例:
212 // 合法的
215u // 合法的
0xFeeL // 合法的
078 // 非法的:8 不是八进制的数字
032UU // 非法的:不能重复后缀
以下是各种类型的整数常量的实例:
85 // 十进制
0213 // 八进制
0x4b // 十六进制
30 // 整数
30u // 无符号整数
30l // 长整数
30ul // 无符号长整数
浮点常量???
浮点常量由整数部分、小数点、小数部分和指数 4个部分组成。您可以使用 小数形式 或者 指数形式 来表示浮点常量。
当使用小数形式表示时,必须包含小数点、指数,或同时包含两者。
当使用指数形式表示时,必须包含整数部分、小数部分,或同时包含两者(无小数点,且E后面的阶码必定为整数可带符号)。
带符号的指数是用 e 或 E 引入的。
先说一下指数形式
由十进制数,加阶码标志“e”或“E”以及阶码(只能为整数,可以带符号)组成。其一般形式为a E n (a为十进制数,n为十进制整数可正可负)其值为 a*10^n
如: 2.1E5 (等于2.1*10的5次方), 3.7E-2 (等于3.7*10的-2次方) 0.5E7 (等于0.5*10的7次方), -2.8E-2 (等于-2.8*10的-2次方),
以下不是合法的实数 345 (无小数点) E7 (阶码标志E之前无数字) -5 (无阶码标志E) 53.-E3 (负号位置不对) 2.7E (无阶码)
下面列举几个浮点常量的实例:
3.14159 // 合法的
314159E-5L // 合法的
510E // 非法的:不完整的指数,即E后面没有阶数
210f // 非法的:没有小数或指数
.e55 // 非法的:缺少整数或分数,即E前面没有数字
布尔常量
布尔常量共有两个,它们都是标准的 C++ 关键字:(Python True False,OC YES NO)
- true 值代表真。
- false 值代表假。
但是,注意:我们不应把 true 的值看成 1,把 false 的值看成 0。???
只要是非零,都为真true!
字符常量
字符 常量是括在 单引号 中。
如果常量以 L(仅当大写时)开头,则表示它是一个宽字符常量(例如 L'x'),此时它必须存储在 wchar_t 类型的变量中。???Excuse Me???
否则,它就是一个窄字符常量(例如 'x'),此时它可以存储在 char 类型的简单变量中。
字符常量可以是一个普通的字符(例如 'x')、一个转义序列(例如 '\t'),或一个通用的字符(例如 '\u02C0')。
在 C++ 中,有一些特定的字符,当它们前面有反斜杠时,它们就具有特殊的含义,被用来表示如换行符(\n)或制表符(\t)等。下表列出了一些这样的转义序列码:
转义序列 | 含义 |
---|---|
\\ | \ 字符 |
\' | ' 字符 |
\" | " 字符 |
\? | ? 字符 |
\a | 警报铃声 |
\b | 退格键 |
\f | 换页符 |
\n | 换行符 |
\r | 回车 |
\t | 水平制表符 |
\v | 垂直制表符 |
\ooo | 一到三位的八进制数??? |
\xhh . . . | 一个或多个数字的十六进制数??? |
下面的实例显示了一些转义序列字符:
#include <iostream>
using namespace std;
int main()
{
cout << "Hello\tBeyond\n\n";
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
Hello Beyond
字符串常量
字符串字面值或常量 是括在双引号 "" 中的。
一个字符串包含类似于字符常量的字符:普通的字符、转义序列和通用的字符。
您可以使用空格做分隔符,把一个很长的字符串常量进行分行。???
下面的实例显示了一些字符串常量。下面这三种形式所显示的字符串是相同的。
"hello, dear"
"hello, \
dear"
"hello, " "d" "ear"
定义常量
在 C++ 中,有两种简单的定义常量的方式:
- 使用 #define 预处理器。
- 使用 const 关键字。
#define 预处理器
下面是使用 #define 预处理器定义常量的形式:
#define kIdentifier value
具体请看下面的实例:
#include <iostream>
using namespace std;
#define LENGTH 6
#define WIDTH 7
#define NEWLINE '\n'
int main()
{
int area;
area = LENGTH * WIDTH;
cout << area;
cout << NEWLINE;
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
42
const 关键字
您可以使用 const 前缀声明指定类型的常量,如下所示:
const type variable_name = value;
具体请看下面的实例:
#include <iostream>
using namespace std;
int main()
{
const int LENGTH = 6;
const int WIDTH = 7;
const char NEWLINE = '\n';
int area;
area = LENGTH * WIDTH;
cout << area;
cout << NEWLINE;
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
42
请注意,把常量定义为大写字母形式,是一个很好的编程实践。
C++ 修饰符类型
C++ 允许在 char、int 和 double 数据类型前放置 修饰符。修饰符 用于改变基本类型的含义,所以它更能满足各种情境的需求。
下面列出了数据类型修饰符:
- signed
- unsigned
- long
- short
修饰符 signed、unsigned、long 和 short 可应用于整型,
signed 和 unsigned 可应用于字符型,
long可应用于双精度型。
修饰符 signed 和 unsigned 也可以作为 long 或 short 修饰符的前缀。
例如:unsigned long int。
C++ 允许使用 速记符 号来声明无符号短整数或无符号长整数。
您可以不写 int,只写单词 unsigned、short或 unsigned、long,这其中的int 是隐含的。
例如,下面的两个语句都声明了无符号整型变量。
unsigned x;
unsigned int y;
为了理解 C++ 解释有符号整数和无符号整数修饰符之间的差别,我们来运行一下下面这个短程序:
#include <iostream>
using namespace std;
/*
* 这个程序演示了有符号整数和无符号整数之间的差别
*/
int main()
{
short int hasSymbol_i; // 有符号短整数
short unsigned int noSymbol_j; // 无符号短整数
noSymbol_j = 50000;
hasSymbol_i = noSymbol_j;
cout << hasYmbol_i << " " << noSymbol_j;
return 0;
}
当上面的程序运行时,会输出下列结果:
-15536 50000
上述结果中,无符号短整数 50,000 的位模式被解释为有符号短整数 -15,536。
说明一下:
无符号短整数 50000的二进制表示为: 1111001110100111000(没有符号位,全用来计数了)
然后把它赋值给有符号位的hasSymbol_i时,先置首位为符号位为1,然后后面再接111001110100111000(即115536),
合起来就是-115536
C++ 中的类型限定符
类型限定符提供了变量的额外信息。
限定符 | 含义 |
---|---|
const | const 类型的对象在程序执行期间不能被修改改变。 |
volatile | 修饰符 volatile 告诉编译器,变量的值可能以程序未明确指定的方式被改变。 |
restrict | 由 restrict 修饰的指针是唯一一种访问它所指向的对象的方式。只有 C99 增加了新的类型限定符 restrict。 |
类型限定符为标识符提供两个属性之一。 const 类型限定符将对象声明为不可修改。
volatile
类型限定符声明一个项,该项的值可由超出该项所在的程序控制范围的某个项(如并发执行的线程)合理更改。???
const 和 volatile
这两个类型限定符在声明中只能出现一次。 ???Excuse Me???
类型限定符可与任何类型说明符一起出现;
但是,它们不能在多项声明中的第一个逗号的后面才出现。
例如,以下声明是合法的:
typedef volatile int VI; const int ci;
以下声明是非法的:
typedef int *i, volatile *vi; float f, const cf; // const不能出现在多项声明中的逗号后面
仅当访问作为表达式的左值的标识符时,类型限定符才会相关。
有关左值和表达式的信息,请参阅左值表达式和右值表达式。
type-qualifier:
constvolatile
以下是合法的 const 和 volatile
声明:
int const *p_ci; /* Pointer to constant int */ int const (*p_ci); /* Pointer to constant int */ int *const cp_i; /* Constant pointer to int */ int (*const cp_i); /* Constant pointer to int */ int volatile vint; /* Volatile integer */
如果 数组类型 的规范包括 类型限定符,则将 限定元素 而不是数组类型。 ???Excuse Me???
如果 函数类型 的规范包括 限定符,则行为是不确定的。 ???Excuse Me???
volatile
和 const 都不会影响值的范围或对象的算术属性。
此列表描述如何使用 const 和 volatile
。
const 关键字可用于修改任何 基本或聚合类型、指向任何类型的对象的指针 或
typedef
。 如果仅使用 const 类型限定符 声明项,则 项的类型 将被当成 const int。 可以初始化 const 变量,也可以将该变量置于存储的只读区域中。 const 关键字对于声明指向 const 的指针很有用,因为这需要函数不以任何方式更改指针。编译器假定可通过使用或修改
volatile
变量的值未知过程来访问该变量(在程序中的任意未知)。 因此,无论是否在命令行上指定优化,都必须为对volatile
变量的每个分配或引用生成代码,即使它似乎不起作用。 ???Excuse Me???如果单独使用
volatile
,则假定int
。volatile
类型说明符 可用于提供对 特定内存位置的可靠访问。 将volatile
用于数据对象,这些对象可通过 信号处理程序、并行执行程序 或特定硬件(如内存映射的 I/O 控制寄存器)访问或更改。 可以为变量的生存期 ???Excuse Me???将变量声明为volatile
,也可以将单个引用强制转换为volatile
。项可以同时为 const 和
volatile
,在这种情况下,项无法通过其自己的程序进行合理修改,但可以通过某些异步进程进行修改。
只要一听到说:“const意味着常数”,就知道这是一个业余者说的话。一般正常来说,只要能说出const意味着“只读”就可以了。尽管这个答案不是完全的答案,但一般会被接受作为一个正确的答案。
下面的声明都是什么意思?
const int a;
int const a;
const int *a;
int * const a;
int const * const a ;
前两个的作用是一样,a是一个常整型数。
第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。
第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。
最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。
如果一个人能正确回答这些问题,那么几乎可以给人留下了一个好的印象。
为什么事到如今还要如此看重关键字const呢?大概理由如下:
1.关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。
如果曾花很多时间清理过其它人留下的代码,可能就会很快学会感谢这点多余的信息。(当然,懂得用const的人应该很少会留下的代码让别人来清理的。)
2. 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。
3. 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现。
(1) “编译器一般不为const变量分配内存,而是将它保存在符号表中,这使得它成为一个编译期间的值,没有了存储与读内存的操作。”
(2) volatile的作用是“告诉编译器,i是随时可能发生变化的,每次使用它的时候必须从内存中取出i的值”。
一,const, volatile含义
(1)const含义是“请做为常量使用”,而并非“放心吧,那肯定是个常量”。
(2)volatile的含义是“请不要做自以为是的优化,这个值可能变掉的”,而并非“你可以修改这个值”。
二,const, volatile的作用以及起作用的阶段
(1)const只在编译期有用,在运行期无用
const在编译期保证在C的“源代码”里面,没有对其修饰的变量进行修改的地方(如有则报错,编译不通过),而运行期该变量的值是否被改变则不受const的限制。
(2) volatile在编译期和运行期都有用
在编译期告诉编译器:请不要做自以为是的优化,这个变量的值可能会变掉;
在运行期:每次用到该变量的值,都从内存中取该变量的值。
三,const, volatile同时修饰一个变量
(1)合法性
“volatile”的含义并非是“non-const”,volatile 和 const 不构成反义词,所以可以放一起修饰一个变量。
(2)同时修饰一个变量的含义
表示一个变量在程序编译期不能被修改且不能被优化;在程序运行期,变量值可修改,但每次用到该变量的值都要从内存中读取,以防止意外错误。
C++ 存储类
存储类定义 C++ 程序中 变量/函数的范围(可见性)和 生命周期。
这些说明符 放置在它们所修饰的类型之前。下面列出 C++ 程序中可用的存储类:
- auto
- register
- static
- extern
- mutable
auto 存储类
auto 存储类是所有 局部变量 默认的 存储类。
{
int mount;
auto int month;
}
上面的实例定义了两个带有相同存储类的变量,
auto 只能用在函数内,即 auto 只能修饰局部变量。
register 存储类
register 存储类用于定义存储在 寄存器中 而不是 RAM 中的 局部变量。
这意味着变量的最大尺寸等于寄存器的大小(通常是一个词???什么意思???),
且不能对它应用一元的 '&' 运算符(因为它没有内存位置)。
{
register int counter;
}
寄存器只用于需要快速访问的变量,比如计数器。
还应注意的是,定义 'register' 并不意味着变量将被存储在寄存器中,它意味着变量可能存储在寄存器中,这取决于硬件和实现的限制。
static 存储类
static 存储类 指示编译器在程序的生命周期内 保持局部变量的存在,而不需要在每次它 进入和离开作用域时 进行创建和销毁。
因此,使用 static 修饰局部变量 可以在函数调用之间 保持局部变量的值。
static 修饰符也可以应用于全局变量。当 static 修饰全局变量时,会使变量的作用域 限制在声明它的文件内。
在 C++ 中,当 static 用在 类数据成员 上时,会导致仅有一个该成员的副本被类的所有对象共享。
#include <iostream>
//注意这儿没有命名空间
// 函数声明
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
extern 存储类
extern 存储类 用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。
相当于OC中类文件.h中的属性
当您使用 'extern' 时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。???Excuse Me???
当您有多个文件且定义了一个可以在其他文件中使用的 全局变量或函数时,可以在其他文件中使用 extern 来得到已定义的变量或函数的引用。
可以这么理解,extern 是用来在另一个文件中声明一个已经存在了的全局变量或函数。
extern 修饰符 通常用于当有两个或多个文件 共享相同的 全局变量或函数 的时候,如下所示:
第一个文件:main.cpp
#include <iostream>
//调用第3方的打印函数
extern void print_3lib();
// 提供给第3方函数打印的全局变量
int score;
int main()
{
score = 520;
print_3lib();
return 0;
}
第二个文件:support.cpp
#include <iostream>
extern int score;
void print_3lib(void)
{
std::cout << "score is: " << count << std::endl;
}
在这里,第二个文件中的 extern 关键字用于声明已经在第一个文件 main.cpp 中定义的 score。现在 ,编译这两个文件,如下所示:
$g++ main.cpp support.cpp -o print3lib
这会产生 print3lib 可执行程序,尝试执行 print3lib,它会产生下列结果:
$ ./print3lib
score is 520
mutable 存储类
mutable 说明符仅适用于 类的对象,这将在本教程的最后进行讲解。
它允许对象的成员替代常量。也就是说,mutable 成员可以通过 const 成员函数修改。???Excuse Me???