




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、1 1第7章 結構體與共用體7.1 結構體概述結構體概述7.2 結構體變量結構體變量7.3 結構體數組結構體數組7.4 結構體與指針結構體與指針7.5 共用體共用體7.6 枚舉類型枚舉類型7.7 用用typedef定義類型定義類型2 2本章主要介紹C語言中的結構體和共用體兩種構造數據類型,同時介紹了枚舉類型及如何用typedef定義類型。學習重點: 結構體類型與結構體變量 共用體類型與共用體變量 枚舉類型與枚舉變量3 37.1.1 結構體的引入結構體的引入前面的課程我們學習了一些簡單數據類型(整型、實型、字符型)的定義和應用,還學習了數組(一維、二維)的定義和應用,這些數據類型的特點是:當定義
2、某一特定數據類型時,就限定該類型變量的存儲特性和取值范圍。對簡單數據類型來說,既可以定義單個的變量,也可以定義數組。而數組的全部元素都具有相同的數據類型,或者說是相同數據類型的一個集合。7.1 結結構構體體概概述述4 4在日常生活中,我們常會遇到一些需要填寫的登記表,如住宿表、成績表、通訊地址表等。在這些表中,填寫的數據是不能用同一種數據類型描述的。在住宿表中我們通常會登記上姓名、性別、身份證號碼等項目;在通訊地址表中我們會寫下姓名、郵編、郵箱地址、電話號碼、E-mail等項目。這些表中集合了多種數據,無法用前面學過的任一種數據類型完全描述,因此C語言引入了一種能集中不同數據類型于一體的數據類
3、型結構體類型。5 57.1.2 結構體類型的定義結構體類型的定義在上面描述的各種登記表中,讓我們仔細觀察一下住宿表、成績表、通訊地址表等。住宿表由下面的項目構成:6 6成績表由下面的項目構成:通訊地址表由下面的項目構成:7 7這些登記表用C語言提供的結構體類型描述如下:住宿表:struct accommod char name20; /*姓名*/ char sex; /*性別*/ char job40; /*職業*/ int age; /*年齡*/ long number; /*身份證號碼*/;8 8成績表:struct score char grade20; /*班級*/ long numb
4、er; /*學號*/ char name20; /*姓名*/ float os; /*操作系統*/ float datastru; /*數據結構*/ float compnet; /*計算機網絡*/;9 9通訊地址表:struct addr char name20; char department30; /*部門*/ char address30; /*住址*/ long box; /*郵編*/ long phone; /*電話號碼*/ char email30; /* E-mail*/;10 10這一系列對不同登記表數據結構的描述類型稱為結構體類型。可以看出結構體類型屬于構造數據類型。結構體
5、與數組類似,都是由若干分量組成的。數組是由相同類型的數組元素組成,而結構體的分量可以是不同類型的。結構體中的分量稱為結構體的成員。訪問數組中的分量(元素)是通過數組的下標,而訪問結構體中的成員是通過成員的名字。在程序中使用結構體之前,首先要對結構體的組成進行描述,稱為結構體的定義。結構體的定義說明了該結構體的組成成員,以及每個成員的數據類型。結構體定義的一般形式如下:11 11struct 結構體名 類型說明符 成員名1; 類型說明符 成員名2; 類型說明符 成員名n;其中,關鍵字“struct”是結構體的標識符;“結構體名”是所定義的結構體的類型說明符,屬于標識符,由用戶自己定義;“”中包圍
6、的是組成該結構體的成員,12 12每個成員的數據類型既可以是簡單的數據類型,也可以是復雜的構造數據類型。整個定義用分號結束,是一個完整的語句。結構體名是可以省略的,此時定義的結構體稱為無名結構體。13 137.2.1 結構體變量的定義結構體變量的定義定義一個結構體類型只是描述了此結構體的組織形式,在編譯時并不為其分配存儲空間,故不能對它進行賦值、存取或運算。為了能在程序中使用結構體類型的數據,應當定義結構體變量,并在其中存放具體的數據。7.2 結結構構體體變變量量14 14定義結構體變量有以下三種方式:(1) 先定義結構體類型再定義變量。例如:struct student int num; c
7、har name20; char sex; int age;15 15 float score; char addr30;struct student stu1, stu2;先定義結構體類型struct student,然后定義兩個struct student類型的變量stu1、stu2,它們都具有struct student類型的結構。(2) 在定義結構體類型的同時定義變量。例如:struct student16 16 int num; char name20; char sex; int age; float score; char addr30;stu1, stu2;同樣定義了結構體類型
8、struct student及其兩個變量stu1、stu2。這種形式定義的一般形式為:struct 結構體名17 17 類型說明符 成員名1; 類型說明符 成員名2; 類型說明符 成員名n;變量名1, 變量名2,;(3) 直接定義結構體類型的變量。一般形式為:struct18 18 類型說明符 成員名1; 類型說明符 成員名2; 類型說明符 成員名n;變量名1, 變量名2,;可以看到,這里省略了結構體名。例如:struct19 19 int num; char name20; char sex; int age; float score; char addr30;stu1, stu2;關于結構
9、體類型及其變量有以下幾點說明:(1) 結構體類型與結構體變量是兩個不同的概念,其區別如同int類型與int型變量的區別一樣。2020(2) 結構體類型中的成員名可以與程序中的變量同名,它們代表不同的對象,互不干擾。(3) 結構體的成員可以是簡單變量、數組、指針(后面一章將介紹)以及結構體變量。例如:struct date int month, day, year;struct student 21 21 char name20; char sex; int age; struct date birthday;stu1, stu2;定義struct student結構體類型時,成員birthda
10、y的類型定義為struct date類型變量。struct student的結構如下所示。22227.2.2 結構體變量的引用結構體變量的引用在定義了結構體變量后,就可以引用這個變量了。但是,在C語言程序中,不允許對結構體變量整體進行各種運算、賦值或輸入/輸出操作。例如,若已定義如下結構體及其變量:struct date int month, day, year;oneday;則下面的操作都是錯誤的: scanf(%d, &oneday);2323 printf(%d, oneday); scanf(%d%d%d, &oneday); printf(%d%d%d, oneday
11、); oneday = 2005, 5, 20;總之,結構體變量只能在以下兩種情況才能作為整體引用:(1) 同類型結構體變量可以相互賦值。例如,上一節定義了兩個struct student結構體類型的變量stu1、stu2,則可以把stu1的值整體賦給stu2: stu2 = stu1;2424(2) 結構體可以作為函數的實參、形參和返回值,后面章節將介紹。在C語言程序中,通常是直接訪問結構體變量的成員。引用結構體變量成員的一般形式為: 結構體變量名.成員名其中,圓點運算符“.”稱為結構體成員運算符,它在C語言中的運算優先級別是最高的,結合性為從左到右。例如,oneday.year就表示引用結
12、構體變量oneday中的year成員,因該成員的類型為int型,所以可以對它執行任何int型變量可以執行的運算。2525例如: oneday.year = 2005; scanf(%d, &oneday.year); printf(%d, oneday.year);可以看出,結構體變量的一個成員相當于一個簡單變量,對結構體成員完全可以像操作簡單變量一樣操作它。【例7-1】 輸入今天的日期,然后輸出該日期。#include void main()2626 struct date /*在函數中定義結構體類型date*/ int year, month, day; ; struct date
13、 today; printf(Please input today date:); scanf(%d.%d.%d, &today.year, &today.month, &today.day); /*輸入日期*/ printf(Today:%d-%d-%dn, today.year, today.month, today.day); /*輸出日期*/2727程序運行結果為:Please input today date:2005.5.20Today:2005-5-20如果結構體成員本身又是結構體類型的,則可繼續使用成員運算符取結構體成員的結構體成員,逐級向下,引用最低一
14、級的成員。程序只能對最低一級的成員進行運算。例如,若定義:struct date2828 int month, day, year;struct student char name20; char sex; int age; struct date birthday;stu1;2929則下面的操作是錯誤的: stu1.birthday = 10, 12, 1978;而應該使用如下操作: stu1.birthday.month = 10; stu1.birthday.day = 12; stu1.birthday.year = 1978;30307.2.3 結構體變量的初始化結構體變量的初始化和
15、其他類型變量一樣,結構體變量可以在定義時指定初始值,格式與一維數組相似: struct 結構體類型名 結構體變量 = 初始化值;【例7-2】 結構體變量的初始化示例。#include void main() struct student 31 31 char name20; char sex; int age; float score; stu1 = Wangwu, M, 20, 88.5; struct student stu2 = Zengying, F, 21, 98; printf(%-10s %c %4d %5.1fn, , stu1.sex, stu1.age,
16、stu1.score); printf(%-10s %c %4d %5.1fn, , stu2.sex, stu2.age, stu2.score);3232程序運行結果為:Wangwu M 20 88.5Zengying F 21 98.0對于結構體變量的初始化需要注意以下幾點:(1) 初始化數據之間用逗號隔開。(2) 初始化數據的個數一般與成員的個數相同,若小于成員數,則剩余的成員將被自動初始化為0或NULL。(3) 初始化數據的類型要與相應成員的類型一致。(4) 不能對結構體類型中的各成員進行初始化賦值。例如:3333 struct student = Zengying
17、, F, 21, 98;是錯誤的,因為結構體類型沒有被分配存儲空間。34347.2.4 結構體變量作函數參數結構體變量作函數參數結構體變量作函數參數分以下兩種情況:(1) 結構體變量成員作函數參數。此時同簡單變量作函數參數是一樣的。例如,在例7-2中用結構體變量stu1、stu2的各成員作實參傳遞給庫函數printf。(2) 結構體變量整體作函數參數。ANSI C以前的語言不允許用結構體變量作函數參數,只允許用指向結構體變量的指針作函數參數,傳遞的是結構體變量的首地址,而ANSI C取消了這一限制。3535用結構體變量作實參時,采取的是“值傳遞”方式,將結構體變量所占的內存單元的內容全部順序傳
18、遞給同結構體類型的形參,這與數組名作函數參數是不一樣的。數組名作實參時,傳遞給形參的是數組在內存中的首地址。3636【例7-3】 分析程序運行結果。#include #include struct student char name20; char sex; int age; float score;3737void print(struct student stu);void main() struct student stu1 = Wangwu, M, 20, 88.5; printf(%-10s %c %4d %5.1fn, , stu1.sex, stu1.age,
19、stu1.score); print(stu1); printf(%-10s %c %4d %5.1fn, , stu1.sex, stu1.age, stu1.score);3838void print(struct student stu) strcpy(, Zengying); stu.sex = F; stu.age = 21; stu.score = 98; printf(%-10s %c %4d %5.1fn, , stu.sex, stu.age, stu.score);3939程序運行結果為:Wangwu M 20 88.5Ze
20、ngying F 21 98.0Wangwu M 20 88.5程序定義了函數print,其形參stu為一個結構體變量,在函數中先對stu賦值,然后輸出stu的各成員。在main函數中,定義了結構體變量stu1,并賦了初始值;接著輸出stu1的各成員;然后將stu1作為實參傳遞給print函數;最后再一次輸出stu1各成員。從運行結果可以看出,函數print并沒有改變實參stu1各成員的值。這證明了結構體變量作參數是單向的“值傳遞”。4040結構體與數組有兩重關系:其一是結構體的一個或多個成員是數組;其二是數組的數據類型為結構體類型,這種數組稱為結構體數組。前者在前面的例題中已多次見到(如例7
21、-3中結構體類型struct student的name成員是字符數組);后者是本節要討論的內容。7.3 結結構構體體數數組組41 417.3.1 結構體數組的定義結構體數組的定義結構體數組是每個數組元素都具有相同結構體類型的數組。在實際應用中,經常用結構體數組來表示具有相同數據結構的一個群體。如一個班的學生檔案,一個車間職工的工資表等。結構體數組的定義與結構體變量定義類似,只是將結構體變量名改為結構體數組變量名。例如:struct student int num; char name20;4242 char sex; int age; float score;stu30;定義了一個數組stu,
22、其元素為struct student類型數據,共有30個數組元素。43437.3.2 結構體數組的初始化結構體數組的初始化結構體數組在定義的同時可以初始化。例如:struct student int num; char name20; char sex; float score;stu5 = 101,Li ping,M,45,4444 102,Zhang ping,M,62.5, 103,He fang,F,92.5, 104,Cheng ling,F,87, 105,Wang ming,M,58;定義數組stu時,可以省略數組的長度,即寫成以下形式: stu = , , , , ;系統會根據
23、內層“”的個數來確定數組元素的個數。45457.3.3 結構體數組元素的引用結構體數組元素的引用結構體數組元素的引用和其他數組元素的引用類似,即引用結構體數組中某個元素同樣是數組名加上此元素的下標,不同的是結構體數組的每個元素是一個結構體變量,因此還要遵循引用結構體變量的規則。其一般形式為: 數組名下標.成員名例如: stu1.num = 102;該語句給stu數組的1號元素的num成員賦值為102。46467.3.4 結構體數組應用舉例結構體數組應用舉例【例7-4】 計算一個班學生的三門課程的平均成績,并輸出該班學生姓名及平均成績。#include #define MAXSIZE 100 s
24、truct student char name16; int grade3, average;4747void main() int i, j, num, s; struct student stuMAXSIZE; printf(Please input the number of the students:); scanf(%d, &num); for (i=0; inum; i+) 4848 printf(Please input name:); scanf(%s, ); printf(Please input the grades(3):); for (j=0,
25、s=0; j3; j+) scanf(%d, &stui.gradej); s+= stui.gradej; 4949 stui.average = s/3; for (i=0; inum; i+) printf(%-10s %4dn, , stui.average);程序運行結果為:Please input the number of the students:3Please input name:wang5050Please input the grades(3):90 78 89Please input name:zhangPlease input the gr
26、ades(3):98 85 76Please input name:zengPlease input the grades(3):87 88 76wang 85zhang 86zeng 8351 51程序中定義了結構體數組stu,它有MAXSIZE(=100)個元素,每個元素都含三個成員:字符數組name(保存姓名)、整型數組grade(保存三門課的成績)和整型變量average(保存平均成績)。程序中的stui.gradej是引用數組stu的i號元素的grade成員的j號元素,即存取第i+1個學生的第j+1門課的成績。程序運行時,先輸入學生人數,然后依次輸入每個學生的姓名、三門課的成績。程序
27、將計算三門課的平均成績。最后輸出每個學生的姓名和平均成績。52527.4.1 指向結構體變量的指針指向結構體變量的指針可以定義一個指針變量來指向一個結構體變量,此時該指針變量的值是所指結構體變量的首地址。通過指針變量即可訪問結構體變量,這與指向函數和數組的指針變量的情況是相同的。7.4 結構體與指針結構體與指針5353指向結構體變量的指針變量定義的一般形式為: struct 結構體名 *指針變量名;例如,如果已經按如下方式定義了student結構體類型和該類型的變量stu1,即struct student int num; char name12; char sex; int age;stu1
28、;5454現定義一個指向struct student類型變量的指針變量pstu,則可寫為: struct student *pstu ;與前面討論的各類指針變量一樣,指向結構體變量的指針變量也必須先賦值后使用。賦值是把結構體變量的首地址賦予該指針變量,不能把結構體名賦予該指針變量。例如: pstu = &stu1; /*正確*/ pstu = &student; /*錯誤*/5555由于結構體名只能表示一個結構體類型,編譯系統并不對它分配內存空間,因此&student是錯誤的寫法,不可能去取一個結構體名的首地址。有了指向結構體變量的指針變量后,就能很方便地利用指針變量訪
29、問結構體變量及其各個成員。*pstu表示pstu所指的結構體變量stu1,stru1.num就可以用(*pstu).num來代替。注意:(*pstu).num不能寫成*pstu.num。因為成員運算符“.”優先級大于“*”運算符,*pstu.num相當于*(pstu.num)。5656在C語言中,可以用pstu-num代替(*pstu).num,它們都表示*pstu所指向的結構體變量中的num成員。即,要訪問stu1的成員,可以用以下三種形式:(1) stu1.成員名;(2) (*pstu).成員名;(3) pstu-成員名。“-”稱為指向運算符。它和成員運算符“.”一樣,在C語言中優先級最高
30、,結合性都是從左到右。例如:p-n 使用p所指結構體變量的成員n的值。5757p-n+ 使用p所指結構體變量的成員n的值,然后使n的值增1。(p+)-n 使用p所指結構體變量的成員n的值,然后使p增1。+p-n 使p所指結構體變量的成員n的值增1,然后再使用n的值。(+p)-n 使p的值增1,然后再使用p所指結構體變量的成員n的值。【例7-5】 指向結構體變量的指針變量示例。#include 5858void main() struct student int num; char *name; char sex; int age; stu1=101,Wang Hong,M,21, *pstu;
31、 pstu = &stu1;5959 printf(Number=%dnName=%sn, stu1.num, ); printf(Sex=%cnAge=%dnn, stu1.sex, stu1.age); printf(Number=%dnName=%sn, (*pstu).num, (*pstu).name); printf(Sex=%cnAge=%dnn, (*pstu).sex, (*pstu).age); printf(Number=%dnName=%sn, pstu-num, pstu-name); printf(Sex=%cnAge=%dnn, pstu
32、-sex, pstu-age);6060程序運行結果為:Number=101Name=Wang HongSex=MAge=21Number=101Name=Wang HongSex=MAge=2161 61Number=101Name=Wang HongSex=MAge=2162627.4.2 鏈表鏈表1鏈表概述鏈表概述鏈表是一種常見的重要的數據結構。其特點是,它所包含的數據對象個數及其相互關系可以按需要動態改變,可以根據需要在運行過程中向系統動態申請存儲空間,并把它與原來分配到的存儲空間“連接”起來。鏈表不要求邏輯上相鄰的元素在物理位置上也相鄰,它沒有順序存儲結構(如數組)所具有的弱點。具體
33、來說,如果要用數組來存放50個員工的數據,必須事先定義一個長度為50的數組,當員工數變為15個時,事先定義的那個數組就浪費了空間;6363當員工數增加到100時,則需要重新定義數組,并把原來數組中的內容復制過來。而鏈表就沒有這個缺點,它是按需開辟內存空間的。圖7-1給出了一個簡單的鏈表結構。圖中的指針變量head稱為頭指針變量,head后面的每個元素稱為結點。每個結點都包含兩部分:一部分存放用戶需要用的實際數據,稱為數據域;另一部分存放下一結點的首地址,稱為指針域。一個鏈表由一個頭指針變量和若干個結點組成。頭指針變量head指向第一個結點,第一個結點的指針域又指向第二個結點,直到最后一個結點。
34、最后一個結點(也稱為表尾)的指針域不指向任何結點,它被置為NULL。6464圖7-1 鏈表結構示意圖6565從圖7-1中可以看出,鏈表中各元素在內存中可以是不連續存放的。要找某一個元素,必須先根據頭指針變量找到第一個元素的地址,然后根據第一個元素找到第二個元素的地址,直到找到目標元素的地址,才能訪問目標元素。從圖7-1中還可以看出,鏈表中的結點應是結構體變量,并且結構體變量有一個成員是指針變量,用它來存放下一個結點的地址。鏈表中的每個結點都是同一種結構體類型。6666例如,一個存放學生學號和成績的結點應為以下結構:struct student int num; int score; struc
35、t student *next;前兩個成員組成數據域,后一個成員next是指針域,它是一個指向student結構體類型變量的指針變量。鏈表的頭指針變量head應該被定義為與結點類型相同的結構體指針變量。67672動態分配存儲空間庫函數動態分配存儲空間庫函數鏈表的存儲空間是動態分配的,即在需要時才分配一個結點的存儲空間。為此,C語言編譯系統提供了相關的庫函數。1) 分配內存空間函數malloc函數原型:void *malloc(unsigned int size); 功能:在內存的動態存儲區中分配一個size字節長度的連續存儲空間。函數的返回值為該區域的首地址。若操作不成功,則返回空指針。例如:
36、 int *p; p = (int *)malloc(8); 6868表示分配8字節的存儲空間,并把返回值(該存儲空間的首地址)強制轉換為整型指針后賦給整型指針變量p。這樣p就指向4個連續的整型存儲單元的第1個。可以在這段存儲空間存放4個整型數據。2) 分配內存空間函數calloc函數的原型:void *calloc(unsigned n, unsigned size );功能:在內存動態存儲區中分配n*size字節的連續存儲空間。函數的返回值為該區域的首地址。若分配未成功,返回空指針。6969例如: ps = (struct student*)calloc(2, sizeof (struct
37、 student); 其中,sizeof(struct student)是求struct student類型變量的長度(即在內存中需要的字節數)。因此該語句的意思是:分配一連續存儲空間,其長度為struct student類型變量長度的2倍,然后把首地址強制轉換為struct student類型指針,并賦予ps。70703) 釋放內存空間函數free函數原型:void free(void *p)功能:釋放由指針變量p所指示的內存區域。p是調用calloc或malloc函數時返回的值。free函數本身是沒有返回值的。例如: int *p; p = (int *)malloc(8); free(p
38、); 通過函數free將已分配的內存區域交還系統,使系統可以重新對其進行分配。 71 713鏈表的基本操作鏈表的基本操作鏈表的基本操作包括鏈表的建立、插入、刪除、輸出和查找等。1) 建立鏈表所謂建立鏈表,是指一個一個地輸入各結點的數據,并建立起各結點前后相鏈接的關系。下面通過一個例子來說明如何建立一個鏈表。【例7-6】 編寫函數create,建立一n個結點的鏈表來存放學生數據,學生數據包括學號和年齡兩項。源程序如下:#define NULL 07272#define TYPE struct student#define LEN sizeof(struct student)struct stud
39、ent int num; int age; struct student *next;TYPE *create(int n)7373 TYPE *head=NULL, *pf, *pb; int i; for (i=0; inum, &pb-age); /*設置新結點的數據域*/ pb-next = NULL; /*設置新結點的指針域*/7474 if (i=0) head=pb; /*若新結點是第一結點,則使head指向它*/ else pf-next=pb; /*若不是第一結點,則使前一結點的指針域指向它*/ pf = pb; /*用pf指向每一新結點的前結點*/ return (
40、head);7575圖7-2 一個結點時的鏈表7676在函數外定義了三個符號常量:用NULL表示0;用TYPE表示struct student;用LEN表示sizeof(struct student)。這樣可以在后面的程序中減少書寫、方便閱讀。結構體student在函數外定義,以使程序中各函數均可使用。create函數用于建立一個有n個結點的鏈表,它是一個指針函數,返回的指針指向student結構體類型變量。在create函數內定義了三個student結構體類型的指針變量。7777head用來作鏈表的頭指針,pf用來指向新結點的前一結點,pb用來指向新結點。在for語句內,用malloc函數分
41、配長度與student長度相等的存儲空間作為新結點,首地址賦予pb。然后輸入新結點的數據,并將指針域設置為NULL。如果新結點為第一結點(i=0),則把pb值(新結點指針)賦予head;如果不是第一結點,則把pb值賦予pf所指結點的指針域next。最后把pb值賦予pf,使其在下一循環時仍指向新結點的前一結點。圖7-2是輸入一個結點后,鏈表和各指針變量的狀態。圖7-3是輸入第二個結點時,鏈表和各指針變量的變化過程。7878圖7-3(a)是執行到語句“pf-next=pb;”前,鏈表和各指針變量的狀態;圖7-3(b)是剛執行語句“pf-next=pb;”后,鏈表和各指針變量的狀態;圖7-3(c)是
42、剛執行語句“pf=pb;”后,鏈表和各指針變量的狀態。7979圖7-3 添加第二個結點時的鏈表80802) 查找鏈表查找鏈表就是在鏈表中查找需要的數據。前面講過,在鏈表中查找數據,需要從頭指針開始一個結點一個結點地往后找,如下例所示。【例7-7】 編寫一個函數,可在鏈表中按學號查找學生。源程序如下:TYPE *search (TYPE *head, int n) TYPE *p; int i; p = head;81 81 while (p-num!=n & p-next!=NULL) p = p-next; /*不是要找的結點,移到下一個結點*/ if (p-num=n) retur
43、n (p); /*找到結點,則返回該結點指針*/ if (p-num!=n & p-next=NULL) /*鏈表中不存在此結點*/ printf (Node %d has not been found!n,n8282本函數中使用了例7-6中定義的符號常量TYPE,它等同于struct student。函數有兩個形參:head是指向struct student類型變量的指針變量,用來接收實參傳遞來的鏈表頭指針;n用來接收要查找結點的學號。進入while循環,逐個檢查結點的num成員是否等于n。如果不等于n,且指針域不等于NULL(不是最后結點),則后移一個結點,繼續循環。如找到該結點,
44、則返回結點指針。如循環完所有結點仍未找到,則輸出“未找到”的提示信息。83833) 在鏈表中刪除結點在鏈表中刪除一個結點時,要分兩種情況:一是被刪結點為第一個結點,則只需要修改頭指針變量head的值,使其指向第二個結點;二是被刪結點不是第一個結點,則需要調整其前一個結點的指針域,使它指向被刪結點的后一結點。若從圖7-4(a)所示的鏈表中刪除內存地址為1100的結點,則需要將內存地址為1300的結點的指針域修改為內存地址為1043的結點的首地址,如圖7-4(b)所示。8484圖7-4 在鏈表中刪除一個結點示意圖8585【例7-8】 編寫一個函數,可刪除鏈表中的指定結點。源程序如下:TYPE *r
45、emove(TYPE *head, int num) TYPE *pf, *pb; if (head=NULL) /*如為空表,輸出提示信息*/ printf(The list is empty!n); return head; 8686 pb = head; /*從第1個結點開始*/ while (pb-num!=num & pb-next!=NULL) pf=pb; pb=pbnext; if(pb-num=num) /*找到待刪結點*/ 8787 if(pb=head) head=pb-next; /*待刪結點為第一個結點,修改head指針*/ else pf-next=pb-n
46、ext; /*不是第一個結點,修改其前一結點指針域*/ free(pb); /*釋放已刪結點存儲空間*/ printf(The node is deleted.n); else printf(Didnt found!n); return head; 8888函數有兩個形參:head接收實參傳遞來的鏈表頭指針,num接收待刪結點的學號。首先判斷鏈表是否為空,為空則不可能有待刪結點。若不為空,則使pb指針指向鏈表的第一個結點。進入while循環后,逐個檢查所有結點,直到找到待刪結點或鏈表才能結束。找到待刪結點(pb所指)之后,再看是否為第一結點。若是,則使head指向第二結點(pb-next所指)
47、;否則使被刪結點的前一結點(pf所指)的指針域指向被刪結點的后一結點(pb-next所指)。然后釋放被刪結點(pb所指)的內存空間。如未找到待刪的結點,則輸出“未找到”的提示信息。最后返回head值。89894) 在鏈表中插入結點在鏈表中插入一個新結點時,分四種情況:第一種情況:原表是空表。只需使head指向新結點即可。第二種情況:結點插在第一結點之前。需要使head指向新結點,新結點的指針域指向原來的第一結點。第三種情況:結點插在表尾,即最后一個結點之后。需要使原表尾結點指針域指向新結點,新結點指針域置為NULL。第四種情況:在兩結點之間插入。需要使插入位置前一結點的指針域指向新結點,新結點
48、的指針域指向插入位置后一結點。9090【例7-9】 已知學生鏈表中,各結點按學號由小到大的順序排列。寫一個函數,將一個結點插入鏈表。要求插入后的鏈表也應該按學號由小到大的順序排列。源程序如下:TYPE *insert(TYPE *head, TYPE *pnew) TYPE *pf, *pb; pb = head; if (head=NULL) /*原表為空表*/ 91 91 head = pnew; pnew-next = NULL; else while (pnew-num pb-num) & (pb-next != NULL) pf=pb; pb=pb-next; 9292 if
49、 (pnew-num num) /*不是在表尾*/ if (head=pb) /*在第一結點之前插入*/ head = pnew; /*使head指向新結點*/ else /*兩結點之間插入*/ pf-next = pnew; /*使插入位置前一結點的指針域指向新結點*/ pnew-next = pb; /*使新結點指針域指向插入位置后一結點*/ 9393 else /*在表尾*/ pb-next = pnew; /*使原表尾結點指針域指向新結點*/ pnew-next = NULL; /*新結點指針域置為NULL*/ return head;9494本函數有兩個形參:head用來接收實參傳遞
50、來的鏈表頭指針;pnew指向新結點。函數體中定義了兩個指針變量:pf用來指向插入位置的前一結點;pb用來指向插入位置的后一結點。函數執行時,首先判斷鏈表是否為空。若鏈表為空,則使head指向新結點。若鏈表不為空,則用while循環查找插入位置。找到之后,再判斷插入位置是在第一結點之前,還是兩結點之間,還是表尾。若插入位置在第一結點之前,則使head 指向新結點。若插入位置在兩結點之間,則使插入位置前一個結點(pf所指)的指針域指向新結點。9595語句“pnew-next =pb;”使新結點指針域指向插入位置后一結點(pb所指)。若插入位置在表尾,則使原表尾結點(pb所指)的指針域指向新結點,新
51、結點指針域置為NULL。函數返回鏈表的頭指針。96967.4.3 指向結構體數組的指針指向結構體數組的指針同數組一樣,也可以用指針來指向結構體數組及其元素。當指針變量指向結構體數組時,指針變量的值為結構體數組的首地址,也是數組0號元素的首地址。當指針變量指向結構體數組元素時,指針變量的值為該數組元素的首地址。【例7-10】 指向結構體數組的指針變量示例。#include struct student9797 int num; char *name; char sex; int age;struct student stu3 = 102,Zhang San,M,20, 105,Li Si,M,2
52、2, 109,Wang Wu,F,23;void main()9898 struct student *pstu; printf(No. Name Sex Agen); for (pstu=stu; pstunum, pstu-name, pstu-sex, pstu-age); 程序運行結果為:No. Name Sex Age102 Zhang San M 20105 Li Si M 22109 Wang Wu F 2399997.4.4 用指向結構體的指針作函數參數用指向結構體的指針作函數參數在ANSI C標準中允許結構體變量作函數參數,采用的是“值傳遞”方式,將結構體變量所占的內存單元的
53、內容全部順序傳遞給形參。形參也必須是同類型的結構體變量。在函數調用期間形參也要占用內存單元。這種傳遞方式在空間和時間上開銷很大,尤其是有數組成員時。此外,如果在執行被調函數期間改變了形參的值,該值便不能返回主調函數,這就造成使用上的不方便。因此最好的辦法就是使用指針,即用指向結構體變量的指針變量作函數參數。100100這時由實參傳遞給形參的只是變量地址,時間和空間的開銷很小,也可以在函數中修改主調函數中變量的值。【例7-11】 用指向結構體變量的指針變量作函數參數,計算一組學生的平均成績和不及格人數。#include void avg(struct student *pstu);struct
54、student101101 int num; char *name; char sex; float score;stu5 = 101,Wang Hong,M,75, 102,Zhang Huan,M,58, 103,He Ying,F,87.5, 104,Zeng Ling,F,80, 105,Li Ming,M,98;void main()102102 struct student *pstu; pstu = stu; avg(pstu);void avg(struct student *pstu) int c=0, i; float average, s=0; for (i=0; isc
55、ore; if (pstu-score60) c +=1; printf(s=%fn, s); average = s/5; printf(average=%fncount=%dn, average, c);104104程序運行結果為:s=398.500000average=79.699997count=1在上面程序中,也可以直接將結構體數組的指針(地址)傳遞給函數的形參: avg(&stu);修改后的程序運行結果不變。105105共用體也是一種構造數據類型。在一個共用體內可以定義多種不同的數據類型,在一個被定義為該共用體類型的變量中,允許裝入該共用體所定義的任何一種數據類型的數據。7
56、.5 共共 用用 體體1061067.5.1 共用體類型的定義共用體類型的定義共用體類型定義格式如下:union 共用體名 類型說明符 成員名1; 類型說明符 成員名2; 類型說明符 成員名n;107107其中,關鍵字union是共用體的標識符;“共用體名”是所定義的共用體的類型說明符,屬于標識符,由用戶自己定義;“”中包圍的是組成該共用體的成員,每個成員的數據類型既可以是簡單的數據類型,也可以是復雜的構造數據類型。整個定義用分號結束,是一個完整的語句。例如:union icf108108 int i; char c; float f;定義了一個共用體類型icf,包含一個整型成員i、一個字符型
57、成員c和一個單精度型成員f。共用體名是可以省略的,此時定義的共用體稱為無名共用體。1091097.5.2 共用體變量的定義共用體變量的定義定義共用體變量有以下三種方式:(1) 先定義共用體類型再定義變量。例如:union data int i; char ch; float f;110110union data a, b, c;(2) 在定義共用體類型的同時定義變量。例如:union data int i; char ch; float f;a, b, c;111111(3) 直接定義共用體類型的變量。例如:union int i; char ch; float f;a, b, c;11211
58、2可以看出,共用體與結構體定義很相似,但兩者有本質上的不同。在結構體中各成員有各自的內存空間,一個結構體變量所占內存長度是各成員占內存長度之和。而在共用體中,各成員共享一段內存空間,一個共用體變量所占內存的長度等于各成員中占內存最長的長度。應該說明的是,這里所謂的共享并不是指把多個成員同時裝入一個共用體變量內,而是指該共用體變量可被賦予任一成員值,但每次只能賦一種值,賦入新值則覆蓋舊值。1131137.5.3 共用體變量的引用共用體變量的引用只有先定義了共用體變量后才能引用它,并且不能引用共用體變量,而只能引用共用體變量中的成員。引用形式如下: 共用體變量名.成員名例如:a.i、a.ch和a.
59、f分別是對共用體變量a的成員i、ch和f的引用。114114說明:(1) 共用體變量中,可以包含若干個成員及若干種類型,但共用體成員不能同時使用。在每一時刻,只有一個成員及一種類型起作用,不能同時引用多個成員及多種類型。(2) 共用體變量中起作用的成員值是最后一次存放的成員值。如: a.i=278, a.ch=D, a.f=5.78;不能企圖通過函數: printf(%d,%c,%f, a.i, a.ch, a.f);得到a.i和a.ch的值,而只能得到a.f的值。115115(3) 不能在定義共用體變量時對它初始化,不能對共用體變量名賦值,也不能企圖引用共用體變量名來得到某成員的值。例如,下
60、面語句都是錯誤的:union data int i; char ch; float f;a = 50, b, 5.5;a = 10;116116a =50, b, 5.5;e = a;(4) 共用體變量不能作函數參數,函數的返回值也不能是共用體類型。(5) 共用體類型和結構體類型可以相互嵌套,共用體中成員可以為數組,甚至還可以定義共用體數組。117117在實際應用中,有些變量的取值范圍是有限的,往往可能只有幾個值。例如,一個星期只有7天,一年只有12個月。在C語言中,可以把這些變量定義為枚舉類型。所謂“枚舉”,就是將變量可取的值一一列舉出來,而變量的值只能取列舉出來的值。7.6 枚枚 舉舉 類類 型型118118與結構體和共用體一樣,枚舉也要先定義類型,再定義該類型的變量。枚舉類型定義的一般形式為: enum 枚舉類型名
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 項目管理績效提升的新維度試題及答案
- 項目管理專家認證考試重要試題及答案
- 2024年福建事業單位考試全局復習策略與試題及答案
- 項目管理資格考試知識推理試題及答案
- 2025年會計政策分析試題及答案
- 精準備戰特許金融分析師考試試題及答案
- 武威電梯裝修施工方案
- 項目管理資格復習關鍵點試題及答案
- 信豐避雷塔安裝施工方案
- 耐高壓潔凈管道施工方案
- 2025商業綜合體委托經營管理合同書
- 人工智能導論課件 第十三章 類腦智能
- 河北單招時政試題及答案
- 2024-2025班主任的培訓心得體會(29篇)
- 實驗14 探究液體內部壓強的特點-中考物理必考實驗專項復習
- 7 請到我的家鄉來(第一課時)(教學設計)統編版道德與法治三年級下冊
- 護理不良事件案例分析及警示
- B超健康知識講座課件
- 煤炭倉儲協議合同
- 政 治薪火相傳的傳統美德 教案-2024-2025學年統編版道德與法治七年級下冊
- 2025-2030中國腦芯片模型行業市場發展趨勢與前景展望戰略研究報告
評論
0/150
提交評論