2.2 C++ 变量

变量

变量提供一个具体、可供程序操作的存储空间。C++中的每一个变量都有其数据类型,数据类型决定着变量所占的内存空间的大小和布局方式、该空间能存储的值的范围,以及变量能参与的运算。对于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),其他所有变量的初始值是未定义的

初始化不是赋值。初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是对象的当前值擦除,而以一个新值来替代。


列表初始化

C++语言定义了初始化的好几种不同形式,这也是初始化问题复杂性的一个体现。例如,想定义一个名字为units_sold的int 变量并初始化为0,以下4条语句都可以实现:

	int units_sold = 0;
	int units_sold = {0};
	int units_sold(0);
	int units_sold{0};

作为C++11新标准的一部分,用{}来初始化变量得到了全面应用,而在此之前,这种初始化的形式仅在某些受限的场合才能使用,这种初始化的形式被称为列表初始化(List initialization)。现在,无论初始化对象还是某些时候为对象赋新值,都可以这样使用一组花括号来初始化。

当用于内置类型的变量时,这种初始化形式有一个重要的特点:如果我们使用列表初始化且初始值存在丢失信息的风险,则编译器将报错:

long double a = 3.1415926536;
int b{a}, c={a}; //Error ,转换未执行,存在丢失信息的危险
int b(a), c(a);  //正确,转换执行,丢失信息

C++ 中的变量声明

变量声明向编译器保证变量以给定的类型和名称存在,这样编译器在不需要知道变量完整细节的情况下也能继续进一步的编译。变量声明只在编译时有它的意义,在程序连接时编译器需要实际的变量声明。

当您使用多个文件且只在其中一个文件中定义变量时(定义变量的文件在程序连接时是可用的),变量声明就显得非常有用。您可以使用 extern 关键字在任何地方声明一个变量。

任何包含了显式初始化的声明即为定义,

extern double pi = 3.1415926; //定义

虽然您可以在 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;
}

 


标识符

变量的名称可以由字母、数字和下划线字符组成。它必须以字母或下划线开头。大写字母和小写字母是不同的,因为 C++ 是大小写敏感的

另外, C99的标准中规定:"除第一个字符外,可以使用$ 即美元符"。

变量命名规范

  • 标识符要能体现实际含义
  • 变量名一般用小写字母,如index ,不要写成Index 或 INDEX。
  • 用户自定义的类一般以大写字母开头,如 Sales_item。
  • 如果标识符有多个单词组成,则单词间应该有明显的区分,如 student_loan ,studentLoan,不要使用studentloan。

对于命名规范来说,若能坚持,必将受益。

写了一个简单程序,来实现以下几种典型的不合法错误:

#include <iostream>
using namespace std;
int main()
{
	//int cat-22;  //不合法使用了-
	int _;        //合法
	//int 1_or_2;  //不合法,第一个字符不能为数字
	//int double = 3.14; //不合法,关键字double
	double Double = 3.14;    //合法
    cout << "Hello, world!" << endl;
    return 0;
}

名字的作用域

无论是在程序的什么位置, 使用到的每个名字都会指向一个特定的实体:变量, 函数, 类型等。然而每个名字如果出现在程序的不同位置, 也就有可能指向不同的实体。

作用域(scope)是程序的一部分, 在其中名字有特殊含义。c+语言中, 大多数作用域都可以用花括号分隔。

同一名字在不同的作用域中可能指向不同的实体。名字的有效区域始于名字的声明语句, 以声明语句所在的作用域末端为结束。

如例:

#include<cstdio>

using namespace std;

int main (void)
{
    int sum = 0;
    for(int val = 1; val <= 10; ++val)
    {
        sum += val;
    }
    printf("%d\n", sum);
    return 0;
}

这段程序定义了三个名字: main、sum和val, 同时使用了命名空间名字 std, 该空间提供了两个名字, cout和cin供程序使用。

名字main定义于所有的花括号之外, 它和大多数定义在函数体之外的名字一样, 拥有全局变量, 名字数码定义于main函数所限定的作用域之内, 从声明sum开始吗知道main函数结束为止都可以访问他, 但是出了main函数所在的块就无法访问了, 因此说变量sum拥有块作用域。 名字val定义于for语句内, 在for语句内可以访问val, 但是在main函数的其他部分就不能访问他。

建议:当你第一次使用的时候在定义它 
一般来说对象第一次被使用的时候地方附近定义它是一种很好的选择, 因为这样做有助于更好地容易找到变量的定义, 更重要的是, 当变量的定义与它第一次被使用的地方很近时, 我们也会赋给他一个比较合理的初值。

嵌套的作用域

作用域可以彼此包含, 被包含的作用域可以被称为内层作用域, 包含别的作用域的作用域被称之为外层作用域。

作用域中一旦声明了某个名字, 他所嵌套这的所有作用域中都能访问该名字, 同时, 允许在内层作用域中重新定义外层作用域中已有的名字。

#include<iostream>

using namespace std;

int reused = 42;
int main (void)
{
    int unique = 0;
    //访问全局变量reused
    std::cout << reused << " " << unique << std::endl;
    intreused = 0;
    //访问局部变量reused
    std::cout << reused << " " << std::endl;
    //访问全局变量reused
    std::cout << ::reused << " " << std ::endl;
    return 0;
}
// 42 42;
// 0 0;
// 42 0;

输出1:在此条语句之前只有一个reused的定义 所以输出的是全局变量中的reused; 
输出2:此条语句使用的是局部变量reused, 
输出3:使用域操作符, 来覆盖默认的作用域规则, 因为全局作用域本身并没有名字, 所以当作用域操作符的坐车为空的时候, 向全局变量发出请求获取作用域操作符右侧名字对应的变量。

*如果函数可能用到某全局变量, 则不宜再定义一个同名的局部变量

猜你喜欢

转载自blog.csdn.net/hanzefeng/article/details/81428686