C 速查手冊

單元 6 - 衍生資料型態

C 語言亦提供一些的衍生資料型態,包含可囊括多筆資料的同質陣列 (array) 與異質結構 (structure) ,另外有可處理記憶體位址的指標 (pointer) , C 語言執行的基本單位函數 (function) 等

指標

指標是用來指向儲存指向某個記憶體位址的資料型態 (data type) ,實際上我們須認識電腦管理記憶體好比一個長列,每一列都有以位元編碼的位址,每一位址都可儲存位元編碼的資料,示意圖如下

0000 ▭▭▭▭
0001 ▭▭▭▭
0010 ▭▭▭▭
0011 ▭▭▭▭
0100 ▭▭▭▭
0101 ▭▭▭▭
0110 ▭▭▭▭
0111 ▭▭▭▭
1000 ▭▭▭▭
 ↓   ↓
位址  內容

例如,我們宣告並指派初值 22 給整數變數 (variable) a ,編譯器 (compiler) 將變數 a 放在 0011 的記憶體位址裡,稍後我們再宣告另一個指向 a 的指標變數 aPtr ,假設編譯器 aPtr 放在 0111 的記憶體位址裡,如下圖所示

0000 ▭▭▭▭   45
0001 ▭▭▭▭   98
0010 ▭▭▭▭  509
0011 ▭▭▭▭   22    a
0100 ▭▭▭▭ 1234
0101 ▭▭▭▭    0
0110 ▭▭▭▭  382
0111 ▭▭▭▭ 0011 aPtr
1000 ▭▭▭▭ 9000
 ↓   ↓     ↓   ↓
位址  內容   數值  變數
其他記憶體位址的數值可能為殘值,意思是如果沒有被程式利用,就對程式沒有用處。

因此,指標變數 aPtr 的內容為變數 a 的記憶體位址,如下

0000 ▭▭▭▭   45
0001 ▭▭▭▭   98
0010 ▭▭▭▭  509
0011 ▭▭▭▭   22    a
0100 ▭▭▭▭ 1234      ↖
0101 ▭▭▭▭    0       ↑
0110 ▭▭▭▭  382       ↑
0111 ▭▭▭▭ 0011 aPtr ↗
1000 ▭▭▭▭ 9000
 ↓   ↓     ↓   ↓
位址  內容   數值  變數

宣告 C 語言的指標變數,格式如下

datatype *name;

* 為宣告指標所用的運算子 (operator) ,注意這跟乘法運算子一樣,編譯器會依上下文判斷星號用為宣告指標,還是用為兩數相乘。

下列程式示範宣告指標變數,然後印出該變數所指向的值

#include <stdio.h>

int main(void)
{
    int a = 22;
    int *aPtr = &a;
    
    printf("*aPtr = %d\n", *aPtr);
    
    return 0;
}

/* 《程式語言教學誌》的範例程式
    http://kaiching.org/
    檔名:simpleptr.c
    功能:示範宣告指標變數,然後印出該變數所指向的值
    作者:張凱慶 */

編譯後執行,結果如下

$ gcc simpleptr.c
$ a.out
*aPtr = 22
$

宣告並建立指標變數的地方

int *aPtr = &a;

後面的 & 為取址運算子,作為取得該變數的記憶體位址,注意這也跟位元運算的逐位元且是相同的符號。

印出指標變數的地方

printf("*aPtr = %d\n", *aPtr);

tsetPtr 為指標變數,宣告時使用 * ,而後若要取得該變數所指向的值,同樣也是利用 *

請參考 C 速查手冊 - 指標有更詳細的敘述。

陣列

C 語言中的陣列為同質的資料結構,這意思是說陣列中只能存放相同資料型態的資料體,每個資料體被稱為陣列的元素,宣告格式如下

datatype name[number];

宣告陣列須先指明這個陣列為何種資料型態,接著是陣列名稱,然後用中括弧圍起來的元素數量。注意,中括弧 [] 在 C 語言中為陣列專用,因此帶有中括弧的識別字名稱即為陣列,陣列宣告或定義無須特別的關鍵字。

例如下列整數陣列中存放 3 個整數

#include <stdio.h>

int main(void)
{
    int a[3] = {3, 2, 1};
    int i;
    
    for (i = 0; i < 3; i++) {
        printf("a[%d] = %d\n", i, a[i]);
    }
    
    return 0;
}

/* 《程式語言教學誌》的範例程式
    http://kaiching.org/
    檔名:simplearray.c
    功能:示範宣告指標變數,然後印出該變數所指向的值
    作者:張凱慶 */

編譯後執行,結果如下

$ gcc simplearray.c
$ a.out
a[0] = 3
a[1] = 2
a[2] = 1
$

宣告並建立陣列變數的地方

int a[3] = {3, 2, 1};

這是宣告後直接指派陣列中的值,注意,像陣列這樣的複合資料型態中給值可以用大括弧圍起來,然後每個元素用逗號分開。

印出陣列元素的地方

printf("a[%d] = %d\n", i, a[i]);

a[i] 中的 i 為陣列的索引,代表陣列中的元素項目, C 語言陣列的索引是從 0 開始的。

請參考 C 速查手冊 - 陣列有更詳細的敘述。

結構

C 語言中的結構為異質的資料結構,這意思是說結構中可以存放不同資料型態的資料體,每個資料體被稱為結構的成員,定義格式如下

struct name {
    datatype var1;
    ...
}

宣告定義關鍵字 struct ,接著是結構名稱,然後用大括弧圍起來的成員宣告,須留意結構定義完的右大括弧其後接分號。

以下程式示範結構的定義與使用,同時簡單利用 typedef 定義新的資料型態名稱

#include <stdio.h>

struct test {
    int i;
    int j;
};

typedef struct test Test;

int main(void)
{
    Test a;
    a.i = 11;
    a.j = 22;
    
    printf("a.i = %d, a.j = %d\n", a.i, a.j);
    
    return 0;
}

/* 《程式語言教學誌》的範例程式
    http://kaiching.org/
    檔名:simplestruct.c
    功能:示範結構的定義與使用,同時簡單利用 typedef 定義新的資料型態名稱
    作者:張凱慶 */

編譯後執行,結果如下

$ gcc simplestruct.c
$ a.out
a.i = 11, a.j = 22
$

先注意到使用關鍵字 typedef 的地方

typedef struct test Test;

將結構 test 的名稱改訂為 Test ,注意大小寫的識別名稱在 C 語言中是不同的。如果沒有改訂名稱的話,在宣告該結構名稱必須連用 struct ,如下

struct test a;

而改成自訂名稱後,就可直接用自訂的 Test 宣告建立結構變數

Test a;
a.i = 11;
a.j = 22;

小數點 . 為結構成員運算子,可依此指派數值給成員,或是如底下印出部分存取結構成員。

請參考 C 速查手冊 - 結構有更詳細的敘述。

聯合

聯合為早期 C 語言為了解決記憶體不足而有的資料型態,其定義與宣告與結構類似,不同之處為聯合的所有成員佔用相同的記憶體空間,因此儲存到聯合的值會以該成員具有儲存範圍最大的資料型態為優先,也就是佔用到最多位元組數的資料型態。

聯合的定義格式如下圖

union name {
    datatype var1;
    ...
}

通常聯合中只能使用其中一個成員,如下例

#include <stdio.h>

union test {
    int i;
    double j;
};

int main(void)
{
    union test a;
    
    a.i = 11;
    printf("a.i = %d, a.j = %f\n", a.i, a.j);
    
    a.j = 22.0;
    printf("a.i = %d, a.j = %f\n", a.i, a.j);
    
    return 0;
}

/* 《程式語言教學誌》的範例程式
    http://kaiching.org/
    檔名:simpleunion.c
    功能:示範聯合的使用
    作者:張凱慶 */

編譯後執行,結果如下

$ gcc simpleunion.c
$ a.out
a.i = 11, a.j = 0.000000
a.i = 0, a.j = 22.000000
$

double 型態為此例中佔用最多的位元組數,因此當聯合 testdouble 成員被指派初值後, int 成員就被歸 0 ,不過實際情況會隨編譯器、系統而有所不同。

請參考 C 速查手冊 - 聯合有更詳細的敘述。

函數

函數是利用 C 語言寫程式的模組單位, C 程式的執行是以函數為單位的,語言保留函數名稱 main 作為每個 C 程式執行的起始點,因此,所有可執行的 C 程式都需要一個名為 main() 的函數。

自行定義函數的目的是將程式的功能切割為不同的模組,需要時再以呼叫的方式使用該函數所提供的功能。

通常含定義前可先宣告函數原型,格式如下

datatype name(datatype, ...);

函數宣告及定義都須指明回傳值 (return value) 的型態,然後才是函數的識別字名稱,接著緊隨小括弧,小括弧內為參數列 (parameter list) ,參數 (parameter) 是函數定義中提供給函數進行計算的數值。

C 語言的函數可以有回傳值,也可以沒有回傳值,若沒有回傳值的函數須用關鍵字 void 宣告。同樣的,函數可以有參數,也可以沒有參數,沒有參數的函數,可在宣告及定義時將 void 放到參數列的小括弧中。

下面以沒有回傳值及參數的函數為例

#include <stdio.h>

void test(void);

int main(void)
{
    test();
    test();
    
    printf("程式成功執行結束\n");
    
    return 0;
}

void test(void)
{
    printf("呼叫函數test()....\n");
}

/* 《程式語言教學誌》的範例程式
    http://kaiching.org/
    檔名:simplefunction.c
    功能:示範函數的定義及呼叫
    作者:張凱慶 */

編譯後執行,結果如下

$ gcc simplefunction.c
$ a.out
呼叫函數test()....
呼叫函數test()....
程式成功執行結束
$

main() 函數的定義之前有

void test(void);

此即為函數原型的宣告。

至於底下 main() 中總計呼叫函數 test() 兩次。

請參考 C 速查手冊 - 函數有更詳細的敘述。

上一頁 5.6 使用 goto
回 C 速查手冊首頁
下一頁 6.1 指標
回 C 教材首頁
回程式語言教材首頁