數據

程序是對數據進行操作的。

基本數據類型

在C語言中,僅有4中基本數據類型:

  • 整型
  • 浮點型
  • 指針
  • 聚合類型

整型

整型家族包括字符、短整型、整型、長整型。

而整型家族中的每一種類型分爲有符號的和無符號的。

具體如下圖所示:

這裏寫圖片描述

注意,儘管設計char類型變量的目的是爲了讓他們容納字符型值,但字符在本質上是整型值(例如,ASCII碼)。

只有當char型變量顯示聲明爲singed或unsinged時,纔對它指向算術運算。

整型字面值常量

字面值常量是一種實體,其指定了自身的值,並且不允許發生改變。

對於整數字面值常量而言,當一個程序內出現整數字面值常量時,它是屬於整數6種不同類型的哪一種呢?

答案取決於整數字面值是如何書寫的。

  1. 其中最自然的方式是十進制整型值。
  2. 整數也可用八進制來表示,只要在數值前面以0開頭。
  3. 整數也可以用十六進制來表示,它以0x開頭。

但是,我們可以在有些整數字面值後面添加一個後綴來改變默認的規則。

  • 在整數字面值後面添加L或l,可以使這個整數被解釋爲long整型值。
  • 在整數字面值後面添加U或u,可以使這個整數被解釋爲unsigned整型值。
  • 如果在一個整數字面值後面添加這兩組字符中的各一個,那麼它就被解釋爲unsigned long整型值。

對於字符字面值常量而言,它就是一個用單引號包圍起來的單個字符。

字符字面值常量類型總是int,所以我們不能在它後面添加unsigned或long後綴。

但是,我們可以在字符字面值常量前面加L,表示其實寬字符常量。

浮點類型

浮點數通常以一個小數以及一個以某個假定數爲基數的指數組成。

浮點數家族包括單精度float類型、雙精度double、擴展精度long double類型。

浮點數字面值常量總是寫成十進制形式,它必須有一個小數點或一個指數,也可以兩者都用。

浮點數字面值常量在默認情況下都會double類型的。除非我們在其後面添加L或l表示它是一個long double類型的值。或在其後面添加一個F或f表示它是一個float類型的值。

基本聲明

變量聲明的基本形式是:

說明符(一個或多個) 聲明表達式列表

  • 說明符包含了一些關鍵字:
    • 用於描述被聲明的標識符的基本類型。
    • 用於修改變量的長度或是否爲有符號數的關鍵字。
    • 用於改變標識符的默認存儲類型和作用域。
  • 對於簡單的類型來說,聲明表達式列表就是被聲明的標識符的列表。
int i;
char j , k , l;

注意:

  1. 在聲明整型變量時,如果聲明中已經至少有了一個其他的說明符,關鍵字int可以省略。
  2. 除char類型之外,其他整型類型在默認情況下都是有符號數。

初始化

在聲明中,我們可以給一個標量變量指定一個初始值。

int i = 15;

聲明簡單數組

聲明一個一維數組,在數組名後面要跟一對方括號,方括號裏面是一個整數,指定數組中元素的個數。

int values[20];/*聲明一個整型數組,數組包含20個整型元素*/

注意:數組的下標總是從0開始,最後一個元素的下標是元素的數目減1。

聲明指針

int *a;

聲明指針變量的同時,我們可以給其指定初始值。

char *message = "Hello,World!";

等價於

char *message;
message = "Hello,World!";

關鍵字typedef

typedef允許我們爲各種數據類型定義新名字。

typedef char* ptr_to_char;
ptr_to_char a;/*a是一個指向字符的指針*/

關鍵字const

const聲明的常量和變量完全一樣,只是它們的值不能修改。

const int a;

由於我們無法給修改常量,我們也就無法給a賦值,所以我們必須在聲明a的同時給其賦予初始值。

const int a = 15;

注意:在函數聲明爲const的形參在函數被調用時會得到實參的值。

對於指針而言,常量const這一概念就會更復雜了!

指針和常量混在一起有兩種情況:

  • 指針是常量。

    • int *const p ;
    • 指針的值無法修改,但是指針指向的值可以修改。

  • 指針指向的數據是常量。

    • const int *p;
    • 指針指向的值無法修改,但是可以修改指針的值。

變量

變量擁有三個屬性,這三個屬性決定了一個變量的“可視性”(在什麼地方使用)和“生命期”(值將保存多久)。

  1. 作用域
  2. 鏈接屬性
  3. 存儲類型

作用域

當變量在程序的某個部分被聲明時,它只有在程序的一定區域才能被訪問,這個區域由標識符的作用域決定。

標識符的作用域就是程序中該標識符可以被使用的區域。

標識符聲明的位置決定它的作用域。

編譯器可以確認4種不同類型的作用域:

  • 文件作用域
    • 任何在所有代碼之外聲明的標識符都具有文件作用域,它表示這些標識符從它們的聲明指出知道它所在的源文件結尾處都是可以訪問的。
    • 在文件中定義的函數名也具有文件作用域,因爲函數名本身並不屬於任何代碼塊。
  • 函數作用域
  • 代碼塊作用域
    • 位於一對花括號之間的所有語句稱爲一個代碼塊。
    • 任何在代碼塊的開始位置聲明的標識符都具有代碼塊作用域,表示它們可以被這個代碼塊中的所有語句訪問。
    • 函數定義的形式參數在函數體內部也具有代碼塊作用域。
  • 原型作用域
    • 原型作用域只適用於在函數原型中聲明的參數名。
    • 原型作用域防止這些參數與程序其他部分的名字衝突。
    • 在函數原型中,參數的名字不是必需的。但是如果我們想給予參數名,我們可以給它們取任何名字,同時不必與函數定義中的形參名匹配,也不必與函數實際調用時所傳遞的實參匹配。

這裏寫圖片描述

鏈接屬性

當組成一個程序的各個源文件分別被編譯之後,所有的目標文件以及那些從一個或多個函數庫中引用的函數鏈接在一起,形成可執行程序。

但是,相同的標識符出現在幾個不同的源文件中,那麼它們是表示同一個實體,還是不同的實體呢?

這取決於這些標識符的鏈接屬性。

標識符的鏈接屬性決定如何處理在不同文件中出現的標識符,一共有三種:

  • none(無)
    • 沒有鏈接屬性的標識符總是被當做單獨的個體,也就是說該標識符的多個聲明被當做獨立不同的實體。
  • external(外部)
    • external鏈接屬性的標識符不論聲明多少次、位於幾個源文件中,都表示一個實體。
  • internal(內部)
    • internal鏈接屬性的標識符在同一源文件內的所有聲明中都指向同一個實體,但是位於不同源文件的多個聲明則分屬於不同的實體。

關鍵字static

如果某個聲明在正常情況下具有external鏈接屬性,在它前面加上static關鍵字可以使它的鏈接屬性變爲internal。

static int b;/* 變量b爲源文件私有*/
static int c(int d); /*函數c爲源文件私有,防止其他源文件對其調用*/

關鍵字extern

關鍵字extern爲一個標識符指定external鏈接屬性,這樣就可以訪問在其他任何位置定義的這個實體了。

注意:當extern關鍵字用於源文件中一個標識符的第一次聲明時,它指定該標識符具有external鏈接屬性。

但是,如果它用於該標識符的第二次或以後的聲明時,它並不會更改由第一次聲明所指定的鏈接屬性。

static int i;
int func()
{
    int j;
    extern int k;
    extern int i;
}

存儲類型

變量的存儲類型是指存儲變量值的內存類型。

變量的存儲類型決定了變量何時創建、何時銷燬以及它的值將保存多久。

變量的默認存儲類型取決於它的聲明位置。

有三個地方可以用於存儲變量:

  • 普通內存
    • 凡是在任何代碼塊之外聲明的變量總是存儲於靜態內存中,就是不屬於堆棧的內存,這類變量稱爲靜態變量。
    • 靜態變量在程序運行之前創建,在程序的整個執行期間始終存在。它始終保持原先的值,除非給它賦一個不同的值或程序結束。
  • 運行時堆棧
    • 在代碼塊內部聲明的變量的默認儲存類型是自動的,也就是說它存儲於堆棧中,稱爲自動變量。
    • 在程序執行到聲明自動變量的代碼塊時,自動變量才被創建,當程序的執行流離開該代碼時,這些自動變量便自行銷燬。
  • 硬件寄存器
    • 關鍵字register可以用於自動變量的聲明,提示它們應該存儲於機器的硬件寄存器而不是內存中,這類變量稱爲寄存器變量。

關鍵字static

對於在代碼塊內部聲明的變量,如果給它們加上關鍵字static,可以使它們的存儲類型從自動變爲靜態。

具有靜態存儲類型的變量在整個程序執行過程中一直存在,而不僅僅在聲明它的代碼塊的執行時存在。

但是,修改變量的存儲類型並不表示修改了變量的作用域,它仍然只能在該代碼塊內部按名字訪問。

靜態變量和自動變量的初始化

在靜態變量的初始化中,我們可以把可執行程序文件想要初始化的值放在當程序執行時變量將會使用的位置。當可執行文件載入內存時,這個已經保存了正確初始值的位置將被賦值給那個變量。

完成這一任務不需要額外的時間,也不需要額外的指令,變量將會得到正確的值。

如果不顯示地指定其初始值,靜態變量將初始化爲0。

對自動變量而言,當程序連接時無法判斷自動變量的存儲位置,所以自動變量沒有默認初始值。

並且,顯示的初始化將在代碼塊的起始處插入一條隱式的賦值語句。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章