變數 (程序設計)

維基百科,自由的百科全書
前往: 導覽搜尋

程序設計中,變數是指一個包含部分已知或未知數值或資訊(即一個)之儲存位址,以及相對應之符號名稱識別字)。通常使用變數名稱參照儲存值;將名稱和內容分開能讓被使用的名稱獨立於所表示的精確訊息之外。電腦原始碼中的識別字能在執行期綁紮一個,且該變數的值可能在程式執行期間改變。 程序設計中的變數不一定能直接對應到數學中所謂的變數之概念。在程序設計中,變數的值不一定要為方程數學公式之一部分。程序設計中的變數可使用在一段可重復的程序:在一處賦值,然後使用於另一處,接著在一次賦值,且以相同方式再使用一次(見迭代)。程序設計中的變數通常會給定一個較長的名稱,以描述其用途;數學中的變數通常較為簡潔,只給定一、兩個字母,以方便抄寫及操作。

一個變數的儲存位址可以被不同的識別字所參照,這種情況稱之為別名。使用其中一個識別字為變數賦值,將會改變透過另一個識別字存取的值。

編譯器必須將代表變數的名稱替代成該數據所在的實際位址。變數的名稱、類型及位址通常會維持固定,但該位址所儲存之數據於程式執行期間則可能會改變。

用標識符引用變數[編輯]

用標識符引用變數能對變數進行訪問,從而讀出變數的值,改變變數的值,或者改變變數的屬性(如訪問許可權、狀態鎖定等)。

例如,一個變數用標識符total_count來引用,設定這個變數的值為1981。如果該變數同時也用標識符x 來引用,通過x將變數值改變為2010,那麼讀取total_count的值就是2010而不是1981。

如果某種程式語言只允許同一個變數用一個標識符引用,那麼討論「該變數的名字」就是有意義的,否則我們稱之為「該變數的名字之一」。例如,在前面的那個例子當中,total_count是這個變數的名字之一,而x是這個變數的另外一個名字。

對變數的操作[編輯]

指令式程式語言中,變數的值通常能夠隨時訪問或重新賦值。但在邏輯編程語言中,根據參數透明的需求,變數被綁定到表達式並且在它的整個生命周期中保持同一個值。在指令式程式語言中,同樣的行為用常量來表達,它和通常的變數存在反差。

根據程式語言的類型系統的不同,變數可能只存儲一種特定的數據類型(如整型字元串型)。而另外一種情況,變數的數據類型能根據當前賦值而改變,允許單個變數存儲該程式語言支持的任何數據類型。

命名規範[編輯]

數學當中的量不同,程序設計所用的變數和常量通常都採用多字元的名字,如count或者size。而單個字元的名字一般僅用於輔助性的變數,如ijk常作為數組索引的變數。

一些命名規範是作為語法在語言層面強制執行的。在大多數語言當中,變數名不能以數字開頭,不能包含空格符。而標點符號是否允許存在在變數名當中就要視具體語言而定了。很多語言僅僅允許下劃線(_)存在在變數名當中,而禁止其他所有的標點符號;而有些程式語言,特殊字元作為前綴或後綴添加在變數標識符當中來表明變數的類型。變數名的大小寫敏感性也要視具體語言而定。大多數現代語言是大小寫敏感的,一些較老的語言則不敏感。一些語言保留特定形式的變數名用來內部使用,在很多語言中,以兩根下劃線開頭(__)的變數名常充當這種角色。

在語言語法基本的限制以外,進一步的命名風格規範也很有必要。在機器碼層面,是不會使用變數名的,所以計算機並不關心是否採用了準確的名字。正因為如此,變數名完全是作為程式設計師的工具而存在,藉助這個工具程式設計師能更容易的編寫和理解程序。程式設計師通常創建編碼規範,並且堅持這些規範,幫助對變數命名甚至提供精確的命名規劃。較短的名字便於輸入,但是描述能力較差;較長的名字使程序更容易讀懂,變數的意圖更容易理解。儘管如此,冗長的變數名也可能會導致更難理解的代碼。

在原始碼中[編輯]

原始碼中,變數名是將變數和內存地址綁定的一種方式。變數值以數據對象的形式存儲在相應的地址內,這樣該數據對象就能通過變數的名字進行訪問和修改了。

在電子表格中[編輯]

電子表格中,一個單元格可能包含參考其他單元格的公式。這種被參考的單元格就是一種形式的變數,它的值就是被參考的單元格的值。

作用域和生存周期[編輯]

變數的作用域表示變數在原程序的文本中能被使用的範圍。變數的生存周期表示變數在程序運行過程中具有實際意義的值的時間範圍。變數的作用域事實上是變數名字的性質,而變數的生存周期是變數本身是性質。

變數名字的作用域會影響它的生存周期。

作用域是變數語法方面的性質。多數語言對每一個變數(和其他名目實體)定義明確的作用域,這些作用域在同一個程序中可能不同。變數的作用域是指程序中的特定區域,在這些區域中,該變數的名字是有意義的並且變數是「可見的」。在進入作用域時,變數通常開始它的生命周期;而在離開作用域時,變數往往結束了它的生命周期。例如,某個變數的語法作用域僅在特定的語句塊或者子程序中。只有在某個函數中能訪問的變數則被稱為局部變數,在程序的任何一個地方都能引用的變數被稱為全局變數

生存周期,則是變數在運行時的性質。在運行時,每次變數與值的綁定都具有自己的生存周期。綁定的生存周期是程序執行過程中的一段時間,在這段時間內,變數始終被關聯到相同的值或者內存位置。在閉包的情況中,運行中的程序可能進入和離開某個生存周期很多次。

在一些代碼段中,在一個變數的作用域中可能未被賦值,或者它的值已經被銷毀掉了。這類變數常被稱為「生存周期外」或者「未綁定」。在很多語言中,試圖使用未綁定的變數是一個錯誤。在其他語言中,這種行為會產生不可預期的結果,這樣的變數可能被分配一個新的值。與之對照的是,一個變數綁定到一個超過他作用域的生存周期是被允許的,如Lisp的閉包和C語言的靜態局部變數。當程序再次執行到變數的作用域時,變數能再次被使用,但還保持上一次的值。

為了提高空間效率,變數需要的存儲空間可能要等到變數第一次使用時才申請,不再使用後就刪除。為了避免浪費空間,如果變數聲明了但不實際使用,編譯器通常會向程式設計師發出警告。

使變數的作用域儘可能的小,被認為是一個好的編程方式,這樣程序的不同部分就不會因為意外的改變對方的變數而互相影響了。實現上述目標的通常技術是讓程序的不同部分使用不同名字空間,或者通過動態變數作用使用各自的私有變數

很多程式語言使用保留的值(如NULL)表示沒有初始化的變數。

類型[編輯]

靜態類型語言中,如JavaML,每個都變數有一個類型,也就是說只有給定種類的值能存儲到該變數中。一個基本類型的變數只能保存基本類型的值。一個類類型的變數能保存空值NULL,或者保存該類型或其子類型的對象。一個介面類型的變數能保存空值NULL,或者該介面的任何一個實現。一個數組類型能保存空值NULL或者一個數組。

動態類型語言中,如Python,是值,而不是變數來攜帶類型信息。在Common Lisp中,這兩種情況同時存在:變數在編譯時具有一個類型(如果沒有聲明,就假設這個類型為超類型T);值也有具有一個類型,該類型可以在運行時進行檢查和識別。

變數的類型也允許在編譯時多態決定。但是,這和物件導向的函數調用(在C++中稱為虛函數)的多態不同。

變數常常保存簡單的數據,如整數字元串。但有些程式語言允許變數同時表示多種數據類型。這些語言一般也允許函數參數多態,其函數對變數的操作可同時適用於多種數據類型。例如,函數length可以求一個列表的長度,如果length類型簽名中包含一個類型變數,就可以實現參數多態。這樣,求列表中的元素個數就與列表元素的類型無關了。

參數[編輯]

函數的形式參數也被稱為變數。如下的C++代碼段:

int AddTwo(int x)
{
    return x + 2;
}
 
AddTwo(5);  // 结果为7

變數x是「形參」,因為當函數被調用時會被給定一個值。整數5是「實參」,它給x一個值。在多數語言中,函數參數具有局部的作用域。這裡的變數x只能在AddTwo函數中有效(儘管如此,其他函數也可以使用自己的變數x)。

內存分配[編輯]

變數的內存空間分配和它們值的表示方法是多種多樣的,這種區別體現在語言之間,也體現在給定語言的內部使用上。很多語言都實現了局部變數的空間分配方式。局部變數保存在調用堆疊上,其生存周期維持在單個函數中,函數返回時這些內存會自動被回收。(更一般的講,變數的名字是和一些特定的連續內存塊的地址綁定,對變數的操作其實是對相應的內存塊進行操作。)對於巨大或者編譯時不知道大小的數據,更常用的方法是使用「引用」。 這時記錄是值的地址而不是值本身,它們是從一種被稱為的內存池中分配的。

綁定的變數具有值,一個抽象的值。在程序執行時,變數的值用計算機內存中存儲的一些數據對象來表示。程序,或者說運行時環境,必須為每個數據對象設置內存。由於內存是有限的,為了安置每一個數據對象,當數據對象不再表示某個變數的值時,相應的內存會被回收並重新使用。

在堆中分配的對象必須被釋放掉,特別是當對象不再被需要時。在具有垃圾回收機制的語言(如C#JavaLisp)中,當變數出了其作用域再也不能被引用時運行環境會自動地回收對象。在不具有垃圾回收機制的語言當中,如C語言,程序(程式設計師)必須顯式地分配內存,而且用完之後還要釋放內存。如果沒有這樣做會造成內存泄漏,在這種情況下,程序運行過程中會逐漸消耗,最終因為內存耗盡而崩潰。

當一個變數指向動態創建的資料結構時,可能其中一些部分只能通過變數間接的訪問。在這種環境下,垃圾回收器(或者類似的語言特性)必須處理當變數回收時只有一部分內存能夠獲得的情況。

名字替換[編輯]