18143-00譚浩強(qiáng)-c程序設(shè)計(jì)教程c演示文稿08_第1頁
18143-00譚浩強(qiáng)-c程序設(shè)計(jì)教程c演示文稿08_第2頁
18143-00譚浩強(qiáng)-c程序設(shè)計(jì)教程c演示文稿08_第3頁
18143-00譚浩強(qiáng)-c程序設(shè)計(jì)教程c演示文稿08_第4頁
18143-00譚浩強(qiáng)-c程序設(shè)計(jì)教程c演示文稿08_第5頁
已閱讀5頁,還剩27頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、第8章結(jié)構(gòu)體、共用體和枚舉類型本章要點(diǎn): 掌握數(shù)據(jù)類型中構(gòu)造數(shù)據(jù)類型(簡稱構(gòu)造類型) 的特點(diǎn)和應(yīng)用。 掌握結(jié)構(gòu)體變量和結(jié)構(gòu)體數(shù)組的定義、初始化和輸入/輸出。 掌握結(jié)構(gòu)體指針作為函數(shù)參數(shù)的用法。 掌握單鏈表的建立和輸出,單鏈表結(jié)點(diǎn)的修改、插入和刪除。 理解共用體和枚舉類型的概念。338.1 概述本章討論構(gòu)造數(shù)據(jù)類型,它的定義是用戶參與的, 不同的用戶可以定義出形式多樣的數(shù)據(jù)類型。它們的特點(diǎn)是由不同數(shù)據(jù)類型組成,并且一旦定義以后,就可在程序需要的地方定義該類型的變量或數(shù)組。如一個學(xué)生的情況記錄單可以包括學(xué)號、姓名、性別、年齡、成績、家庭地址等數(shù)據(jù)項(xiàng),這些數(shù)據(jù)項(xiàng)都是跟某一個學(xué)生相聯(lián)系的,可以構(gòu)造成一

2、個稱為“學(xué)生”的結(jié)構(gòu)體類型。這些數(shù)據(jù)項(xiàng)中,學(xué)號、年齡可以是整型數(shù)據(jù);姓名、性別、家庭地址可以是字符型數(shù)據(jù);分?jǐn)?shù)可以是實(shí)型數(shù)據(jù)或整型數(shù)據(jù)。像這樣把不同類型的數(shù)據(jù)集合成一個整體并構(gòu)造成一個新的數(shù)據(jù)類型,在C語言中稱它為結(jié)構(gòu)體(structure)。8.2 結(jié)構(gòu)體類型的定義不同用戶根據(jù)不同要求可以定義出形式多樣的結(jié)構(gòu)體類型,但大家都必須遵守一個統(tǒng)一的格式,這個統(tǒng)一的格式是:struct結(jié)構(gòu)體名結(jié)構(gòu)體成員表列(域表);其中struct是關(guān)鍵字,不能省略,表示這是一個結(jié)構(gòu)體類型,結(jié)構(gòu)體名的命名跟標(biāo)識符相同,一對大括號中間是結(jié)構(gòu)體成員表列,右大括號后跟一個分號,這個分號不能省略。結(jié)構(gòu)體成員表列中的成員數(shù)目

3、根據(jù)不同用戶的要求可多可少。(講解p157159定義例)說明:(1) 結(jié)構(gòu)體類型是設(shè)計(jì)者根據(jù)不同對象來定義的,所以結(jié)構(gòu)體類型并非只有一種,而是根據(jù)所描述的對象的不同有很多種。(2) 定義了一個結(jié)構(gòu)體類型以后,并不意味著已分配一段內(nèi)存單元來存放這些結(jié)構(gòu)體成員,此時只是定義了類型而不分配內(nèi)存單元。(3) 結(jié)構(gòu)體中的成員名可以和程序中其它地方的變量名相同,兩者互不干擾。(4) 結(jié)構(gòu)體成員可以是整型、實(shí)型、字符型、數(shù)組、指針等基本類型外,還可以是已定義的別的構(gòu)造類型。(5) 結(jié)構(gòu)體成員中還可包括本類型的指針,用來指向同類型的變量,構(gòu)成一種新的數(shù)據(jù)結(jié)構(gòu)鏈表。8.3 結(jié)構(gòu)體變量的定義假定己定義如下結(jié)構(gòu)體類

4、型:structStudentcharname20; floatscore;那么就可以用該類型定義變量、數(shù)組或指針。如:struct Student stu,s8,*p;該類型定義了變量stu,數(shù)組s8,指針變量p。p 可以指向該類型的結(jié)構(gòu)體變量。關(guān)鍵字struct和結(jié)構(gòu)體名Student都不能省略。在定義變量的同時,系統(tǒng)分配一組內(nèi)存單元用來存放它的成員。例8.1 測試結(jié)構(gòu)體變量和數(shù)組所占的字節(jié)數(shù)。定義結(jié)構(gòu)體類型不分配內(nèi)存單元#include stdio.h struct Worker定義變量和數(shù)組分配內(nèi)存單元char name20; float pay;main()struct Worker

5、 wa,w10;/*定義結(jié)構(gòu)體變量和數(shù)組*/printf(L1=%dn,sizeof(struct Worker);printf(L2=%dn,sizeof(wa);/*變量所占字節(jié)數(shù)*/printf(L3=%dn,sizeof(w);/*數(shù)組所占字節(jié)數(shù)*/8.4 結(jié)構(gòu)體變量的使用和初始化結(jié)構(gòu)體變量的使用一般可分為兩種情況:一種是結(jié)構(gòu)體成員的使用;另一種是結(jié)構(gòu)體變量整體的使用。8.4.1結(jié)構(gòu)體變量成員的使用使用方式是:目前常見的使用方法結(jié)構(gòu)體變量名成員名若有結(jié)構(gòu)體指針已經(jīng)指向某結(jié)構(gòu)體變量,則通過指針訪問成員的方式是:目前較少使用(*結(jié)構(gòu)體指針)成員名目前常見的使用方法或結(jié)構(gòu)體指針-成員名8.4

6、.2 結(jié)構(gòu)體變量的初始化注意此題稍作修改所謂初始化就是在定義變量的同時給變量的成員賦初值(例8.2)。數(shù)組元素賦初值#include stdio.h struct Studentchar name20;float score; ; main()struct Student w3=qqq,87.5,ooo,99,kkk,88; struct Student wa=“ppp”,98.0,*p=&w1;/*變量和指針初值*/ printf(wa: %s,%fn,,wa.score);變量成員的使用printf(w0: %s,%fn,,w0.score);printf(w1

7、: %s,%fn,(*p).name,(*p).score); p=&w2;printf(w2: %s,%fn,p-name,p-score);8.4.3 結(jié)構(gòu)體變量(整體)的使用相同類型的結(jié)構(gòu)體變量可以相互整體賦值。例8.3結(jié)構(gòu)體變量(整體)使用示例。#include stdio.hstruct Studentchar name20; float score;main()struct Student wa=ppp,98.0,wb=www,68.0; struct Student *p,w3=kkk,88.0;w1=wa;/* 結(jié)構(gòu)體變量(整體)賦值 */w2=wb;/* 結(jié)構(gòu)體變量(整體)賦

8、值 */printf(w0: %s,%fn,,w0.score); p=&w1;printf(w1: %s,%fn,(*p).name,(*p).score); p=&w2;printf(w2: %s,%fn,p-name,p-score);運(yùn)行結(jié)果是:w0: kkk,88.000000w1: ppp,98.000000 w2: www,68.000000結(jié)構(gòu)體變量可以整體賦值,但不能以整體的形式輸出,要輸出只能分解為成員的形式來實(shí)現(xiàn) (見8.5節(jié))。8.5 結(jié)構(gòu)體數(shù)據(jù)的輸入/輸出結(jié)構(gòu)體數(shù)據(jù)不能以整體的形式直接輸入或輸出,只 能以成員的形式實(shí)現(xiàn)輸入輸出,成員有基本數(shù)據(jù)類型, 有具

9、體的輸入或輸出格式描述符。例8.4單個結(jié)構(gòu)體變量的輸入/輸出示例。#include stdio.h struct Studentint num;char name20; float score;main()struct Student wa; scanf(%d%s%f,&wa.num,,&wa.score);/* 成員輸入*/printf(wa:%d,%s,%fn,wa.num,,wa.score);/* 成員輸出*/運(yùn)行結(jié)果是:1111 LiMin 89.0wa: 1111,LiMin,89.000000注意,本身是地址(數(shù)組名),用%s格式符時,不

10、可以寫成&。輸入含有空格的字符串成員可采用gets()函數(shù)(見p164說明)。例8.5結(jié)構(gòu)體數(shù)組的輸入/輸出示例。從鍵盤輸入3個職工的工資單記錄,統(tǒng)計(jì)工資總數(shù), 而后輸出這3個記錄。#include stdio.h struct Workerint num;char name20; char sex;float pay;詳見p165 p166說明main()int i;float sum=0;struct Worker *p,per3;%c前要空一格scanf(“%f”,&sum);/*連接浮點(diǎn)格式*/for(i=0;i3;i+)scanf(%d%s %c%f,&peri.num

11、,,&peri.sex,&peri.pay); sum=sum+peri.pay;/*輸入3個職工的工資單記錄,統(tǒng)計(jì)工資總數(shù)*/ for(p=per;pnum,p-name,p-sex,p-pay); printf(sum=%0.1fn,sum);8.6 結(jié)構(gòu)體指針作為函數(shù)參數(shù)結(jié)構(gòu)體指針作為函數(shù)參數(shù),實(shí)際調(diào)用時傳遞的是結(jié)構(gòu)體變量的首地址,在函數(shù)調(diào)用過程中, 實(shí)參和形參指向的是同一組內(nèi)存單元,因此函數(shù)通過指針對變量的操作結(jié)果也同時“返回” 到調(diào)用函數(shù) 別是結(jié)構(gòu)體數(shù)組名作為實(shí)參時,被調(diào)函數(shù)對整個結(jié)構(gòu)體數(shù)組的操作結(jié)果也同時“返回”到調(diào)用函數(shù)中。(講解例8.6和例8.7)8.7 動態(tài)

12、內(nèi)存分配函數(shù)迄今為止,通過數(shù)據(jù)類型(不管是基本數(shù)據(jù)類型或 是結(jié)構(gòu)體類型)定義的變量或數(shù)組,內(nèi)存中都有固定 的數(shù)據(jù)結(jié)構(gòu),不能改變,并且必須在程序模塊的執(zhí)行 語句前就定義完畢。如數(shù)組,數(shù)組元素的內(nèi)存單元個 數(shù)和它們的順序關(guān)系是在定義數(shù)組時就確定的,并且是連續(xù)存放。對于那些數(shù)組元素個數(shù)不確定的數(shù)組, 在定義時就得用可能的最多元素個數(shù)來定義,實(shí)際應(yīng) 用時,可能會造成很大的浪費(fèi)。本節(jié)介紹C語言中的動 態(tài)內(nèi)存分配函數(shù),可以根據(jù)用戶的需要分配內(nèi)存空間, 甚至可以是用一個分配一個,不用時就釋放。這些工作在程序執(zhí)行過程中進(jìn)行,這樣做既充分利用了內(nèi)存 空間,又給用戶提供了靈活性。(1) 動態(tài)內(nèi)存分配函數(shù)mallo

13、c()函數(shù)原型:void* malloc(unsigned size);調(diào)用方式:(類型*)malloc(size);(調(diào)用時確定具體類型)(2) 動態(tài)內(nèi)存分配函數(shù)calloc()函數(shù)原型:void* calloc(unsigned num,unsigned size);調(diào)用方式:(類型*)calloc(numsize);(調(diào)用時確定具體類型)(3) 內(nèi)存釋放函數(shù)free()函數(shù)原型:void free(void* buffer);調(diào)用方式:free(buffer);(詳見p169 p171說明并講解例8.8)8.8 動態(tài)數(shù)據(jù)結(jié)構(gòu)鏈表動態(tài)數(shù)據(jù)結(jié)構(gòu)鏈表中的變量是根據(jù)需要向系統(tǒng)申請獲得,各變量所占

14、用的內(nèi)存單元不一定是連續(xù)存放,要把它們串連成一個整體必須通過指針,同時被串連的數(shù)據(jù)個數(shù)(元素)和它們之間的順序關(guān)系可以按需要改變, 整體所占用的內(nèi)存空間大小隨元素個數(shù)的變化而變化, 因此不會造成內(nèi)存空間的浪費(fèi)。鏈表主要有兩個用途, 一個是用來代替數(shù)組元素個數(shù)不確定的數(shù)組;另一個在數(shù)據(jù)庫管理程序中用來對磁盤文件的存儲操作,鏈表允許方便迅速地插入、刪除數(shù)據(jù)項(xiàng),同時整個磁盤文件又不必重排。鏈表(linked list)是把存放在內(nèi)存中不同地方的元素像“鏈條”那樣連接起來,構(gòu)造成一種鏈?zhǔn)綌?shù)據(jù)結(jié)構(gòu)。鏈表可分單向鏈表(單鏈表)和雙向鏈表(雙鏈表)。8.8.1 單鏈表概述0DCBA單鏈表數(shù)據(jù)結(jié)構(gòu)示意圖:he

15、ad鏈表中的每個元素(又稱結(jié)點(diǎn))除了本身的數(shù)據(jù)信息(圖中的A、B、C、D等)外,還包含指針成員。單向鏈表包含一個指針成員,它用來存儲下一個結(jié)點(diǎn)的首地址。單鏈表中末尾結(jié)點(diǎn)的指針成員賦0 ( 或空NULL),表示它不指向內(nèi)存的任何單元。可見,鏈表的結(jié)點(diǎn)是一個結(jié)構(gòu)體變量。一般專門定義一個指針,用來存放鏈表第一個結(jié)點(diǎn)的首地址,這個指針稱鏈表的頭指針(head),要操作鏈表,必須知道這個鏈表的頭指針。建立單鏈表程序的一般步驟:(1) 定義結(jié)點(diǎn)類型,除基本信息成員外還需一個本類型的指針成員next。(2) 定義鏈表頭指針(head)和工作指針(p和q)。(3) 調(diào)用動態(tài)內(nèi)存分配函數(shù)(如:malloc()

16、申請第1個結(jié)點(diǎn), 返回指針賦值給head,p和q。(4) 輸入第1個結(jié)點(diǎn)信息成員的值。(5) 再調(diào)用動態(tài)內(nèi)存分配函數(shù)申請下一個結(jié)點(diǎn),返回指針賦值給p。(6) 輸入新結(jié)點(diǎn)信息成員的值。(7) 通過q-next=p;與上一個結(jié)點(diǎn)相連。(8) 通過q=p;準(zhǔn)備申請新結(jié)點(diǎn)。返回(5)延伸單鏈表。(9)末尾結(jié)點(diǎn)的指針成員賦0(或空NULL)。(講解例8.9)其中(3)(4)完成主教材中的第一步; (5)(6)完成主教材中的第二步;(7)完成主教材中的連接;(8)完成主教材中的第三步。8.8.2 雙鏈表概述雙鏈表的結(jié)點(diǎn)中包含兩個指針成員(next和prec), next用來指向它后面的結(jié)點(diǎn),prec用來指

17、向它前面的結(jié)點(diǎn)。雙鏈表中的頭結(jié)點(diǎn)prec和尾結(jié)點(diǎn)next為0值。雙鏈表有兩條鏈組成,更為可靠和安全,即使有一條鏈損壞,仍能輸出鏈表的全部數(shù)據(jù)。建立雙鏈表程序的一般步驟與單鏈表相似。只要記住連接新結(jié)點(diǎn)時別忘了對prec指針成員的處理。 (講解例8.10)8.8.3 單鏈表創(chuàng)建和輸出函數(shù)的設(shè)計(jì)及應(yīng)用1. 創(chuàng)建單鏈表函數(shù)的設(shè)計(jì)要點(diǎn):(1) 函數(shù)返回鏈表頭指針,類型與結(jié)點(diǎn)類型相同, 所以是指針型函數(shù)。(2) 函數(shù)完成創(chuàng)建操作,無需參數(shù)。(3) 函數(shù)體的設(shè)計(jì)與“建立單鏈表程序的一般步驟29”(主教材中的三步)基本一致。(4) 返回頭指針。設(shè)單鏈表結(jié)點(diǎn)類型為S,LEN定義為:sizeof(S),則函數(shù)設(shè)計(jì)

18、如下:S *create(void)S *p,*q,*head;p=q=head=(S*)malloc(LEN);/* 第一步 */scanf(%d%s%f,&p-num,p-name,&p-pay);while(1)p=(S*)malloc(LEN);/* 第 二 步 */ scanf(%d%s%f,&p-num,p-name,&p-pay); if(p-num=0) break;/*判別循環(huán)是否繼續(xù)*/ q-next=p;/* 連接 */q=p;/* 第三步 */q-next=0;/*有效尾結(jié)點(diǎn)的next成員賦0*/free(p);/*釋放最后那個多余的結(jié)點(diǎn)*/return head;/*

19、函數(shù)返回頭指針*/2. 單鏈表輸出函數(shù)的設(shè)計(jì)該函數(shù)只完成輸出操作,無需返回值,所以函數(shù)類 型是void。但是函數(shù)參數(shù)調(diào)用時要求單鏈表的頭指針, 所以要一個參數(shù),是結(jié)構(gòu)體S類型的指針參數(shù)。函數(shù) 設(shè)計(jì)如下:void list(S *p)printf(The linked list:n); while(p!=0)printf(%d,%s,%0.1fn,p-num,p-name,p-pay); p=p-next;/*p指向下一個結(jié)點(diǎn)*/3. 單鏈表創(chuàng)建和輸出函數(shù)的應(yīng)用(講解例8.11)8.8.3 單鏈表刪除和插入函數(shù)的設(shè)計(jì)及應(yīng)用1. 刪除結(jié)點(diǎn)函數(shù)的設(shè)計(jì)要刪除鏈表中沒有用的結(jié)點(diǎn),設(shè)計(jì)成函數(shù),它的參數(shù)要求

20、傳入 作的單鏈表和被刪結(jié)點(diǎn)某成員值(如工號或姓名等),該函數(shù)完成刪除操作后,返回單鏈表的頭指針,所以是結(jié)構(gòu)體指針函數(shù)。本函數(shù)設(shè)計(jì)時選用工號作為刪除參數(shù)。函數(shù)體中的具體操作可借助于兩個工作指針p和q,p用來尋找刪除節(jié)點(diǎn)的位置,q 用來協(xié)助刪除操作。刪除節(jié)點(diǎn)的位置可分兩種情況:(1)刪除鏈表中間結(jié)點(diǎn)或末尾結(jié)點(diǎn),圖8.5所示。p找到了刪除的結(jié)點(diǎn)后,執(zhí)行如下兩語句:q-next=p-next;free(p);就把p所指向的那個結(jié)點(diǎn)刪除了。若p所指的是最后一個結(jié)點(diǎn),那么執(zhí)行此操作后就把原鏈表中倒數(shù)第二個結(jié)點(diǎn)的指針被0賦值(因?yàn)榇藭r的p-next為0值),這樣就刪除了末尾結(jié)點(diǎn)。(2)刪除頭結(jié)點(diǎn)。當(dāng)p被定位

21、在第一個結(jié)點(diǎn)的位置上,那么執(zhí)行如下兩語句:head=p-next; free(p);就把第一個結(jié)點(diǎn)刪除了,此時的頭指針已指向原鏈表的第二個結(jié)點(diǎn)。刪除結(jié)點(diǎn)函數(shù)設(shè)計(jì)如下:邏輯與,若n等于p-num結(jié)束循環(huán),說明找到了要刪除的結(jié)點(diǎn);若是p-next等于0 結(jié)束循環(huán),說明找不到要刪的結(jié)點(diǎn)。S *del(S* head,int n)S *p,*q; p=q=head;while(n!=p-num & p-next!=0) q=p; p=p-next;/* 尋找要刪除的結(jié)點(diǎn) */if(n=p-num)/*如果找到*/ if(p=head)head=p-next; /*若是頭結(jié)點(diǎn),head重新賦值*/ el

22、seq-next=p-next;/*否則刪除中間或末尾結(jié)點(diǎn) */ free(p);/* 釋 放 被 刪 結(jié) 點(diǎn) 內(nèi) 存 */ printf(“delete:%dn”,n);/*提示已刪結(jié)點(diǎn)工號*/elseprintf(“not been found!n”);/*提示找不到*/return head;/*函數(shù)返回頭指針*/2. 鏈表插入函數(shù)的設(shè)計(jì)鏈表要插入新的結(jié)點(diǎn),插入點(diǎn)的位置可以是要求的某一確定位置(如在第5個結(jié)點(diǎn)前)插入新結(jié)點(diǎn);另一種情況是在已按結(jié)點(diǎn)的某一成員值排好序的鏈表中(對結(jié)點(diǎn)的某一成員來說是有序鏈表)插入新結(jié)點(diǎn),插入新結(jié)點(diǎn)后仍要求鏈表有序。這兩種情況都要求程序先尋找插入位置,情況有些

23、相似,這里我們對后一種情況進(jìn)行討論。首先開辟一個新結(jié)點(diǎn)的內(nèi)存單元,其首地址賦值給一個指針(設(shè)為p0),通過p0給新結(jié)點(diǎn)成員賦值。再把這個新結(jié)點(diǎn)插入鏈表中,要考慮以下兩種可能:(1)如果鏈表原來是空的,那么新結(jié)點(diǎn)作為鏈表的第一個結(jié)點(diǎn);(2)如果鏈表原來已有結(jié)點(diǎn),那么尋找插入位置,可能有三種情況:插在鏈表的最前面,插在鏈表某兩個結(jié)點(diǎn)之間,或插在末尾。跟建立鏈表一樣,用兩個工作指針p和q,p用來尋找插入位置,q用來幫助插入。圖8.6所示為插入操作的三種情況。從以上分析可知,鏈表插入函數(shù)要求有兩個指針參數(shù):一個是引入鏈表頭指針參數(shù);另一個是要插入新結(jié)點(diǎn)的指針參數(shù)。這兩個參數(shù)都是結(jié)構(gòu)體指針。而函數(shù)完成操作后要返回鏈表的頭指針,因此該函數(shù)是結(jié)構(gòu)體指針型函數(shù)。插入函數(shù)設(shè)計(jì)如下:S *i

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論