亚洲最大看欧美片,亚洲图揄拍自拍另类图片,欧美精品v国产精品v呦,日本在线精品视频免费

  • 站長(zhǎng)資訊網(wǎng)
    最全最豐富的資訊網(wǎng)站

    《C語(yǔ)言完全教程》第九章 結(jié)構(gòu)與聯(lián)合

    第九章:結(jié)構(gòu)與聯(lián)合

    結(jié)構(gòu)類型定義和結(jié)構(gòu)變量說(shuō)明

      在實(shí)際問(wèn)題中,一組數(shù)據(jù)往往具有不同的數(shù)據(jù)類型。例如, 在學(xué)生登記表中,姓名應(yīng)為字符型;學(xué)號(hào)可為整型或字符型; 年齡應(yīng)為整型;性別應(yīng)為字符型;成績(jī)可為整型或?qū)嵭汀?顯然不能用一個(gè)數(shù)組來(lái)存放這一組數(shù)據(jù)。 因?yàn)閿?shù)組中各元素的類型和長(zhǎng)度都必須一致,以便于編譯系統(tǒng)處理。為了解決這個(gè)問(wèn)題,C語(yǔ)言中給出了另一種構(gòu)造數(shù)據(jù)類型——“結(jié)構(gòu)”。 它相當(dāng)于其它高級(jí)語(yǔ)言中的記錄。

      “結(jié)構(gòu)”是一種構(gòu)造類型,它是由若干“成員”組成的。 每一個(gè)成員可以是一個(gè)基本數(shù)據(jù)類型或者又是一個(gè)構(gòu)造類型。 結(jié)構(gòu)既是一種“構(gòu)造”而成的數(shù)據(jù)類型, 那么在說(shuō)明和使用之前必須先定義它,也就是構(gòu)造它。如同在說(shuō)明和調(diào)用函數(shù)之前要先定義函數(shù)一樣。

    一、結(jié)構(gòu)的定義

    定義一個(gè)結(jié)構(gòu)的一般形式為:
    struct 結(jié)構(gòu)名
    {
    成員表列
    };
    成員表由若干個(gè)成員組成, 每個(gè)成員都是該結(jié)構(gòu)的一個(gè)組成部分。對(duì)每個(gè)成員也必須作類型說(shuō)明,其形式為:
    類型說(shuō)明符 成員名;
    成員名的命名應(yīng)符合標(biāo)識(shí)符的書寫規(guī)定。例如:
    struct stu
    {
    int num;
    char name[20];
    char sex;
    float score;
    };
       在這個(gè)結(jié)構(gòu)定義中,結(jié)構(gòu)名為stu,該結(jié)構(gòu)由4個(gè)成員組成。 第一個(gè)成員為num,整型變量;第二個(gè)成員為name,字符數(shù)組;第三個(gè)成員為sex,字符變量;第四個(gè)成員為score,實(shí)型變量。 應(yīng)注意在括號(hào)后的分號(hào)是不可少的。結(jié)構(gòu)定義之后,即可進(jìn)行變量說(shuō)明。 凡說(shuō)明為結(jié)構(gòu)stu的變量都由上述4個(gè)成員組成。由此可見(jiàn), 結(jié)構(gòu)是一種復(fù)雜的數(shù)據(jù)類型,是數(shù)目固定,類型不同的若干有序變量的集合。

    二、結(jié)構(gòu)類型變量的說(shuō)明

    說(shuō)明結(jié)構(gòu)變量有以下三種方法。以上面定義的stu為例來(lái)加以說(shuō)明。
    1. 先定義結(jié)構(gòu),再說(shuō)明結(jié)構(gòu)變量。如:
    struct stu
    {
    int num;
    char name[20];
    char sex;
    float score;
    };
    struct stu boy1,boy2;
    說(shuō)明了兩個(gè)變量boy1和boy2為stu結(jié)構(gòu)類型。也可以用宏定義使一個(gè)符號(hào)常量來(lái)表示一個(gè)結(jié)構(gòu)類型,例如:
    #define STU struct stu
    STU
    {
    int num;
    char name[20];
    char sex;
    float score;
    };
    STU boy1,boy2;

    2. 在定義結(jié)構(gòu)類型的同時(shí)說(shuō)明結(jié)構(gòu)變量。例如:
    struct stu
    {
    int num;
    char name[20];
    char sex;
    float score;
    }boy1,boy2;

    3. 直接說(shuō)明結(jié)構(gòu)變量。例如:
    struct
    {
    int num;
    char name[20];
    char sex;
    float score;
    }boy1,boy2;

      第三種方法與第二種方法的區(qū)別在于第三種方法中省去了結(jié)構(gòu)名,而直接給出結(jié)構(gòu)變量。三種方法中說(shuō)明的boy1,boy2變量都具有圖7.1所示的結(jié)構(gòu)。說(shuō)明了boy1,boy2變量為stu類型后,即可向這兩個(gè)變量中的各個(gè)成員賦值。在上述stu結(jié)構(gòu)定義中,所有的成員都是基本數(shù)據(jù)類型或數(shù)組類型。成員也可以又是一個(gè)結(jié)構(gòu), 即構(gòu)成了嵌套的結(jié)構(gòu)。例如,圖7.2給出了另一個(gè)數(shù)據(jù)結(jié)構(gòu)。 按圖7.2可給出以下結(jié)構(gòu)定義:
    struct date{
    int month;
    int day;
    int year;
    }
    struct{
    int num;
    char name[20];
    char sex;
    struct date birthday;
    float score;
    }boy1,boy2;
       首先定義一個(gè)結(jié)構(gòu)date,由month(月)、day(日)、year(年) 三個(gè)成員組成。 在定義并說(shuō)明變量 boy1 和 boy2 時(shí), 其中的成員birthday被說(shuō)明為data結(jié)構(gòu)類型。成員名可與程序中其它變量同名,互不干擾。結(jié)構(gòu)變量成員的表示方法在程序中使用結(jié)構(gòu)變量時(shí), 往往不把它作為一個(gè)整體來(lái)使用。

      在ANSI C中除了允許具有相同類型的結(jié)構(gòu)變量相互賦值以外, 一般對(duì)結(jié)構(gòu)變量的使用,包括賦值、輸入、輸出、 運(yùn)算等都是通過(guò)結(jié)構(gòu)變量的成員來(lái)實(shí)現(xiàn)的。

      表示結(jié)構(gòu)變量成員的一般形式是: 結(jié)構(gòu)變量名.成員名 例如:boy1.num 即第一個(gè)人的學(xué)號(hào) boy2.sex 即第二個(gè)人的性別 如果成員本身又是一個(gè)結(jié)構(gòu)則必須逐級(jí)找到最低級(jí)的成員才能使用。例如:boy1.birthday.month 即第一個(gè)人出生的月份成員可以在程序中單獨(dú)使用,與普通變量完全相同。

    結(jié)構(gòu)變量的賦值

    前面已經(jīng)介紹,結(jié)構(gòu)變量的賦值就是給各成員賦值。 可用輸入語(yǔ)句或賦值語(yǔ)句來(lái)完成。
    [例7.1]給結(jié)構(gòu)變量賦值并輸出其值。
    main(){
    struct stu
    {
    int num;
    char *name;
    char sex;
    float score;
    } boy1,boy2;
    boy1.num=102;
    boy1.name=”Zhang ping”;
    printf(“input sex and scoren”);
    scanf(“%c %f”,&boy1.sex,&boy1.score);
    boy2=boy1;
    printf(“Number=%dnName=%sn”,boy2.num,boy2.name);
    printf(“Sex=%cnScore=%fn”,boy2.sex,boy2.score);
    }
    struct stu
    {
    int num;
    char *name;
    char sex;
    float score;
    }boy1,boy2;
    boy1.num=102;
    boy1.name=”Zhang ping”;
    printf(“input sex and scoren”);
    scanf(“%c %f”,&boy1.sex,&boy1.score);
    boy2=boy1;
    printf(“Number=%dnName=%sn”,boy2.num,boy2.name);
    printf(“Sex=%cnScore=%fn”,boy2.sex,boy2.score);

      本程序中用賦值語(yǔ)句給num和name兩個(gè)成員賦值,name是一個(gè)字符串指針變量。用scanf函數(shù)動(dòng)態(tài)地輸入sex和score成員值,然后把boy1的所有成員的值整體賦予boy2。最后分別輸出boy2 的各個(gè)成員值。本例表示了結(jié)構(gòu)變量的賦值、輸入和輸出的方法。

    結(jié)構(gòu)變量的初始化
       如果結(jié)構(gòu)變量是全局變量或?yàn)殪o態(tài)變量, 則可對(duì)它作初始化賦值。對(duì)局部或自動(dòng)結(jié)構(gòu)變量不能作初始化賦值。
    [例7.2]外部結(jié)構(gòu)變量初始化。
    struct stu /*定義結(jié)構(gòu)*/
    {
    int num;
    char *name;
    char sex;
    float score;
    } boy2,boy1={102,”Zhang ping”,’M’,78.5};
    main()
    {
    boy2=boy1;
    printf(“Number=%dnName=%sn”,boy2.num,boy2.name);
    printf(“Sex=%cnScore=%fn”,boy2.sex,boy2.score);
    }
    struct stu
    {
    int num;
    char *name;
    char sex;
    float score;
    }boy2,boy1={102,”Zhang ping”,’M’,78.5};
    main()
    {
    boy2=boy1;
    ……
    }
    本例中,boy2,boy1均被定義為外部結(jié)構(gòu)變量,并對(duì)boy1作了初始化賦值。在main函數(shù)中,把boy1的值整體賦予boy2, 然后用兩個(gè)printf語(yǔ)句輸出boy2各成員的值。
    [例7.3]靜態(tài)結(jié)構(gòu)變量初始化。
    main()
    {
    static struct stu /*定義靜態(tài)結(jié)構(gòu)變量*/
    {
    int num;
    char *name;
    char sex;
    float score;
    }boy2,boy1={102,”Zhang ping”,’M’,78.5};
    boy2=boy1;
    printf(“Number=%dnName=%sn”,boy2.num,boy2.name);
    printf(“Sex=%cnScore=%fn”,boy2.sex,boy2.score);
    }
    static struct stu
    {
    int num;
    char *name;
    char sex;
    float score;
    }boy2,boy1={102,”Zhang ping”,’M’,78.5};
       本例是把boy1,boy2都定義為靜態(tài)局部的結(jié)構(gòu)變量, 同樣可以作初始化賦值。

    結(jié)構(gòu)數(shù)組

    數(shù)組的元素也可以是結(jié)構(gòu)類型的。 因此可以構(gòu)成結(jié)構(gòu)型數(shù)組。結(jié)構(gòu)數(shù)組的每一個(gè)元素都是具有相同結(jié)構(gòu)類型的下標(biāo)結(jié)構(gòu)變量。 在實(shí)際應(yīng)用中,經(jīng)常用結(jié)構(gòu)數(shù)組來(lái)表示具有相同數(shù)據(jù)結(jié)構(gòu)的一個(gè)群體。如一個(gè)班的學(xué)生檔案,一個(gè)車間職工的工資表等。
    結(jié)構(gòu)數(shù)組的定義方法和結(jié)構(gòu)變量相似,只需說(shuō)明它為數(shù)組類型即可。例如:
    struct stu
    {
    int num;
    char *name;
    char sex;
    float score;
    }boy[5];
    定義了一個(gè)結(jié)構(gòu)數(shù)組boy1,共有5個(gè)元素,boy[0]~boy[4]。每個(gè)數(shù)組元素都具有struct stu的結(jié)構(gòu)形式。 對(duì)外部結(jié)構(gòu)數(shù)組或靜態(tài)結(jié)構(gòu)數(shù)組可以作初始化賦值,例如:
    struct stu
    {
    int num;
    char *name;
    char sex;
    float score;
    }boy[5]={
    {101,”Li ping”,”M”,45},
    {102,”Zhang ping”,”M”,62.5},
    {103,”He fang”,”F”,92.5},
    {104,”Cheng ling”,”F”,87},
    {105,”Wang ming”,”M”,58};
    }
    當(dāng)對(duì)全部元素作初始化賦值時(shí),也可不給出數(shù)組長(zhǎng)度。
    [例7.4]計(jì)算學(xué)生的平均成績(jī)和不及格的人數(shù)。
    struct stu
    {
    int num;
    char *name;
    char sex;
    float score;
    }boy[5]={
    {101,”Li ping”,’M’,45},
    {102,”Zhang ping”,’M’,62.5},
    {103,”He fang”,’F’,92.5},
    {104,”Cheng ling”,’F’,87},
    {105,”Wang ming”,’M’,58},
    };
    main()
    {
    int i,c=0;
    float ave,s=0;
    for(i=0;i<5;i++)
    {
    s+=boy[i].score;
    if(boy[i].score<60) c+=1;
    }
    printf(“s=%fn”,s);
    ave=s/5;
    printf(“average=%fncount=%dn”,ave,c);
    }
    本例程序中定義了一個(gè)外部結(jié)構(gòu)數(shù)組boy,共5個(gè)元素, 并作了初始化賦值。在main函數(shù)中用for語(yǔ)句逐個(gè)累加各元素的score 成員值存于s之中,如score的值小于60(不及格)即計(jì)數(shù)器C加1, 循環(huán)完畢后計(jì)算平均成績(jī),并輸出全班總分,平均分及不及格人數(shù)。

    [例7.5]建立同學(xué)通訊錄
    #include”stdio.h”
    #define NUM 3
    struct mem
    {
    char name[20];
    char phone[10];
    };
    main()
    {
    struct mem man[NUM];
    int i;
    for(i=0;i<NUM;i++)
    {
    printf(“input name:n”);
    gets(man[i].name);
    printf(“input phone:n”);
    gets(man[i].phone);
    }
    printf(“nametttphonenn”);
    for(i=0;i<NUM;i++)
    printf(“%sttt%sn”,man[i].name,man[i].phone);
    }
       本程序中定義了一個(gè)結(jié)構(gòu)mem,它有兩個(gè)成員name和phone 用來(lái)表示姓名和電話號(hào)碼。在主函數(shù)中定義man為具有mem 類型的結(jié)構(gòu)數(shù)組。在for語(yǔ)句中,用gets函數(shù)分別輸入各個(gè)元素中兩個(gè)成員的值。然后又在for語(yǔ)句中用printf語(yǔ)句輸出各元素中兩個(gè)成員值。

    結(jié)構(gòu)指針變量

    結(jié)構(gòu)指針變量的說(shuō)明和使用一個(gè)指針變量當(dāng)用來(lái)指向一個(gè)結(jié)構(gòu)變量時(shí), 稱之為結(jié)構(gòu)指針變量。
    結(jié)構(gòu)指針變量中的值是所指向的結(jié)構(gòu)變量的首地址。 通過(guò)結(jié)構(gòu)指針即可訪問(wèn)該結(jié)構(gòu)變量, 這與數(shù)組指針和函數(shù)指針的情況是相同的。結(jié)構(gòu)指針變量說(shuō)明的一般形式為:
    struct 結(jié)構(gòu)名*結(jié)構(gòu)指針變量名
    例如,在前面的例7.1中定義了stu這個(gè)結(jié)構(gòu), 如要說(shuō)明一個(gè)指向stu的指針變量pstu,可寫為:
    struct stu *pstu;

      當(dāng)然也可在定義stu結(jié)構(gòu)時(shí)同時(shí)說(shuō)明pstu。與前面討論的各類指針變量相同,結(jié)構(gòu)指針變量也必須要先賦值后才能使用。賦值是把結(jié)構(gòu)變量的首地址賦予該指針變量, 不能把結(jié)構(gòu)名賦予該指針變量。如果boy是被說(shuō)明為stu類型的結(jié)構(gòu)變量,則: pstu=&boy是正確的,而: pstu=&stu是錯(cuò)誤的。

      結(jié)構(gòu)名和結(jié)構(gòu)變量是兩個(gè)不同的概念,不能混淆。 結(jié)構(gòu)名只能表示一個(gè)結(jié)構(gòu)形式,編譯系統(tǒng)并不對(duì)它分配內(nèi)存空間。 只有當(dāng)某變量被說(shuō)明為這種類型的結(jié)構(gòu)時(shí),才對(duì)該變量分配存儲(chǔ)空間。 因此上面&stu這種寫法是錯(cuò)誤的,不可能去取一個(gè)結(jié)構(gòu)名的首地址。 有了結(jié)構(gòu)指針變量,就能更方便地訪問(wèn)結(jié)構(gòu)變量的各個(gè)成員。

    其訪問(wèn)的一般形式為: (*結(jié)構(gòu)指針變量).成員名 或?yàn)椋?br /> 結(jié)構(gòu)指針變量->成員名
    例如: (*pstu).num或者: pstu->num
    應(yīng)該注意(*pstu)兩側(cè)的括號(hào)不可少, 因?yàn)槌蓡T符“.”的優(yōu)先級(jí)高于“*”。如去掉括號(hào)寫作*pstu.num則等效于*(pstu.num),這樣,意義就完全不對(duì)了。 下面通過(guò)例子來(lái)說(shuō)明結(jié)構(gòu)指針變量的具體說(shuō)明和使用方法。
    [例7.6]
    struct stu
    {
    int num;
    char *name;
    char sex;
    float score;
    } boy1={102,”Zhang ping”,’M’,78.5},*pstu;
    main()
    {
    pstu=&boy1;
    printf(“Number=%dnName=%sn”,boy1.num,boy1.name);
    printf(“Sex=%cnScore=%fnn”,boy1.sex,boy1.score);
    printf(“Number=%dnName=%sn”,(*pstu).num,(*pstu).name);
    printf(“Sex=%cnScore=%fnn”,(*pstu).sex,(*pstu).score);
    printf(“Number=%dnName=%sn”,pstu->num,pstu->name);
    printf(“Sex=%cnScore=%fnn”,pstu->sex,pstu->score);
    }

      本例程序定義了一個(gè)結(jié)構(gòu)stu,定義了stu類型結(jié)構(gòu)變量boy1 并作了初始化賦值,還定義了一個(gè)指向stu類型結(jié)構(gòu)的指針變量pstu。在main函數(shù)中,pstu被賦予boy1的地址,因此pstu指向boy1 。然后在printf語(yǔ)句內(nèi)用三種形式輸出boy1的各個(gè)成員值。 從運(yùn)行結(jié)果可以看出:
    結(jié)構(gòu)變量.成員名
    (*結(jié)構(gòu)指針變量).成員名
    結(jié)構(gòu)指針變量->成員名

      這三種用于表示結(jié)構(gòu)成員的形式是完全等效的。結(jié)構(gòu)數(shù)組指針變量結(jié)構(gòu)指針變量可以指向一個(gè)結(jié)構(gòu)數(shù)組, 這時(shí)結(jié)構(gòu)指針變量的值是整個(gè)結(jié)構(gòu)數(shù)組的首地址。 結(jié)構(gòu)指針變量也可指向結(jié)構(gòu)數(shù)組的一個(gè)元素,這時(shí)結(jié)構(gòu)指針變量的值是該結(jié)構(gòu)數(shù)組元素的首地址。設(shè)ps為指向結(jié)構(gòu)數(shù)組的指針變量,則ps也指向該結(jié)構(gòu)數(shù)組的0號(hào)元素,ps+1指向1號(hào)元素,ps+i則指向i號(hào)元素。 這與普通數(shù)組的情況是一致的。
    [例7.7]用指針變量輸出結(jié)構(gòu)數(shù)組。
    struct stu
    {
    int num;
    char *name;
    char sex;
    float score;
    }boy[5]={
    {101,”Zhou ping”,’M’,45},
    {102,”Zhang ping”,’M’,62.5},
    {103,”Liou fang”,’F’,92.5},
    {104,”Cheng ling”,’F’,87},
    {105,”Wang ming”,’M’,58},
    };
    main()
    {
    struct stu *ps;
    printf(“NotNametttSextScoretn”);
    for(ps=boy;ps<boy+5;ps++)
    printf(“%dt%stt%ct%ftn”,ps->num,ps->name,ps->sex,ps->
    score);
    }
       在程序中,定義了stu結(jié)構(gòu)類型的外部數(shù)組boy 并作了初始化賦值。在main函數(shù)內(nèi)定義ps為指向stu類型的指針。在循環(huán)語(yǔ)句for的表達(dá)式1中,ps被賦予boy的首地址,然后循環(huán)5次,輸出boy數(shù)組中各成員值。 應(yīng)該注意的是, 一個(gè)結(jié)構(gòu)指針變量雖然可以用來(lái)訪問(wèn)結(jié)構(gòu)變量或結(jié)構(gòu)數(shù)組元素的成員,但是,不能使它指向一個(gè)成員。 也就是說(shuō)不允許取一個(gè)成員的地址來(lái)賦予它。因此,下面的賦值是錯(cuò)誤的。 ps=&boy[1].sex;而只能是:ps=boy;(賦予數(shù)組首地址)
    或者是:
    ps=&boy[0];(賦予0號(hào)元素首地址)

    結(jié)構(gòu)指針變量作函數(shù)參數(shù)

      在ANSI C標(biāo)準(zhǔn)中允許用結(jié)構(gòu)變量作函數(shù)參數(shù)進(jìn)行整體傳送。 但是這種傳送要將全部成員逐個(gè)傳送, 特別是成員為數(shù)組時(shí)將會(huì)使傳送的時(shí)間和空間開(kāi)銷很大,嚴(yán)重地降低了程序的效率。 因此最好的辦法就是使用指針,即用指針變量作函數(shù)參數(shù)進(jìn)行傳送。 這時(shí)由實(shí)參傳向形參的只是地址,從而減少了時(shí)間和空間的開(kāi)銷。
    [例7.8]題目與例7.4相同,計(jì)算一組學(xué)生的平均成績(jī)和不及格人數(shù)。
    用結(jié)構(gòu)指針變量作函數(shù)參數(shù)編程。
    struct stu
    {
    int num;
    char *name;
    char sex;
    float score;}boy[5]={
    {101,”Li ping”,’M’,45},
    {102,”Zhang ping”,’M’,62.5},
    {103,”He fang”,’F’,92.5},
    {104,”Cheng ling”,’F’,87},
    {105,”Wang ming”,’M’,58},
    };
    main()
    {
    struct stu *ps;
    void ave(struct stu *ps);
    ps=boy;
    ave(ps);
    }
    void ave(struct stu *ps)
    {
    int c=0,i;
    float ave,s=0;
    for(i=0;i<5;i++,ps++)
    {
    s+=ps->score;
    if(ps->score<60) c+=1;
    }
    printf(“s=%fn”,s);
    ave=s/5;
    printf(“average=%fncount=%dn”,ave,c);
    }
       本程序中定義了函數(shù)ave,其形參為結(jié)構(gòu)指針變量ps。boy 被定義為外部結(jié)構(gòu)數(shù)組,因此在整個(gè)源程序中有效。在main 函數(shù)中定義說(shuō)明了結(jié)構(gòu)指針變量ps,并把boy的首地址賦予它,使ps指向boy 數(shù)組。然后以ps作實(shí)參調(diào)用函數(shù)ave。在函數(shù)ave 中完成計(jì)算平均成績(jī)和統(tǒng)計(jì)不及格人數(shù)的工作并輸出結(jié)果。與例7.4程序相比,由于本程序全部采用指針變量作運(yùn)算和處理,故速度更快,程序效率更高。.

    topoic=動(dòng)態(tài)存儲(chǔ)分配

      在數(shù)組一章中,曾介紹過(guò)數(shù)組的長(zhǎng)度是預(yù)先定義好的, 在整個(gè)程序中固定不變。C語(yǔ)言中不允許動(dòng)態(tài)數(shù)組類型。例如: int n;scanf(“%d”,&n);int a[n]; 用變量表示長(zhǎng)度,想對(duì)數(shù)組的大小作動(dòng)態(tài)說(shuō)明, 這是錯(cuò)誤的。但是在實(shí)際的編程中,往往會(huì)發(fā)生這種情況, 即所需的內(nèi)存空間取決于實(shí)際輸入的數(shù)據(jù),而無(wú)法預(yù)先確定。對(duì)于這種問(wèn)題, 用數(shù)組的辦法很難解決。為了解決上述問(wèn)題,C語(yǔ)言提供了一些內(nèi)存管理函數(shù),這些內(nèi)存管理函數(shù)可以按需要?jiǎng)討B(tài)地分配內(nèi)存空間, 也可把不再使用的空間回收待用,為有效地利用內(nèi)存資源提供了手段。 常用的內(nèi)存管理函數(shù)有以下三個(gè):

    1.分配內(nèi)存空間函數(shù)malloc
    調(diào)用形式: (類型說(shuō)明符*) malloc (size) 功能:在內(nèi)存的動(dòng)態(tài)存儲(chǔ)區(qū)中分配一塊長(zhǎng)度為”size” 字節(jié)的連續(xù)區(qū)域。函數(shù)的返回值為該區(qū)域的首地址。 “類型說(shuō)明符”表示把該區(qū)域用于何種數(shù)據(jù)類型。(類型說(shuō)明符*)表示把返回值強(qiáng)制轉(zhuǎn)換為該類型指針?!皊ize”是一個(gè)無(wú)符號(hào)數(shù)。例如: pc=(char *) malloc (100); 表示分配100個(gè)字節(jié)的內(nèi)存空間,并強(qiáng)制轉(zhuǎn)換為字符數(shù)組類型, 函數(shù)的返回值為指向該字符數(shù)組的指針, 把該指針賦予指針變量pc。

    2.分配內(nèi)存空間函數(shù) calloc
    calloc 也用于分配內(nèi)存空間。調(diào)用形式: (類型說(shuō)明符*)calloc(n,size) 功能:在內(nèi)存動(dòng)態(tài)存儲(chǔ)區(qū)中分配n塊長(zhǎng)度為“size”字節(jié)的連續(xù)區(qū)域。函數(shù)的返回值為該區(qū)域的首地址。(類型說(shuō)明符*)用于強(qiáng)制類型轉(zhuǎn)換。calloc函數(shù)與malloc 函數(shù)的區(qū)別僅在于一次可以分配n塊區(qū)域。例如: ps=(struet stu*) calloc(2,sizeof (struct stu)); 其中的sizeof(struct stu)是求stu的結(jié)構(gòu)長(zhǎng)度。因此該語(yǔ)句的意思是:按stu的長(zhǎng)度分配2塊連續(xù)區(qū)域,強(qiáng)制轉(zhuǎn)換為stu類型,并把其首地址賦予指針變量ps。

    3.釋放內(nèi)存空間函數(shù)free
    調(diào)用形式: free(void*ptr); 功能:釋放ptr所指向的一塊內(nèi)存空間,ptr 是一個(gè)任意類型的指針變量,它指向被釋放區(qū)域的首地址。被釋放區(qū)應(yīng)是由malloc或calloc函數(shù)所分配的區(qū)域:[例7.9]分配一塊區(qū)域,輸入一個(gè)學(xué)生數(shù)據(jù)。
    main()
    {
    struct stu
    {
    int num;
    char *name;
    char sex;
    float score;
    } *ps;
    ps=(struct stu*)malloc(sizeof(struct stu));
    ps->num=102;
    ps->name=”Zhang ping”;
    ps->sex=’M’;
    ps->score=62.5;
    printf(“Number=%dnName=%sn”,ps->num,ps->name);
    printf(“Sex=%cnScore=%fn”,ps->sex,ps->score);
    free(ps);
    }
       本例中,定義了結(jié)構(gòu)stu,定義了stu類型指針變量ps。 然后分配一塊stu大內(nèi)存區(qū),并把首地址賦予ps,使ps指向該區(qū)域。再以ps為指向結(jié)構(gòu)的指針變量對(duì)各成員賦值,并用printf 輸出各成員值。最后用free函數(shù)釋放ps指向的內(nèi)存空間。 整個(gè)程序包含了申請(qǐng)內(nèi)存空間、使用內(nèi)存空間、釋放內(nèi)存空間三個(gè)步驟, 實(shí)現(xiàn)存儲(chǔ)空間的動(dòng)態(tài)分配。鏈表的概念在例7.9中采用了動(dòng)態(tài)分配的辦法為一個(gè)結(jié)構(gòu)分配內(nèi)存空間。每一次分配一塊空間可用來(lái)存放一個(gè)學(xué)生的數(shù)據(jù), 我們可稱之為一個(gè)結(jié)點(diǎn)。有多少個(gè)學(xué)生就應(yīng)該申請(qǐng)分配多少塊內(nèi)存空間, 也就是說(shuō)要建立多少個(gè)結(jié)點(diǎn)。當(dāng)然用結(jié)構(gòu)數(shù)組也可以完成上述工作, 但如果預(yù)先不能準(zhǔn)確把握學(xué)生人數(shù),也就無(wú)法確定數(shù)組大小。 而且當(dāng)學(xué)生留級(jí)、退學(xué)之后也不能把該元素占用的空間從數(shù)組中釋放出來(lái)。 用動(dòng)態(tài)存儲(chǔ)的方法可以很好地解決這些問(wèn)題。 有一個(gè)學(xué)生就分配一個(gè)結(jié)點(diǎn),無(wú)須預(yù)先確定學(xué)生的準(zhǔn)確人數(shù),某學(xué)生退學(xué), 可刪去該結(jié)點(diǎn),并釋放該結(jié)點(diǎn)占用的存儲(chǔ)空間。從而節(jié)約了寶貴的內(nèi)存資源。 另一方面,用數(shù)組的方法必須占用一塊連續(xù)的內(nèi)存區(qū)域。 而使用動(dòng)態(tài)分配時(shí),每個(gè)結(jié)點(diǎn)之間可以是不連續(xù)的(結(jié)點(diǎn)內(nèi)是連續(xù)的)。 結(jié)點(diǎn)之間的聯(lián)系可以用指針實(shí)現(xiàn)。 即在結(jié)點(diǎn)結(jié)構(gòu)中定義一個(gè)成員項(xiàng)用來(lái)存放下一結(jié)點(diǎn)的首地址,這個(gè)用于存放地址的成員,常把它稱為指針域??稍诘谝粋€(gè)結(jié)點(diǎn)的指針域內(nèi)存入第二個(gè)結(jié)點(diǎn)的首地址, 在第二個(gè)結(jié)點(diǎn)的指針域內(nèi)又存放第三個(gè)結(jié)點(diǎn)的首地址, 如此串連下去直到最后一個(gè)結(jié)點(diǎn)。最后一個(gè)結(jié)點(diǎn)因無(wú)后續(xù)結(jié)點(diǎn)連接,其指針域可賦為0。這樣一種連接方式,在數(shù)據(jù)結(jié)構(gòu)中稱為“鏈表”。圖7.3為鏈表的示意圖。

      在圖7.3中,第0個(gè)結(jié)點(diǎn)稱為頭結(jié)點(diǎn), 它存放有第一個(gè)結(jié)點(diǎn)的首地址,它沒(méi)有數(shù)據(jù),只是一個(gè)指針變量。 以下的每個(gè)結(jié)點(diǎn)都分為兩個(gè)域,一個(gè)是數(shù)據(jù)域,存放各種實(shí)際的數(shù)據(jù),如學(xué)號(hào)num,姓名name,性別sex和成績(jī)score等。另一個(gè)域?yàn)橹羔樣颍?存放下一結(jié)點(diǎn)的首地址。鏈表中的每一個(gè)結(jié)點(diǎn)都是同一種結(jié)構(gòu)類型。例如, 一個(gè)存放學(xué)生學(xué)號(hào)和成績(jī)的結(jié)點(diǎn)應(yīng)為以下結(jié)構(gòu):
    struct stu
    { int num;
    int score;
    struct stu *next;
    }
       前兩個(gè)成員項(xiàng)組成數(shù)據(jù)域,后一個(gè)成員項(xiàng)next構(gòu)成指針域, 它是一個(gè)指向stu類型結(jié)構(gòu)的指針變量。鏈表的基本操作對(duì)鏈表的主要操作有以下幾種:
    1.建立鏈表;
    2.結(jié)構(gòu)的查找與輸出;
    3.插入一個(gè)結(jié)點(diǎn);
    4.刪除一個(gè)結(jié)點(diǎn);
    下面通過(guò)例題來(lái)說(shuō)明這些操作。
    [例7.10]建立一個(gè)三個(gè)結(jié)點(diǎn)的鏈表,存放學(xué)生數(shù)據(jù)。 為簡(jiǎn)單起見(jiàn), 我們假定學(xué)生數(shù)據(jù)結(jié)構(gòu)中只有學(xué)號(hào)和年齡兩項(xiàng)。
    可編寫一個(gè)建立鏈表的函數(shù)creat。程序如下:
    #define NULL 0
    #define TYPE struct stu
    #define LEN sizeof (struct stu)
    struct stu
    {
    int num;
    int age;
    struct stu *next;
    };
    TYPE *creat(int n)
    {
    struct stu *head,*pf,*pb;
    int i;
    for(i=0;i<n;i++)
    {
    pb=(TYPE*) malloc(LEN);
    printf(“input Number and Agen”);
    scanf(“%d%d”,&pb->num,&pb->age);
    if(i==0)
    pf=head=pb;
    else pf->next=pb;
    pb->next=NULL;
    pf=pb;
    }
    return(head);
    }
       在函數(shù)外首先用宏定義對(duì)三個(gè)符號(hào)常量作了定義。這里用TYPE表示struct stu,用LEN表示sizeof(struct stu)主要的目的是為了在以下程序內(nèi)減少書寫并使閱讀更加方便。結(jié)構(gòu)stu定義為外部類型,程序中的各個(gè)函數(shù)均可使用該定義。

      creat函數(shù)用于建立一個(gè)有n個(gè)結(jié)點(diǎn)的鏈表,它是一個(gè)指針函數(shù),它返回的指針指向stu結(jié)構(gòu)。在creat函數(shù)內(nèi)定義了三個(gè)stu結(jié)構(gòu)的指針變量。head為頭指針,pf 為指向兩相鄰結(jié)點(diǎn)的前一結(jié)點(diǎn)的指針變量。pb為后一結(jié)點(diǎn)的指針變量。在for語(yǔ)句內(nèi),用malloc函數(shù)建立長(zhǎng)度與stu長(zhǎng)度相等的空間作為一結(jié)點(diǎn),首地址賦予pb。然后輸入結(jié)點(diǎn)數(shù)據(jù)。如果當(dāng)前結(jié)點(diǎn)為第一結(jié)點(diǎn)(i==0),則把pb值 (該結(jié)點(diǎn)指針)賦予head和pf。如非第一結(jié)點(diǎn),則把pb值賦予pf 所指結(jié)點(diǎn)的指針域成員next。而pb所指結(jié)點(diǎn)為當(dāng)前的最后結(jié)點(diǎn),其指針域賦NULL。 再把pb值賦予pf以作下一次循環(huán)準(zhǔn)備。
       creat函數(shù)的形參n,表示所建鏈表的結(jié)點(diǎn)數(shù),作為for語(yǔ)句的循環(huán)次數(shù)。圖7.4表示了creat函數(shù)的執(zhí)行過(guò)程。

    [例7.11]寫一個(gè)函數(shù),在鏈表中按學(xué)號(hào)查找該結(jié)點(diǎn)。
    TYPE * search (TYPE *head,int n)
    {
    TYPE *p;
    int i;
    p=head;
    while (p->num!=n && p->next!=NULL)
    p=p->next; /* 不是要找的結(jié)點(diǎn)后移一步*/
    if (p->num==n) return (p);
    if (p->num!=n&& p->next==NULL)
    printf (“Node %d has not been found!n”,n
    }
       本函數(shù)中使用的符號(hào)常量TYPE與例7.10的宏定義相同,等于struct stu。函數(shù)有兩個(gè)形參,head是指向鏈表的指針變量,n為要查找的學(xué)號(hào)。進(jìn)入while語(yǔ)句,逐個(gè)檢查結(jié)點(diǎn)的num成員是否等于n,如果不等于n且指針域不等于NULL(不是最后結(jié)點(diǎn))則后移一個(gè)結(jié)點(diǎn),繼續(xù)循環(huán)。如找到該結(jié)點(diǎn)則返回結(jié)點(diǎn)指針。 如循環(huán)結(jié)束仍未找到該結(jié)點(diǎn)則輸出“未找到”的提示信息。

    [例7.12]寫一個(gè)函數(shù),刪除鏈表中的指定結(jié)點(diǎn)。刪除一個(gè)結(jié)點(diǎn)有兩種情況:
    1. 被刪除結(jié)點(diǎn)是第一個(gè)結(jié)點(diǎn)。這種情況只需使head指向第二個(gè)結(jié)點(diǎn)即可。即head=pb->next。其過(guò)程如圖7.5所示。
    2. 被刪結(jié)點(diǎn)不是第一個(gè)結(jié)點(diǎn),這種情況使被刪結(jié)點(diǎn)的前一結(jié)點(diǎn)指向被刪結(jié)點(diǎn)的后一結(jié)點(diǎn)即可。即pf->next=pb->next。其過(guò)程如圖7.6所示。
    函數(shù)編程如下:
    TYPE * delete(TYPE * head,int num)
    {
    TYPE *pf,*pb;
    if(head==NULL) /*如為空表, 輸出提示信息*/
    { printf(“nempty list!n”);
    goto end;}
    pb=head;
    while (pb->num!=num && pb->next!=NULL)
    /*當(dāng)不是要?jiǎng)h除的結(jié)點(diǎn),而且也不是最后一個(gè)結(jié)點(diǎn)時(shí),繼續(xù)循環(huán)*/
    {pf=pb;pb=pb->next;}/*pf指向當(dāng)前結(jié)點(diǎn),pb指向下一結(jié)點(diǎn)*/
    if(pb->num==num)
    {if(pb==head) head=pb->next;
    /*如找到被刪結(jié)點(diǎn),且為第一結(jié)點(diǎn),則使head指向第二個(gè)結(jié)點(diǎn),
    否則使pf所指結(jié)點(diǎn)的指針指向下一結(jié)點(diǎn)*/
    else pf->next=pb->next;
    free(pb);
    printf(“The node is deletedn”);}
    else
    printf(“The node not been foud!n”);
    end:
    return head;
    }
       函數(shù)有兩個(gè)形參,head為指向鏈表第一結(jié)點(diǎn)的指針變量,num刪結(jié)點(diǎn)的學(xué)號(hào)。 首先判斷鏈表是否為空,為空則不可能有被刪結(jié)點(diǎn)。若不為空,則使pb指針指向鏈表的第一個(gè)結(jié)點(diǎn)。進(jìn)入while語(yǔ)句后逐個(gè)查找被刪結(jié)點(diǎn)。找到被刪結(jié)點(diǎn)之后再看是否為第一結(jié)點(diǎn),若是則使head指向第二結(jié)點(diǎn)(即把第一結(jié)點(diǎn)從鏈中刪去),否則使被刪結(jié)點(diǎn)的前一結(jié)點(diǎn)(pf所指)指向被刪結(jié)點(diǎn)的后一結(jié)點(diǎn)(被刪結(jié)點(diǎn)的指針域所指)。如若循環(huán)結(jié)束未找到要?jiǎng)h的結(jié)點(diǎn), 則輸出“末找到”的提示信息。最后返回head值。

    [例7.13]寫一個(gè)函數(shù),在鏈表中指定位置插入一個(gè)結(jié)點(diǎn)。在一個(gè)鏈表的指定位置插入結(jié)點(diǎn), 要求鏈表本身必須是已按某種規(guī)律排好序的。例如,在學(xué)生數(shù)據(jù)鏈表中, 要求學(xué)號(hào)順序插入一個(gè)結(jié)點(diǎn)。設(shè)被插結(jié)點(diǎn)的指針為pi。 可在三種不同情況下插入。
    1. 原表是空表,只需使head指向被插結(jié)點(diǎn)即可。見(jiàn)圖7.7(a)
    2. 被插結(jié)點(diǎn)值最小,應(yīng)插入第一結(jié)點(diǎn)之前。這種情況下使head指向被插結(jié)點(diǎn),被插結(jié)點(diǎn)的指針域指向原來(lái)的第一結(jié)點(diǎn)則可。即:pi->next=pb;
    head=pi; 見(jiàn)圖7.7(b)
    3. 在其它位置插入,見(jiàn)圖7.7(c)。這種情況下,使插入位置的前一結(jié)點(diǎn)的指針域指向被插結(jié)點(diǎn),使被插結(jié)點(diǎn)的指針域指向插入位置的后一結(jié)點(diǎn)。即為:pi->next=pb;pf->next=pi;
    4. 在表末插入,見(jiàn)圖7.7(d)。這種情況下使原表末結(jié)點(diǎn)指針域指向被插結(jié)點(diǎn),被插結(jié)點(diǎn)指針域置為NULL。即:
    pb->next=pi;
    pi->next=NULL; TYPE * insert(TYPE * head,TYPE *pi)
    {
    TYPE *pf,*pb;
    pb=head;
    if(head==NULL) /*空表插入*/
    (head=pi;
    pi->next=NULL;}
    else
    {
    while((pi->num>pb->num)&&(pb->next!=NULL))
    {pf=pb;
    pb=pb->next; }/*找插入位置*/
    if(pi->num<=pb->num)
    {if(head==pb)head=pi;/*在第一結(jié)點(diǎn)之前插入*/
    else pf->next=pi;/*在其它位置插入*/
    pi->next=pb; }
    else
    {pb->next=pi;
    pi->next=NULL;} /*在表末插入*/
    }
    return head;}
       本函數(shù)有兩個(gè)形參均為指針變量,head指向鏈表,pi 指向被插結(jié)點(diǎn)。函數(shù)中首先判斷鏈表是否為空,為空則使head指向被插結(jié)點(diǎn)。表若不空,則用while語(yǔ)句循環(huán)查找插入位置。找到之后再判斷是否在第一結(jié)點(diǎn)之前插入,若是則使head 指向被插結(jié)點(diǎn)被插結(jié)點(diǎn)指針域指向原第一結(jié)點(diǎn),否則在其它位置插入, 若插入的結(jié)點(diǎn)大于表中所有結(jié)點(diǎn),則在表末插入。本函數(shù)返回一個(gè)指針, 是鏈表的頭指針。 當(dāng)插入的位置在第一個(gè)結(jié)點(diǎn)之前時(shí), 插入的新結(jié)點(diǎn)成為鏈表的第一個(gè)結(jié)點(diǎn),因此head的值也有了改變, 故需要把這個(gè)指針?lè)祷刂髡{(diào)函數(shù)。
    [例7.14]將以上建立鏈表,刪除結(jié)點(diǎn),插入結(jié)點(diǎn)的函數(shù)組織在一起,再建一個(gè)輸出全部結(jié)點(diǎn)的函數(shù),然后用main函數(shù)調(diào)用它們。
    #define NULL 0
    #define TYPE struct stu
    #define LEN sizeof(struct stu)
    struct stu
    {
    int num;
    int age;
    struct stu *next;
    };
    TYPE * creat(int n)
    {
    struct stu *head,*pf,*pb;
    int i;
    for(i=0;i<n;i++)
    {
    pb=(TYPE *)malloc(LEN);
    printf(“input Number and Agen”);
    scanf(“%d%d”,&pb->num,&pb->age);
    if(i==0)
    pf=head=pb;
    else pf->next=pb;
    pb->next=NULL;
    pf=pb;
    }
    return(head);
    }
    TYPE * delete(TYPE * head,int num)
    {
    TYPE *pf,*pb;
    if(head==NULL)
    { printf(“nempty list!n”);
    goto end;}
    pb=head;
    while (pb->num!=num && pb->next!=NULL)
    {pf=pb;pb=pb->next;}
    if(pb->num==num)
    { if(pb==head) head=pb->next;
    else pf->next=pb->next;
    printf(“The node is deletedn”); }
    else
    free(pb);
    printf(“The node not been found!n”);
    end:
    return head;
    }
    TYPE * insert(TYPE * head,TYPE * pi)
    {
    TYPE *pb ,*pf;
    pb=head;
    if(head==NULL)
    { head=pi;
    pi->next=NULL; }
    else
    {
    while((pi->num>pb->num)&&(pb->next!=NULL))
    { pf=pb;
    pb=pb->next; }
    if(pi->num<=pb->num)
    { if(head==pb) head=pi;
    else pf->next=pi;
    pi->next=pb; }
    else
    { pb->next=pi;
    pi->next=NULL; }
    }
    return head;
    }
    void print(TYPE * head)
    {
    printf(“NumberttAgen”);
    while(head!=NULL)
    {
    printf(“%dtt%dn”,head->num,head->age);
    head=head->next;
    }
    }
    main()
    {
    TYPE * head,*pnum;
    int n,num;
    printf(“input number of node: “);
    scanf(“%d”,&n);
    head=creat(n);
    print(head);
    printf(“Input the deleted number: “);
    scanf(“%d”,&num);
    head=delete(head,num);
    print(head);
    printf(“Input the inserted number and age: “);
    pnum=(TYPE *)malloc(LEN);
    scanf(“%d%d”,&pnum->num,&pnum->age);
    head=insert(head,pnum);
    print(head);
    }
       本例中,print函數(shù)用于輸出鏈表中各個(gè)結(jié)點(diǎn)數(shù)據(jù)域值。函數(shù)的形參head的初值指向鏈表第一個(gè)結(jié)點(diǎn)。在while語(yǔ)句中,輸出結(jié)點(diǎn)值后,head值被改變,指向下一結(jié)點(diǎn)。若保留頭指針head, 則應(yīng)另設(shè)一個(gè)指針變量,把head值賦予它,再用它來(lái)替代head。在main函數(shù)中,n為建立結(jié)點(diǎn)的數(shù)目, num為待刪結(jié)點(diǎn)的數(shù)據(jù)域值;head為指向鏈表的頭指針,pnum為指向待插結(jié)點(diǎn)的指針。 main函數(shù)中各行的意義是:
    第六行輸入所建鏈表的結(jié)點(diǎn)數(shù);
    第七行調(diào)creat函數(shù)建立鏈表并把頭指針?lè)祷亟ohead;
    第八行調(diào)print函數(shù)輸出鏈表;
    第十行輸入待刪結(jié)點(diǎn)的學(xué)號(hào);
    第十一行調(diào)delete函數(shù)刪除一個(gè)結(jié)點(diǎn);
    第十二行調(diào)print函數(shù)輸出鏈表;
    第十四行調(diào)malloc函數(shù)分配一個(gè)結(jié)點(diǎn)的內(nèi)存空間, 并把其地址賦予pnum;
    第十五行輸入待插入結(jié)點(diǎn)的數(shù)據(jù)域值;
    第十六行調(diào)insert函數(shù)插入pnum所指的結(jié)點(diǎn);
    第十七行再次調(diào)print函數(shù)輸出鏈表。

      從運(yùn)行結(jié)果看,首先建立起3個(gè)結(jié)點(diǎn)的鏈表,并輸出其值;再刪103號(hào)結(jié)點(diǎn),只剩下105,108號(hào)結(jié)點(diǎn);又輸入106號(hào)結(jié)點(diǎn)數(shù)據(jù), 插入后鏈表中的結(jié)點(diǎn)為105,106,108。聯(lián)合“聯(lián)合”也是一種構(gòu)造類型的數(shù)據(jù)結(jié)構(gòu)。 在一個(gè)“聯(lián)合”內(nèi)可以定義多種不同的數(shù)據(jù)類型, 一個(gè)被說(shuō)明為該“聯(lián)合”類型的變量中,允許裝入該“聯(lián)合”所定義的任何一種數(shù)據(jù)。 這在前面的各種數(shù)據(jù)類型中都是辦不到的。例如, 定義為整型的變量只能裝入整型數(shù)據(jù),定義為實(shí)型的變量只能賦予實(shí)型數(shù)據(jù)。

      在實(shí)際問(wèn)題中有很多這樣的例子。 例如在學(xué)校的教師和學(xué)生中填寫以下表格: 姓 名 年 齡 職 業(yè) 單位 “職業(yè)”一項(xiàng)可分為“教師”和“學(xué)生”兩類。 對(duì)“單位”一項(xiàng)學(xué)生應(yīng)填入班級(jí)編號(hào),教師應(yīng)填入某系某教研室。 班級(jí)可用整型量表示,教研室只能用字符類型。 要求把這兩種類型不同的數(shù)據(jù)都填入“單位”這個(gè)變量中, 就必須把“單位”定義為包含整型和字符型數(shù)組這兩種類型的“聯(lián)合”。

      “聯(lián)合”與“結(jié)構(gòu)”有一些相似之處。但兩者有本質(zhì)上的不同。在結(jié)構(gòu)中各成員有各自的內(nèi)存空間, 一個(gè)結(jié)構(gòu)變量的總長(zhǎng)度是各成員長(zhǎng)度之和。而在“聯(lián)合”中,各成員共享一段內(nèi)存空間, 一個(gè)聯(lián)合變量的長(zhǎng)度等于各成員中最長(zhǎng)的長(zhǎng)度。應(yīng)該說(shuō)明的是, 這里所謂的共享不是指把多個(gè)成員同時(shí)裝入一個(gè)聯(lián)合變量?jī)?nèi), 而是指該聯(lián)合變量可被賦予任一成員值,但每次只能賦一種值, 賦入新值則沖去舊值。如前面介紹的“單位”變量, 如定義為一個(gè)可裝入“班級(jí)”或“教研室”的聯(lián)合后,就允許賦予整型值(班級(jí))或字符串(教研室)。要么賦予整型值,要么賦予字符串,不能把兩者同時(shí)賦予它。聯(lián)合類型的定義和聯(lián)合變量的說(shuō)明一個(gè)聯(lián)合類型必須經(jīng)過(guò)定義之后, 才能把變量說(shuō)明為該聯(lián)合類型。

    一、聯(lián)合的定義

    定義一個(gè)聯(lián)合類型的一般形式為:
    union 聯(lián)合名
    {
    成員表
    };
    成員表中含有若干成員,成員的一般形式為: 類型說(shuō)明符 成員名 成員名的命名應(yīng)符合標(biāo)識(shí)符的規(guī)定。
    例如:
    union perdata
    {
    int class;
    char office[10];
    };
       定義了一個(gè)名為perdata的聯(lián)合類型,它含有兩個(gè)成員,一個(gè)為整型,成員名為class;另一個(gè)為字符數(shù)組,數(shù)組名為office。聯(lián)合定義之后,即可進(jìn)行聯(lián)合變量說(shuō)明,被說(shuō)明為perdata類型的變量,可以存放整型量class或存放字符數(shù)組office。

    二、聯(lián)合變量的說(shuō)明

      聯(lián)合變量的說(shuō)明和結(jié)構(gòu)變量的說(shuō)明方式相同, 也有三種形式。即先定義,再說(shuō)明;定義同時(shí)說(shuō)明和直接說(shuō)明。以perdata類型為例,說(shuō)明如下:
    union perdata
    {
    int class;
    char officae[10];
    };
    union perdata a,b; /*說(shuō)明a,b為perdata類型*/
    或者可同時(shí)說(shuō)明為:
    union perdata
    { int class;
    char office[10]; }a,b;或直接說(shuō)明為: union
    { int class;
    char office[10]; }a,b
    經(jīng)說(shuō)明后的a,b變量均為perdata類型。 它們的內(nèi)存分配示意圖如圖7—8所示。a,b變量的長(zhǎng)度應(yīng)等于 perdata 的成員中最長(zhǎng)的長(zhǎng)度, 即等于
    office數(shù)組的長(zhǎng)度,共10個(gè)字節(jié)。從圖中可見(jiàn),a,b變量如賦予整型值時(shí),只使用了2個(gè)字節(jié),而賦予字符數(shù)組時(shí),可用10個(gè)字節(jié)。

    聯(lián)合變量的賦值和使用

      對(duì)聯(lián)合變量的賦值,使用都只能是對(duì)變量的成員進(jìn)行。 聯(lián)合變量的成員表示為: 聯(lián)合變量名.成員名 例如,a被說(shuō)明為perdata類型的變量之后,可使用 a.class a.office 不允許只用聯(lián)合變量名作賦值或其它操作。 也不允許對(duì)聯(lián)合變量作初始化賦值,賦值只能在程序中進(jìn)行。還要再?gòu)?qiáng)調(diào)說(shuō)明的是,一個(gè)聯(lián)合變量, 每次只能賦予一個(gè)成員值。換句話說(shuō),一個(gè)聯(lián)合變量的值就是聯(lián)合變員的某一個(gè)成員值。
    [例7.15]設(shè)有一個(gè)教師與學(xué)生通用的表格,教師數(shù)據(jù)有姓名,年齡,職業(yè),教研室四項(xiàng)。學(xué)生有姓名,年齡,職業(yè),班級(jí)四項(xiàng)。
    編程輸入人員數(shù)據(jù), 再以表格輸出。
    main()
    {
    struct
    {
    char name[10];
    int age;
    char job;
    union
    {
    int class;
    char office[10];
    } depa;
    }body[2];
    int n,i;
    for(i=0;i<2;i++)
    {
    printf(“input name,age,job and departmentn”);
    scanf(“%s %d %c”,body[i].name,&body[i].age,&body[i].job);
    if(body[i].job==’s’)
    scanf(“%d”,&body[i].depa.class);
    else
    scanf(“%s”,body[i].depa.office);
    }
    printf(“nametage job class/officen”);
    for(i=0;i<2;i++)
    {
    if(body[i].job==’s’)
    printf(“%st%3d %3c %dn”,body[i].name,body[i].age
    ,body[i].job,body[i].depa.class);
    else
    printf(“%st%3d %3c %sn”,body[i].name,body[i].age,
    body[i].job,body[i].depa.office);
    }
    }
       本例程序用一個(gè)結(jié)構(gòu)數(shù)組body來(lái)存放人員數(shù)據(jù), 該結(jié)構(gòu)共有四個(gè)成員。其中成員項(xiàng)depa是一個(gè)聯(lián)合類型, 這個(gè)聯(lián)合又由兩個(gè)成員組成,一個(gè)為整型量class,一個(gè)為字符數(shù)組office。在程序的第一個(gè)for語(yǔ)句中,輸入人員的各項(xiàng)數(shù)據(jù),先輸入結(jié)構(gòu)的前三個(gè)成員name,age和job,然后判別job成員項(xiàng),如為”s”則對(duì)聯(lián)合depa·class輸入(對(duì)學(xué)生賦班級(jí)編號(hào))否則對(duì)depa·office輸入(對(duì)教師賦教研組名)。

      在用scanf語(yǔ)句輸入時(shí)要注意,凡為數(shù)組類型的成員,無(wú)論是結(jié)構(gòu)成員還是聯(lián)合成員,在該項(xiàng)前不能再加”&”運(yùn)算符。如程序第18行中
    body[i].name是一個(gè)數(shù)組類型,第22行中的body[i].depa.office也是數(shù)組類型,因此在這兩項(xiàng)之間不能加”&”運(yùn)算符。程序中的第二個(gè)for語(yǔ)句用于輸出各成員項(xiàng)的值:

    本章小結(jié)

    1. 結(jié)構(gòu)和聯(lián)合是兩種構(gòu)造類型數(shù)據(jù),是用戶定義新數(shù)據(jù)類型的重要手段。結(jié)構(gòu)和聯(lián)合有很多的相似之處,它們都由成員組成。成員可以具有不同的數(shù)據(jù)類型。成員的表示方法相同。都可用三種方式作變量說(shuō)明。 2. 在結(jié)構(gòu)中,各成員都占有自己的內(nèi)存空間,它們是同時(shí)存在的。一個(gè)結(jié)構(gòu)變量的總長(zhǎng)度等于所有成員長(zhǎng)度之和。在聯(lián)合中,所有成員不能同時(shí)占用它的內(nèi)存空間,它們不能同時(shí)存在。聯(lián)合變量的長(zhǎng)度等于最長(zhǎng)的成員的長(zhǎng)度。

    3. “.”是成員運(yùn)算符,可用它表示成員項(xiàng),成員還可用“->”運(yùn)算符來(lái)表示。

    4. 結(jié)構(gòu)變量可以作為函數(shù)參數(shù),函數(shù)也可返回指向結(jié)構(gòu)的指針變量。而聯(lián)合變量不能作為函數(shù)參數(shù),函數(shù)也不能返回指向聯(lián)合的指針變量。但可以使用指向聯(lián)合變量的指針,也可使用聯(lián)合數(shù)組。 5. 結(jié)構(gòu)定義允許嵌套,結(jié)構(gòu)中也可用聯(lián)合作為成員,形成結(jié)構(gòu)和聯(lián)合的嵌套。

    6. 鏈表是一種重要的數(shù)據(jù)結(jié)構(gòu),它便于實(shí)現(xiàn)動(dòng)態(tài)的存儲(chǔ)分配。本章介紹是單向鏈表,還可組成雙向鏈表,循環(huán)鏈表等。

     

    贊(0)
    分享到: 更多 (0)
    網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)