變量
變量提供一個具體、可供程序操作的存儲空間。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:使用域操作符, 來覆蓋默認的作用域規則, 因爲全局作用域本身並沒有名字, 所以當作用域操作符的坐車爲空的時候, 向全局變量發出請求獲取作用域操作符右側名字對應的變量。
*如果函數可能用到某全局變量, 則不宜再定義一個同名的局部變量