变量用于在有限时间内临时存储数据。常量不允许对其内容做更改。
一、什么是变量
在我们开始学习编程语言中变量的使用之前,先来了解一下计算机相关的一些内容及其工作原理。
1、内存和寻址简介
所有计算机、智能手机和其它可编程设备都包含一个微处理器和一定量的内存,该内存用于临时存储,称为随机存取存储器(RAM)。此外,许多设备还允许将数据保存在诸如硬盘的存储设备上。微处理器执行应用程序,它与RAM一起工作以获取要执行的应用程序二进制代码以及与其相关联的数据,其中包括屏幕上显示的和用户输入的数据。
RAM看作是类似于宿舍中的一排储物柜的存储区域,每个储物柜具有数字 - 即地址。 为了访问存储器中的位置,比如位置578,需要通过指令询问处理器以从那里获取值或者向其写入值。
2、变量声明、访问和使用
声明一个变量可用于存储临时数据,而不用我们制定内存中的位置(如上面的578)来存放数据。
变量声明方式:
VariableType VariableName;
或
VariableType VariableName = InitialValue;
变量类型属性告诉编译器变量可以存储的数据类型,并且编译器为其保留必要的空间。变量名称是存储变量值的内存中地址的友好替代品。
下面程序显示了如何在内存中声明、初始化和使用变量:
#include <iostream>
using namespace std;
int main()
{
cout << "This program will help you multiply two numbers" << endl;
cout << "Enter the first number: ";
int firstNumber = 0;
cin >> firstNumber;
cout << "ENter the second number: ";
int secondNumber = 0;
cin >> secondNumber;
// Multiply two numbers, store result in a variable
int multiplicationResult = firstNumber * secondNumber;
// Display result
cout << firstNumber << " x " << secondNumber;
cout << " = " << multiplicationResult << endl;
return 0;
}
上述程序先通过内存的形式将用户输入的变量存储在内存中,输入完成后将两个变量的值做相乘操作。
声明变量后,编译器将此变量firstNumber/secondNumber映射到内存中的某个位置,并为声明的所有变量负责相关的内存地址记录。因此,程序员使用容易记住的变量名称,而编译器管理存储器寻址并创建微处理器在使用RAM时执行的指令。
变量命名注意事项:
C ++中的变量名称可以是字母和数字,但不能以数字开头。
变量名不能包含空格,也不能包含算术运算符(如+, - 等)。
变量名也不能是保留关键字。例如,名为return的变量将导致编译失败。
变量名称可以包含下划线,通常用于描述性变量命名。
3、声明和初始化同一类型的多个变量
同一类型的变量声明和初始化可以一次性完成:
int firstNumber = 0, secondNumber = 0, multiplicationResult = 0;
可以在函数开头同时声明多个变量。但是在首次需要时声明变量通常更好,因为它使代码可读,当声明接近其首次使用的位置时,更容易知道变量的类型和初始值信息。
需要注意的是,存储在变量中的数据是存储在RAM中的数据。 当应用程序终止时,此数据将丢失,除非程序员明确地将数据保留在存储介质(如硬盘)上。
4、变量的范围
一般的变量具有明确定义的范围,在该范围内它们是有效的并且可以使用,在有效范围之外,编译器将无法识别变量名称,程序将无法编译。 在有效范围之外,变量是一个未被识别的实体,编译器无法识别。
代码示例:
#include <iostream>
using namespace std;
void MultiplyNumbers()
{
cout << "Enter the first number: ";
int firstNumber = 0;
cin >> firstNumber;
cout << "Enter the second number: ";
int secondNumber = 0;
cin >> secondNumber;
// Multiply two numbers, store result in a variable
int multiplicationResult = firstNumber * secondNumber;
// Display result
cout << firstNumber << " x " << secondNumber;
cout << " = " << multiplicationResult << endl;
}
int main()
{
cout << "This program will help you multiply two numbers" << endl;
// Call the function that does all the work
MultiplyNumbers();
// cout << firstNumber << " x " << secondNumber;
// cout << " = " << multiplicationResult << endl;
return 0;
}
这段代码与第3小节代码的功能完全一样,唯一的区别在main()调用MultiplyNumbers()函数来完成大部分的工作。其中,变量firstNumber和secondNumber不能在函数MultiplyNumbers()之外使用。如果取消注释main()中的第29行和第30行,则会遇到类型为“未声明标识符”错误提示,编译失败。
因为变量firstNumber和secondNumber的范围是局部的,是局部变量,仅限于在声明它们的函数内使用。当函数结束时,所有局部变量都将被销毁,它们占用的内存将返回。
5、全局变量
如果函数MultiplyNumbers()中变量的声明在函数MultiplyNumber()之外而不是在函数内部,那么它们是全局变量,在main()和MultiplyNumbers()中都可用。
下面程序演示了全局变量,它是程序中使用范围最广的变量:
#include <iostream>
using namespace std;
// three global integers
int firstNumber = 0;
int secondNumber = 0;
int multiplicationResult = 0;
void MultiplyNumbers()
{
cout << "Enter the first number: ";
cin >> firstNumber;
cout << "Enter the second number: ";
cin >> secondNumber;
// Multiply two numbers, store result in a variable
multiplicationResult = firstNumber * secondNumber;
// Display result
cout << "Displaying from MultiplyNumbers(): ";
cout << firstNumber << " x " << secondNumber;
cout << " = " << multiplicationResult << endl;
}
int main()
{
cout << "This program will help you multiply two numbers" << endl;
// Call the function that does all the work
MultiplyNumbers();
// This line will now compile and work!
cout << firstNumber << " x " << secondNumber;
cout << " = " << multiplicationResult << endl;
return 0;
}
输出:
This program will help you multiply two numbers
Enter the first number: 52
Enter the second number: 23
Displaying from MultiplyNumbers(): 52 x 23 = 1196
Displaying from main(): 52 x 23 = 1196
需要注意的是:
不能随意使用全局变量,因为全局变量可以在任何一个函数中被赋值,并且可以包含不可预测的状态,尤其是当修改它们的函数在不同的线程中运行或由团队中的不同程序员编程时。上述代码中,在不使用全局变量的情况下,可以使函数MultiplyNumbers()将乘法的整数结果返回给main()。
6、命名规范
在上面程序中,我们将函数命名为MultiplyNumbers(),其中函数名中的每个单词都以大写字母开头,而变量firstNumber,secondNumber和multiplicationResult中的第一个字母为小写。
变量表示法有camel casing、Hungarian notation等,选择一套表示法并始终遵循该规则是个十分良好的习惯。
二、C ++变量类型
三、使用sizeof确定变量大小
变量大小是在声明变量时编译器保留的内存量。变量的大小取决于它的类型,C ++有一个非常方便的运算符sizeof,可以得到变量或类型的字节大小。
使用方法:
cout << "Size of an int: " << sizeof (int);
需要注意的是,对于sizeof的输出,32位编译器和64位编译器可能会输出不同的结果。
C ++ 11引入了固定宽度的整数类型,允许我们以位为单位指定整数的确切宽度。 对于8位有符号和无符号整数,它们分别是int8_t或uint8_t。还可以使用16位(int16_t,uint16_t),32位(int32_t,uint32_t)和64位(int64_t,uint64_t)整数类型。要使用这些类型,请记住包含头。
四、使用auto实现自动类型推断
在给定初始化值的情况下,变量类型已知。 例如,如果使用值true初始化变量,那么我们知道变量类型为bool。
在支持C ++ 11及更高版本的编译器中,使用关键字auto可以不必显式指定变量类型。
auto coinFlippedHeads = true;
在上面这行代码中,将为变量coinFlippedHeads定义类型的任务留给了编译器。编译器检查变量初始化的值的性质,然后决定适合此变量的最佳类型。在这种特殊情况下,很明显初始化值true最适合bool类型的变量。 因此编译器将bool确定为最适合变量coinFlippedHeads的类型。
需要注意的是:
使用auto需要初始化变量,编译器根据该变量的初始值来决定变量类型。如果不初始化auto类型的变量,则会出现编译错误。
五、使用typedef替换变量类型
C ++允许我们将变量类型名替换为更方便的别名,使用关键字typedef实现这一功能。下面程序将unsigned int 类型使用STRICTLY_POSITIVE_INTEGER替换,替换之后STRICTLY_POSITIVE_INTEGER即表示unsigned int 类型。
typedef unsigned int STRICTLY_POSITIVE_INTEGER; STRICTLY_POSITIVE_INTEGER numEggsInBasket = 4532;
六、什么是常量
在定义之后,常量的值不能改变。 在C ++中对常量的赋值会导致编译错误。
与变量类似,常量也占用内存中的空间,并且用常量名来标识保留空间的地址。 但是,此空间的内容不能被覆盖。
C++中的常量包括下面五种:
1、文字常量
文字常量可以是多种类型:整数,字符串等。如下面代码:
std::cout << "Hello World" << std::endl;
“Hello World”就是一个文字常量,
int someNumber = 10;
其中10是一个文字常量。
2、使用关键字const将变量声明为常量
一种常量类型是在变量类型之前使用关键字const声明:
const type-name constant-name = value;
如下面示例程序:
#include <iostream>
int main()
{
using namespace std;
const double pi = 22.0 / 7;
cout << "The value of constant pi is: " << pi << endl;
// Uncomment next line to view compile failure
// pi = 345;
return 0;
}
上述代码中,用const关键字告诉编译器pi是double类型的常量,所以在后面就不能重新对pi赋值了。
3、使用constexpr的常量表达式
关键字constexpr允许类似于函数的常量声明:
constexpr double GetPi() {return 22.0 / 7;}
constexpr关键字也可以套用:
constexpr double TwicePi() {return 2 * GetPi();}
constexpr看起来像一个函数,但是从编译器和应用程序的角度来看,它允许优化,编译器能够将常量表达式计算为常量。在前面的示例中,TwicePi()是一个使用常量表达式GetPi()的constexpr。这可能会触发编译时优化,其中TwicePi()的每次使用都被编译器简单地替换为6.28571,而不是在执行时计算2 x 22/7的代码。
GetPi()和TwicePi()可能看起来像函数,但是他们并不完全是。函数在程序执行时调用,但GetPi()和TwicePi()是常量表达式,编译器已经用3.14286替换了GetPi(),用6.28571替换了TwicePi()。
4、枚举
在某些情况下,应允许特定变量仅接受某组值。在这两种情况下,我们需要一种变量,其值仅限于已定义的某个集合。枚举正是这种情况下所需的工具,以关键字enum表示。枚举包含一组称为枚举数的常量。
例如:
enum CardinalDirections
{
North,
South,
East,
West
};
枚举用作用户定义的类型。 可以为此类型的变量分配一系列限制在枚举中包含的枚举数的值:
#include <iostream>
using namespace std;
enum CardinalDirections
{
North = 25,
South,
East,
West
};
int main()
{
cout << "Displaying directions and their symbolic values" << endl;
cout << "North: " << North << endl;
cout << "South: " << South << endl;
cout << "East: " << East << endl;
cout << "West: " << West << endl;
CardinalDirections windDirection = South;
cout << "Variable windDirection = " << windDirection << endl;
return 0;
}
枚举类型的使用方法:
CardinalDirections direction = North; // Initial value
运行结果:
Displaying directions and their symbolic values
North: 25
South: 26
East: 27
West: 28
Variable windDirection = 26
上面代码中我们枚举了四个基本方向,并给出了第一个北方的初始值为25,这确保编译器为以下常量分配值26,27和28,如输出中所示。在第20行中,创建了一个CardinalDirections类型的变量,该变量被赋予一个初始值South。当在第21行的屏幕上显示时,编译器将调度与South关联的整数值,即26。
如果需要,还可以通过初始化枚举常量来为每个枚举常量指定显式值。
5、使用#define定义的常量
#define pi 3.14286
#define是一个预处理器宏,这里所做的是所有提到的pi都将由3.14286替换,供编译器处理。
不建议使用#define使用预处理器定义常量。
七、不能用作变量或常量名称的关键字
某些单词由C ++保留,不能将它们用作变量名。这些关键字对C ++编译器具有特殊意义:
总结
这一章学习了如何使用内存临时存储变量和常量中的值,了解到变量的大小由其类型决定,并且运算符sizeof可用于查看变量的大小。不同类型的变量,例如bool,int等,并且它们将用于包含不同类型的数据。正确选择变量类型对于有效编程非常重要,并且选择对于此目的来说太小的变量会导致换行错误或溢出情况。您了解了关键字auto,您可以让编译器根据变量的初始化值为您确定数据类型。还使用关键字const,constexpr和enum了解了不同类型的常量以及其中最重要的常量的用法。