程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 你好,C++(8)如何表達那些始終保持不變的數據量?3.2.2 常量,始終保持3.2.2

你好,C++(8)如何表達那些始終保持不變的數據量?3.2.2 常量,始終保持3.2.2

編輯:C++入門知識

你好,C++(8)如何表達那些始終保持不變的數據量?3.2.2 常量,始終保持3.2.2


3.2.2  常量

與變量可以用在程序中表達那些可能會發生變化的數據量相對應地,在C++中,我們用常量來表達那些始終保持不變的數據量。簡單來講,就是程序中直接使用的數值、字符、字符串以及const關鍵字修飾的常變量等。大多數時候,常量只需要被讀取一次,所以它沒有名字,無須定義而可以直接使用。又因為其數據只能讀取,不能修改,所以通常用來給一個變量賦值或者直接參與運算。例如:

// 用常量180對變量nHeight賦值
nHeight = 180;
// 直接使用常量進行計算
fArea = fR * fR * 3.1415926;

這裡的“180”和“3.1415926”就是兩個常量,分別用來對變量nHeight進行賦值和參與乘法運算。這樣的常量只能使用一次,當完成賦值操作和乘法運算後,這兩個常量也就不再有意義了。

C++中的常量主要包括數值常量(整型常數、浮點型常數)、字符常量、字符串常量。

1. 整型常數

整型常數就是以文字形式出現的整數。整型常數的表示形式最常見的是十進制,也可以根據需要采用八進制或十六進制表示。在程序中,我們可以根據數字的前綴來區分各種進制的整數。

l  十進制整數:沒有前綴,例如0、123、-1等。

l  八進制整數:以0為前綴,數字不包含8和9。例如0123、-022等。

l  十六進制整數:以0x或0X為前綴,數字除了0~9十個數字之外,還包括A~F六個英文字母字符。例如0x123、-0X2等。

在程序中,我們可以直接使用這三種方式來表示某個整數數值:

nHeight = 173;         // 十進制常數
nHeight = 0255;        // 八進制常數
nHeight = 0xAD;        // 十六進制常數

上面的代碼分別采用不同進制形式的常數對一個變量賦值。雖然這些常數的表現形式不同,但是它們所代表的數值都是173。

2. 浮點型常數

浮點型常數就是以文字形式出現的浮點數,也就是我們通常所說的小數。浮點數有兩種表示形式:小數形式和指數形式。小數形式就是我們通常的小數書寫形式,由數字和小數點構成,如1.0、0.1、.123等。而指數形式則是用科學記數法,將一個浮點數表示為一個小數與10的多少次方的乘積的形式。當一個浮點數較大或者較小時,使用指數形式來表示浮點數會更加方便。例如,1.3e9表示1.3×109,也就是1300000000,0.123E-4表示0.123×10-4等。

3. 字符常量

字符常量就是程序中使用的單個字符,如“a”、“A”、“!”等。在C++中,我們使用單引號(' ')來表示一個字符常量。例如:

// 用一個字符常量對變量aMark賦值
char aMark = 'A';
// 輸出一個字符常量‘!’
cout<<'!'<<endl;

除了上述常見的可在屏幕顯示的字符外,C++還允許使用一類特殊的字符常量。這些字符無法通過鍵盤直接輸入,也不能直接輸出顯示到屏幕,但是可以用來表示一些特殊的控制意義,比如計算機響鈴(/a)、換行(/n)、回車(/r)等。這些字符都以“\”開始,表示將“\”後的字符轉換成其他的含義,所以這些字符也被稱為轉義字符。表3-2列出了C++的常用轉義字符。

表3-2  C++中的常用轉義字符

轉義字符

意    義

'\a'

響鈴,用cout直接輸出該字符時,屏幕無顯示,但計算機喇叭會發出“滴”聲,常用來提示用戶程序完成某項操作

'\n'

換行(n: line),如果在一個字符串中有這個字符,轉義字符後的字符串將換行輸出

(還記得在2.2.2[Chen1] 小節中我們曾用到過這個轉義字符嗎?回顧一下吧!)

'\t'

制表符,輸出位置將橫向移動一個Tab的位置

'\r'

回車(r:return)

'\\'

轉義字符“\”本身

'\"'

雙引號

'\''

單引號。以上這三個轉義字符組合起來,可以輸出一些含有特殊符號的字符串。例如,我們想輸出:

這些字符都以“\”開始

這樣一個字符串,就需要用到這些轉義字符來輸出其中的特殊符號:

cout<<"這些字符都以\"\\\"開始"<<endl;

轉義字符的使用跟可顯示字符的使用相似,可以把轉義字符放到一個字符串中,讓它完成相應的控制功能,也可以單獨輸出某個轉義字符,例如:

// 將“\n“放到一個字符串中,它將控制這個字符串輸出為兩行
// 恭喜!
// 任務完成!
cout<<"恭喜!\n任務完成!"<<endl;
// 直接輸出““\a”轉義字符,發出一個計算機響鈴,提示用戶任務完成
cout<<'\a'<<endl;

4. 字符串常量

字符串常量就是由一對雙引號(" ")括起來的字符序列,如"Hello World!"。注意,因為雙引號是字符串的界限符,所以如果想在字符串中使用雙引號,就要使用轉義字符來表示。另外值得提醒的是,這裡的雙引號必須是英文的("")。因為與中文雙引號(“”)在形式上非常相似,所以常常被初學者誤用而導致錯誤。例如:

// 使用字符串常量對變量賦值
strName = "ZengMei";
// 輸出字符串常量
// 在輸出一些特殊符號(比如,雙引號,斜槓等)時,我們必須使用相應的轉義字符
// 這裡使用了轉義字符“\””來輸出字符串中的雙引號,最終輸出結果如下
// 你的名字是:”ZengMei”
cout<<"你的名字是:\"ZengMei\""<<endl;

知道更多:原生字符串(raw string)標識

在字符串常量中,我們可以使用反斜槓(\)這個轉義操作符來引入一些特殊字符,實現特殊的輸出目的。然而,這卻給正則表達式的書寫帶來了麻煩,因為在正則表達式中,反斜槓成了用於引入表示字符的特殊符號,並且使用非常頻繁。如果想在正則表達式中表示反斜槓這個字符,我們不得不使用兩個反斜槓來表示一個反斜槓字符。例如,我們要表達“被反斜槓(\)分隔開的兩個單詞”這樣一個模式(\zeng\\\mei),在C++代碼中就成了:

string s = "\\zeng\\\\\\mei";   // 這樣的表示很不直觀、且容易出錯

我們注意到,在正則表達式中,反斜槓字符被表達為兩個反斜槓的組合。為了表示一個反斜槓,我們必須在正則表達式中使用兩個反斜槓來表示。第一個反斜槓表示這是一個轉義字符,第二個才表示真正的反斜槓。這樣的表達方式,會讓我們的字符串變得非常復雜繁瑣,很不直觀,即使是經驗豐富的程序員也很容易出錯。

為了解決這個問題,C++11引入了原生字符串的機制,並使用原生字符串標識符R來表示一個原生字符串。在原生字符串中,每個字符都代表其最原始的字符意義,所見即所得。換句話說,也就是反斜槓(\)不再具有轉義符的作用,一個反斜槓僅用一個反斜槓字符就可以表示。因而,上述的例子可以簡化為:

string s = R"(\zeng\\mei)";        // 使用R"()"表示的原生字符串

原生字符串的R"(...)"記法相比於普通字符串的"..."記法會有一點點的冗長,但它的意義就在於它可以讓字符串中的轉義規則無效,所寫即所得,所見即所得。當我們需要在字符串中頻繁地表示各種特殊符號(反斜槓,引號等)的時候,原生字符串將非常簡便,而這一點點書寫上的冗長也是值得的。

無論是數值常量還是字符串常量,它們都像C++世界的“雷鋒”,只做好事而不留名字。可是,這樣也帶來了一個麻煩:當我們在程序中需要重復多次地使用某個常量時,我們不得不在代碼中一遍又一遍地書寫同一個常量。例如,要編寫一個有關圓的計算程序,無疑會多次用到3.14159這個浮點常數:

float fR = 19.82;  // 半徑
// 用常數3.14159計算面積
float fArea = 3.14159 * fR * fR;
// 用常數3.14159計算周長
float fGirth = 2 * 3.14159 * fR;

這樣的代碼,不僅書寫起來非常困難(多次重復書寫同一個小數,難以保證正確性和一致性),在後期也難以維護(如果想改變這個常數,我們不得不修改所有用到這個常數的地方)。這一切,都是因為常量在程序中無名無份,每次都是直接使用引起的。那麼,解決的辦法自然就是給常量取一個名字,讓我們可以通過這個名字方便地重復多次使用同一個常量。在C++中,給常量取一個名字的方法有兩種:

1.用#define預編譯指令將數值或字符串定義成宏,然後用宏來代替常量的直接使用

2.用const關鍵字將一個變量修飾成常變量,然後用常變量來代替常量的直接使用

我們首先來看如何用宏來代替常量。所謂的宏,就是將某個無明確意義的數值(例如,3.14159,知道的認為是圓周率,不知道的認為只是某個奇怪的數字)定義為某個有明確意義的標識符(例如,PI,所有人都會認為是圓周率)。然後,就可以在代碼中使用這個有意義的標識符來代替無明確意義的數值,從而使代碼更具可讀性。在C++中,可以使用#define預編譯指令來定義一個宏:

#define 宏名稱 宏值

其中,“宏名稱”就是要定義的宏,通常用一個大寫的有意義的名稱來表示。“宏值”就是這個宏所代表的內容,它可以是一個常數、一個字符串,甚至是一個更加復雜的語句。比如,可以用下面的語句將3.14159定義為一個宏PI:

// 將3.14159定義成宏PI
#define PI 3.14159

有了常數3.14159所對應的宏PI之後,我們就可以在代碼中直接使用PI來代替3.14159進行相應的計算。例如,上面的代碼可以簡化為:

// 將3.14159定義成宏PI
#define PI 3.14159

 
float fR = 19.82;  // 半徑
// 用PI計算面積
float fArea = PI * fR * fR;
// 用PI計算周長
float fGirth = 2 * PI * fR;

這裡,使用PI代替了原本應該使用的3.14159也同樣可以完成計算。那麼,宏是如何做到這一點呢?這裡的宏PI並不是真正地具有了它所代表的3.14159這個常數的值,從本質上講,宏只是一種替換。當編譯器對代碼進行預編譯處理的時候,它會將代碼中的宏替換為它所代表的內容,換而言之,也就是上面代碼中的PI會被替換為3.14159,最終參與編譯的代碼實際上仍舊是:

// 宏PI被替換為常數3.14159計算面積
float fArea = 3.14159 * fR * fR;

// 宏PI被替換為常數3.14159計算周長
float fGirth = 2 * 3.14159 * fR;

從這裡可以看到,宏的使用並沒有減少代碼中的常數,但是它用一種巧妙的方法,減少了重復輸入某個常數的繁瑣,避免了可能發生的書寫錯誤。

最佳實踐:使用宏提高代碼的可讀性與可維護性

除了減少代碼重復避免書寫錯誤之外,宏的使用還會給我們帶來額外好處:

1. 讓代碼更簡潔明了,更具可讀性

一個意義明確的宏名稱往往比一個復雜而無意義的常數數字包含了更加豐富的信息,可以增加代碼的可讀性;同時,宏比常數數字更簡單,可以使代碼更簡潔。對比下面兩段代碼:

// 不使用宏的代碼
for( int i = 0; i < 1024; ++i )
{
    // ...
}

// 使用宏的代碼
#define MIN 0
#define MAX 1024

for( int i = MIN; i < MAX; ++i )
{
    // ...
 }

通過對比我們可以發現,雖然兩段代碼實現的功能是一樣的,但是給代碼閱讀者的信息卻不大相同。第一段代碼只是表示這個循環是從0到1024之間,至於為什麼是從0到1024,只能讓代碼閱讀者自己去猜測了。第二段代碼則通過宏的使用,明確地告訴了我們這個循環是在最小值和最大值之間進行的,這樣可以從代碼本身獲得更加豐富的信息,增加了代碼的可讀性。

2. 讓代碼更加易於維護

如果我們在代碼中直接多次使用某個常數數字,而恰好這個數字需要修改,那麼我們不得不修改代碼中所有使用這個數字的地方。而如果是將這個常數定義成宏,並在代碼中使用宏來代替這個常數,當我們需要修改這個常數時,只需要修改宏的定義就可以了,而無需修改代碼中所有使用這個宏的地方。例如,我們將3.14159這個常數定義成PI這個宏並用它參與計算,當我們需要降低精度使用3.14進行計算時,只需修改PI的定義,將3.14定義成PI即可:

// 修改PI的定義
#define PI 3.14

// 使用3.14作為圓周率計算面積
float fArea = PI * fR * fR;

 

除了用#define定義的宏可以表示常數之外,C++還提供了const關鍵字,使用它可以將一個變量修飾成一個數值不可修改的常變量,也可以用來表示程序中的常數。

const關鍵字的使用非常簡單,只需要在定義變量的時候,在數據類型前或後加上const關鍵字即可:

const 數據類型 常變量名 = 常量值;

這裡的const關鍵字會告訴編譯器,這個變量的數值不可修改(或者更嚴格地說,不可以通過這個變量名直接修改它所表示的數值,而通過其他方式間接地修改是可以的),這就使得這個變量具有了一個常數最基本的特征:不可修改。所以,經過const關鍵字的修飾,這個變量就成了一個常變量,可以用來表示程序當中的各種常數。需要特別注意的是,因為常變量的值在定義後便不可以修改,所以必須在定義常變量的同時完成它的賦值。例如:

// 定義常變量PI
const double PI = 3.14159;

// …

// 用常量PI計算面積
float fArea = PI * fR * fR;
// 用常量PI計算周長
float fGirth = 2 * PI * fR;

而在定義之後,如果試圖通過這個常變量名來修改它所表示的值,則會導致一個編譯錯誤,以此來保證這個變量的數值不會被修改而成為一個常變量。例如,如果想在程序中降低PI的精度,偷工減料是不行的:

// 錯誤:不能修改const常變量的值
PI = 3.141;

既然宏和const關鍵字都可以用來給常數一個名分,那麼該如何選擇呢?要表示常數的時候,到底是用宏還是用const關鍵字?我們的回答是:應該更多地選擇使用const關鍵字。比如,要想在程序中表示3.14159這個常數,可以采用以下兩種方式:

// 宏方式
#define PI 3.14159

// const方式
const double PI = 3.14159;

這兩種方式在語法上都是合法的,在使用上也並沒有什麼太大區別。但是第二種方式要比第一種方式好,因為如果使用#define將這個常數定義成宏PI,PI會在代碼的預編譯階段被預編譯處理器替換成3.14159這個常數本身,這樣就沒有了編譯器的數據類型檢查, 並且,宏的名稱不會出現在符號表中,這樣會給代碼後期的調試帶來麻煩,可能會遇到一個數字,卻不知道它從何而來,這就是我們常說的Magic Number(像擁有魔力一樣不知從何而來的數字)。而使用const將這個常數表示成一個常變量,它是擁有數據類型的,編譯器可以對其進行數據類型檢查,避免錯誤的發生。同時這個常變量名也會出現在程序的符號表中,便於程序的調試。所以,我們總是優先使用const關鍵字修飾的常變量來表示程序中的常數。


 [Chen1]確認


C語言題目:以下正確的實型常量是() A、E34 B、-12345 C、22e08 D、4 問D為何不對?

4是整型常量,而非實型常量。
 

java有什基本數據類型,他們的常量又是怎表示

int a = 3 ;
byte b = 4 ;
short c = 5 ;
long d = 8L ;
float e = 9.2f ;
double f = 12.1 ;
boolean g = false ;
char ch = 'a';

常量的話,前面加 static final
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved