第9章結(jié)構(gòu)體和共用體12-07_第1頁
第9章結(jié)構(gòu)體和共用體12-07_第2頁
第9章結(jié)構(gòu)體和共用體12-07_第3頁
第9章結(jié)構(gòu)體和共用體12-07_第4頁
第9章結(jié)構(gòu)體和共用體12-07_第5頁
已閱讀5頁,還剩18頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、博學(xué)谷讓IT教學(xué)更簡單,讓IT學(xué)習(xí)更有效第9章 結(jié)構(gòu)體和共用體學(xué)習(xí)目標(biāo)u 掌握結(jié)構(gòu)體類型與變量的定義及初始化u 掌握結(jié)構(gòu)體變量的引用u 掌握結(jié)構(gòu)體與數(shù)組、指針、函數(shù)等結(jié)合使用u 掌握共用體變量的定義與引用u 理解結(jié)構(gòu)體與共用體的內(nèi)存分配機(jī)制前面章節(jié)所學(xué)的數(shù)據(jù)類型都是分散的、互相獨立的,例如定義int a和char b兩個變量,這兩個變量是毫無內(nèi)在聯(lián)系的,但在實際生活和工作中,經(jīng)常需要處理一些關(guān)系密切的數(shù)據(jù),例如,描述公司一個員工的姓名、部門、職位、電話、E-mail地址等,由于這些數(shù)據(jù)的類型各不相同,因此,要想對這些數(shù)據(jù)進(jìn)行統(tǒng)一管理,僅靠前面所學(xué)的基本類型和數(shù)組都很難實現(xiàn)。為此,C語言提供了另

2、外兩種構(gòu)造類型,分別是結(jié)構(gòu)體和共用體,本章將圍繞這兩種構(gòu)造類型進(jìn)行詳細(xì)地講解。9.1 結(jié)構(gòu)體類型和結(jié)構(gòu)體變量9.1.1 結(jié)構(gòu)體類型定義結(jié)構(gòu)體是一種構(gòu)造數(shù)據(jù)類型,把不同類型的數(shù)據(jù)整合在一起,每一個數(shù)據(jù)都稱為該結(jié)構(gòu)體類型的成員。在程序設(shè)計中,使用結(jié)構(gòu)體類型時,首先要對結(jié)構(gòu)體類型的組成進(jìn)行描述,結(jié)構(gòu)體類型的定義方式如下所示:struct 結(jié)構(gòu)體類型名稱數(shù)據(jù)類型 成員名1;數(shù)據(jù)類型 成員名2;數(shù)據(jù)類型 成員名n;在上述語法結(jié)構(gòu)中,“struct”是定義結(jié)構(gòu)體類型的關(guān)鍵字,其后是所定義的“結(jié)構(gòu)體類型名稱”,在“結(jié)構(gòu)體類型名稱”下的大括號中,定義了結(jié)構(gòu)體類型的成員項,每個成員是由“數(shù)據(jù)類型”和“成員名”共

3、同組成的。例如,為了描述一組學(xué)生信息,該信息由學(xué)號(num)、姓名(name)、性別(sex)、年齡(age)、地址(address)等組成,我們可以使用下列語句定義一個名稱為Student的結(jié)構(gòu)體類型:struct Studentint num;char name10;char sex;int age;char address30;在上述結(jié)構(gòu)體類型的定義中,結(jié)構(gòu)體類型Student由5個成員組成,分別是num、name、sex、age和address。值得一提的是,結(jié)構(gòu)體類型中的成員,也可以是一個結(jié)構(gòu)體變量,例如,在學(xué)生信息中增加一項出生日期的信息,具體代碼如下:struct Dateint

4、 year;int month;int day;struct Studentint num;char name10;char sex;struct Date birthday; stu1;在上述代碼中,我們首先定義了結(jié)構(gòu)體類型Date,該結(jié)構(gòu)體類型由year、month、day三個成員組成;然后定義了結(jié)構(gòu)體變量stu1,其中的成員birthday是Date結(jié)構(gòu)體類型。student的類型結(jié)構(gòu)如圖9-1所示。圖9-1 結(jié)構(gòu)體類型Student的類型結(jié)構(gòu)注意:1、 結(jié)構(gòu)體類型定義以關(guān)鍵字struct開頭,后面跟的是結(jié)構(gòu)體類型的名稱,該名稱的命名規(guī)則與變量名的命名規(guī)則相同。2、 定義好一個結(jié)構(gòu)體類型

5、后,并不意味著立即分配一塊內(nèi)存單元來存放各個數(shù)據(jù)成員,它只是告訴編譯器,該結(jié)構(gòu)體類型是由哪些數(shù)據(jù)類型的成員構(gòu)成,各占多少個字節(jié),按什么格式存儲,并把它們當(dāng)作一個整體來處理。 3、 結(jié)構(gòu)體類型定義末尾括號后的分號不可缺少。4、 結(jié)構(gòu)體類型的成員可以是一個結(jié)構(gòu)體變量,但不能是自身結(jié)構(gòu)體類型的變量。 9.1.2 結(jié)構(gòu)體變量的定義上個小節(jié)只是定義了結(jié)構(gòu)體類型,它僅相當(dāng)于一個模型,其中并無具體數(shù)據(jù),系統(tǒng)也不會為它分配內(nèi)存空間。為了能在程序中使用結(jié)構(gòu)體類型的數(shù)據(jù),應(yīng)該定義結(jié)構(gòu)體類型的變量,并在其中存放具體的數(shù)據(jù)。下列是定義結(jié)構(gòu)體變量的三種方式。1、 先定義結(jié)構(gòu)體類型,再定義結(jié)構(gòu)體變量定義好結(jié)構(gòu)體類型后,就

6、可以定義結(jié)構(gòu)體變量了,定義結(jié)構(gòu)體變量的語法格式如下所示:struct 結(jié)構(gòu)體類型名 結(jié)構(gòu)體變量名;例如:struct student stu1, stu2; 上述示例定義了結(jié)構(gòu)體類型變量stu1和stu2,這時變量stu1和stu2具有了結(jié)構(gòu)體特征,它們各自存儲了一組基本類型的變量,具體如圖9-2所示。圖9-2 變量stu1、stu2的存儲結(jié)構(gòu)從圖9-2中可以看出,變量stu1和stu2分別占據(jù)了一塊連續(xù)的內(nèi)存空間。2、 在定義結(jié)構(gòu)體類型的同時定義結(jié)構(gòu)體變量該方式的作用與第一種方式相同,其語法格式如下所示:struct 結(jié)構(gòu)體類型名稱數(shù)據(jù)類型 成員名1;數(shù)據(jù)類型 成員名2;數(shù)據(jù)類型 成員名n;

7、 結(jié)構(gòu)體變量名列表;例如:struct studentint num;char name10;char sex; stu1, stu2;上述代碼在定義結(jié)構(gòu)體類型student的同時,也定義了結(jié)構(gòu)體類型變量stu1和stu2。其中變量stu1和stu2中包含的成員的數(shù)據(jù)類型都是一樣的。3、 直接定義結(jié)構(gòu)體變量除了上述兩種方式外,我們還可以直接定義結(jié)構(gòu)體變量,其語法格如下所示:struct數(shù)據(jù)類型 成員名1;數(shù)據(jù)類型 成員名2;數(shù)據(jù)類型 成員名n; 結(jié)構(gòu)體變量名列表;例如:structint num;char name10;char sex; stu1, stu2;上述代碼同樣定義了結(jié)構(gòu)體變量st

8、u1和stu2,但采用這種方式定義的結(jié)構(gòu)體是沒有類型名稱,我們稱之為匿名結(jié)構(gòu)體。注意:結(jié)構(gòu)體類型是用戶自定義的一種數(shù)據(jù)類型,它同前面所介紹的簡單數(shù)據(jù)類型一樣,在編譯時對結(jié)構(gòu)體類型不分配空間。只有用它來定義某個變量時,才會為該結(jié)構(gòu)體變量分配結(jié)構(gòu)體類型所需大小的內(nèi)存單元。9.1.3 結(jié)構(gòu)體變量的內(nèi)存分配結(jié)構(gòu)體變量一旦被定義,系統(tǒng)就會為其分配內(nèi)存。結(jié)構(gòu)體變量占據(jù)的內(nèi)存大小是按照字節(jié)對齊的機(jī)制來分配的。字節(jié)對齊就是字節(jié)按照一定規(guī)則在空間上排列。通常情況下,字節(jié)對齊滿足兩個原則,具體如下:(1)結(jié)構(gòu)體的每個成員變量相對于結(jié)構(gòu)體首地址的偏移量,是該成員變量的基本數(shù)據(jù)類型(不包括結(jié)構(gòu)體、數(shù)組等)大小的整數(shù)倍

9、,如果不夠,編譯器會在成員之間加上填充字節(jié)。接下來通過一個案例來打印出每個成員變量的地址,如例9-1所示。例9-1 1 #include <stdio.h> 2 / 直接定義結(jié)構(gòu)體變量 3 struct 4 5 char a; 6 double b; 7 int c; 8 short d; 9 s; 10 void main() 11 12 printf("成員變量a的地址:%dn", &s.a); 13 printf("成員變量b的地址:%dn", &s.b); 14 printf("成員變量c的地址:%dn&qu

10、ot;, &s.c); 15 printf("成員變量d的地址:%dn", &s.d); 16 printf("成員變量d的地址:%dn", &s+1; 17 運行結(jié)果如圖9-3所示。圖9-3 運行結(jié)果從圖9-3中可以看出,結(jié)構(gòu)體變量中成員變量的地址都被打印出來了。結(jié)構(gòu)體變量S中各成員在內(nèi)存中所占內(nèi)存如圖9-4所示。圖9-4 結(jié)構(gòu)體變量中各成員所占內(nèi)存圖接下來根據(jù)圖9-3和圖9-4來逐步分析每個成員變量的地址:l 成員變量a的地址是3703968,同時這也是結(jié)構(gòu)體變量s的首地址;l 成員變量b的地址是3703976,相對于結(jié)構(gòu)體變

11、量的首地址的偏移量是8個字節(jié)。這是因為成員變量b的基本數(shù)據(jù)類型是double型,其偏移量應(yīng)該是8(sizeof(double))的倍數(shù),所以a變量后面被填充了7個字節(jié);l 成員變量c的地址是3703984,相對于結(jié)構(gòu)體變量的首地址的偏移量是16,是變量a與變量b所占內(nèi)存大小之和,正好也是4(sizeof(int))的倍數(shù);l 成員變量d的地址是3703988,相對于首地址的偏移量是20字節(jié),是變量a、b、c所占內(nèi)存大小之和,正好也是2(sizeof(short))的倍數(shù)。(2)結(jié)構(gòu)體的總大小為結(jié)構(gòu)體最寬基本類型成員大小的整數(shù)倍,如果不夠,編譯器會在最末一個成員之后加上填充字節(jié)。經(jīng)過例9-1的分

12、析,可以計算出結(jié)構(gòu)體變量s的內(nèi)存大小是22,但是這并不符合字節(jié)對齊的第二項準(zhǔn)則,下面將例9-1中的結(jié)構(gòu)體變量在內(nèi)存中的大小打印出來,如例9-2所示。例9-2 1 #include <stdio.h> 2 struct 3 4 char a; 5 double b; 6 int c; 7 short d; 8 s; 9 void main() 10 11 printf("結(jié)構(gòu)體變量s在內(nèi)存中的大?。?dn", sizeof(s); 12 運行結(jié)果如圖9-5所示。圖9-5 運行結(jié)果從圖9-5中可以看出,結(jié)構(gòu)體變量s的內(nèi)存大小為24字節(jié),而非22字節(jié)。這是因為,結(jié)構(gòu)體

13、的總大小應(yīng)該是最寬基本類型成員大小的整數(shù)倍。成員變量中最寬基本類型的大小為8(sizeof(double)),所以d后面被填充了2個字節(jié),結(jié)構(gòu)體變量s所占內(nèi)存大小為24字節(jié)。其內(nèi)存分配如圖9-6所示。圖9-6 結(jié)構(gòu)體s占內(nèi)存的總大小需要注意的是,如果結(jié)構(gòu)體中有構(gòu)造類型變量,如結(jié)構(gòu)體中有char類型數(shù)組成員,則其偏移量是按數(shù)組中的元素類型為基準(zhǔn),即偏移量是1(sizeof(char))的倍數(shù)。如果是int類型數(shù)組,則偏移量是4(sizeof(int))的倍數(shù)。關(guān)于結(jié)構(gòu)體變量的分配,不同的編繹器有不同的分配規(guī)則,讀者了解即可,在實際應(yīng)用中可用sizeof()運算符很快捷的求出結(jié)構(gòu)體變量的大小。9.

14、1.4 結(jié)構(gòu)體變量的初始化由于結(jié)構(gòu)體變量中存儲的是一組類型不同的數(shù)據(jù),因此,為結(jié)構(gòu)體變量初始化的過程,其實就是為結(jié)構(gòu)體中各個成員初始化的過程。根據(jù)結(jié)構(gòu)體變量定義方式的不同,結(jié)構(gòu)體變量初始化的方式可分為兩種。1、在定義結(jié)構(gòu)體類型和結(jié)構(gòu)體變量的同時,對結(jié)構(gòu)體變量初始化,具體示例如下:struct Studentint num;char name10;char sex;stu=20140101,"Zhang San",'M' ;上述代碼在定義結(jié)構(gòu)體變量stu的同時,就對其中的成員進(jìn)行了初始化。2、定義好結(jié)構(gòu)體類型后,對結(jié)構(gòu)體變量初始化,具體示例如下:struct

15、Studentint num;char name10;char sex;struct Student stu = 20140101,"Zhang San",'M'在上述代碼中,首先定義了一個結(jié)構(gòu)體類型Student,然后在定義結(jié)構(gòu)體變量時,為其中的成員進(jìn)行初始化。M腳下留心:初始化一部分成員變量在對結(jié)構(gòu)體初始化時,如果只初始化其中一部分成員,則要對前面的成員初始化,后面的成員可以空余,因為給成員變量賦值時,編繹器是從按成員從前往后匹配,而不是按數(shù)據(jù)類型自動去匹配。可以給一部分成員初始化,然后將各個成員打印出來,如例9-3所示。例9-3#include <

16、;stdio.h>struct Studentint num;char name10;char sex;stu = 20140101, 'M' ;void main() printf("num = %dn", stu.num);printf("name = %sn", );printf("sex = %cn", stu.sex);運行結(jié)果如圖9-7所示。圖9-7 運行結(jié)果如圖9-7所示,在結(jié)構(gòu)體變量stu中只對num和sex賦值,但在輸出所有成員的值時,M卻賦值給了name,sex沒有值。9.1.

17、5 結(jié)構(gòu)體變量的引用定義并初始化結(jié)構(gòu)體變量的目的是使用結(jié)構(gòu)體變量中的成員。在C語言中,引用結(jié)構(gòu)體變量中一個成員的方式如下所示:結(jié)構(gòu)體變量名.成員名;例如,下列的語句用于引用結(jié)構(gòu)體變量stu1中num成員:stu1.num;為了幫助大家更好地掌握結(jié)構(gòu)體變量的使用,接下來通過一個案例來輸出結(jié)構(gòu)體變量中所有成員的值,如例9-4所示。例9-4 1 #include <stdio.h> 2 #include <stdlib.h> 3 struct Student 4 5 char name50; 6 int age; 7 ; 8 void main() 9 10 struct S

18、tudent s = "Zhang San", 23; 11 s.age = 24; 12 printf("%s %dn", , s.age); 13 運行結(jié)果如圖9-8所示。圖9-8 運行結(jié)果 從圖9-8中可以看出,結(jié)構(gòu)體變量中成員name和age的值被輸出了。9.2 結(jié)構(gòu)體數(shù)組一個結(jié)構(gòu)體變量可以存儲一組數(shù)據(jù),例如一個學(xué)生的序號、姓名、性別等數(shù)據(jù)。如果有10個學(xué)生的信息需要存儲,可以采用結(jié)構(gòu)體數(shù)組。與前面講解的數(shù)組不同,結(jié)構(gòu)體數(shù)組中的每個元素都是結(jié)構(gòu)體類型的,它們都是具有若干個成員的項。本節(jié)將針對結(jié)構(gòu)體數(shù)組的定義、引用及初始化方式進(jìn)行詳細(xì)地

19、講解。9.2.1 結(jié)構(gòu)體數(shù)組的定義假設(shè)一個班有20個學(xué)生,如果我們需要描述這20個學(xué)生的信息,可以定義一個長度為20的Student類型數(shù)組,與定義結(jié)構(gòu)體變量一樣,可以采用三種方式定義結(jié)構(gòu)體數(shù)組stus。 1、 先定義結(jié)構(gòu)體類型,后定義結(jié)構(gòu)體數(shù)組,具體示例如下:struct Studentint num;char name10;char sex;struct Student stus20;2、 在定義結(jié)構(gòu)體類型的同時定義結(jié)構(gòu)體數(shù)組,具體示例如下:struct Studentint num;char name10;char sex; stus20;3、 直接定義結(jié)構(gòu)體數(shù)組,具體示例如下:stru

20、ct int num;char name10;char sex; stus20;9.2.2 結(jié)構(gòu)體數(shù)組的初始化結(jié)構(gòu)體數(shù)組的初始化方式與數(shù)組類似,都是通過為元素賦值的方式完成的。由于結(jié)構(gòu)體數(shù)組中的每個元素都是一個結(jié)構(gòu)體變量,因此,在為每個元素賦值的時候,需要將其成員的值依次放到一對大括號中。例如,定義一個結(jié)構(gòu)體數(shù)組students,該數(shù)組有3個元素,并且每個元素有num,name,sex三個成員,可以采用下列兩種方式對結(jié)構(gòu)體數(shù)組students初始化。1、先定義結(jié)構(gòu)體數(shù)組類型,然后初始化結(jié)構(gòu)體數(shù)組,具體示例如下:struct Studentint num;char name10;char sex

21、;struct Student students3 = 20140101, "Zhang San",'M', 20140102, "Li Si",'W' 20140103, "Zhao Liu",'M'2、在定義結(jié)構(gòu)體數(shù)組的同時,對結(jié)構(gòu)體數(shù)組初始化,具體示例如下:struct Studentint num;char name10;char sex; students3 = 20140101, "Zhang San",'M', 20140102, &qu

22、ot;Li Si",'W',20140103, "Zhao Liu",'M'當(dāng)然,使用這種方式初始化結(jié)構(gòu)體數(shù)組時,也可以不指定結(jié)構(gòu)體數(shù)組的長度,系統(tǒng)在編譯時,會自動根據(jù)初始化的值決定結(jié)構(gòu)體數(shù)組的長度。例如,下列初始化方式也是合法的。struct Studentint num;char name10;char sex; Student students = 20140101, "Zhang San",'M', 20140102, "Li Si",'W',20140

23、103, "Zhao Liu",'M'9.2.3 結(jié)構(gòu)體數(shù)組的引用結(jié)構(gòu)體數(shù)組的引用是指對結(jié)構(gòu)體數(shù)組元素的引用,由于每個結(jié)構(gòu)體數(shù)組元素都是一個結(jié)構(gòu)體變量,因此,結(jié)構(gòu)體數(shù)組元素的引用方式與結(jié)構(gòu)體變量類似,其語法格式如下所示:數(shù)組元素名稱.成員名; 例如,要引用9.2.2小節(jié)中結(jié)構(gòu)體數(shù)組student第一個元素的num成員,可以采用下列方式:student0.num;為了幫助讀者更好地掌握結(jié)構(gòu)體數(shù)組的引用,接下來通過一個案例來輸出結(jié)構(gòu)體數(shù)組中的所有成員,如例9-5所示。例9-5 1 #include <stdio.h> 2 #include <s

24、tdlib.h> 3 struct Student 4 5 char name50; 6 int studentID; 7 ; 8 void main() 9 10 struct Student s2 = "Zhang San", 20140000, "Li Si", 20140001; 11 for (int i = 0; i < 2; i+) 12 13 printf("%s %dn", , si.studentID); 14 15 運行結(jié)果如圖9-9所示。圖9-9 運行結(jié)果在例9-5中,首先定義了一個長

25、度為2的結(jié)構(gòu)體數(shù)組s,并對數(shù)組中的元素進(jìn)行了初始化。然后使用for循環(huán),依次輸出了s0和s1中的成員值。9.3 結(jié)構(gòu)體指針變量在第6章學(xué)習(xí)指針時,指針指向的都是基本數(shù)據(jù)類型。其實,指針還可以指向結(jié)構(gòu)體,被稱為結(jié)構(gòu)體指針變量,它的用法與一般指針沒有太大差異,本節(jié)將圍繞結(jié)構(gòu)體指針變量進(jìn)行詳細(xì)講解。9.3.1 結(jié)構(gòu)體指針變量在使用結(jié)構(gòu)體指針變量之前,首先需要定義結(jié)構(gòu)體指針,結(jié)構(gòu)體指針的定義方式與一般指針類似,例如,下列語句定義了一個Student類型的指針。struct Student s = "Zhang San", 20140100, 'M', 93.5;st

26、ruct Student *p = &s;在上述代碼中,定義了一個結(jié)構(gòu)體指針p,并通過“&”將結(jié)構(gòu)體變量s的地址賦值給p,因此,p就是指向結(jié)構(gòu)體變量s的指針。當(dāng)程序中定義了一個指向結(jié)構(gòu)體變量的指針后,就可以通過“指針名à成員變量名”的方式來訪問結(jié)構(gòu)體變量中的成員,接下來通過一個案例來演示結(jié)構(gòu)體指針的用法,如例9-6所示。例9-6 1 #include <stdio.h> 2 #include <stdlib.h> 3 struct Student 4 5 char name50; 6 int studentID; 7 ; 8 void main

27、() 9 10 struct Student s = "Zhang San", 20140000; 11 struct Student *p = &s; 12 printf("%s %dn", p->name, p->studentID); 13 運行結(jié)果如圖9-10所示。圖9-10 運行結(jié)果在例9-6中,首先定義了一個結(jié)構(gòu)體類型變量s,并將變量s中的成員name初始化為Zhang San,studentID 初始化為20140000。然后,定義了一個結(jié)構(gòu)體指針p,并將p指向s的地址,最后,通過p->name訪問成員name和s

28、tudentID的值。從圖9-10中可以看出,使用結(jié)構(gòu)體指針同樣可以訪問結(jié)構(gòu)體變量中的成員。9.3.2 結(jié)構(gòu)體數(shù)組指針指針可以指向結(jié)構(gòu)體數(shù)組,即將結(jié)構(gòu)體數(shù)組的起始地址賦給指針變量,這種指針就是結(jié)構(gòu)體數(shù)組指針,例如,下面語句定義了Student結(jié)構(gòu)體的一個數(shù)組和該數(shù)組的指針。struct Student stu110,*p=&stu1;在上述代碼中,p是一個Student結(jié)構(gòu)體數(shù)組指針,從定義上看,它和結(jié)構(gòu)體指針沒什么區(qū)別,只不過指向的是結(jié)構(gòu)體數(shù)組。為了幫助讀者更好地掌握結(jié)構(gòu)體數(shù)組指針的用法,接下來通過一個案例來演示如何使用結(jié)構(gòu)體數(shù)組指針輸出多個學(xué)生的信息,如例9-7所示。例9-7 1

29、#include <stdio.h> 2 #include <stdlib.h> 3 struct student 4 5 int num; 6 char name20; 7 char sex; 8 int age; 9 stu3= 10 201401001,"Wang Ming",'M',19, 11 201401002,"Zhang Ning",'W',23, 12 201401003,"Wang Ming",'M',19; 13 void main() 14

30、 15 struct student *p; 16 printf("numttnamettsextagen "); 17 for(p=stu;p<stu+3;p+) 18 19 printf("%ldt%-12st%-2ct%4dn",p->num,p->name,p->sex,p->age); 20 21 運行結(jié)果如圖9-11所示。圖9-11 運行結(jié)果在例9-7中,第312行代碼用于初始化結(jié)構(gòu)體數(shù)組stu,在第17行代碼中,“p=stu”用于將p指向結(jié)構(gòu)體數(shù)組stu的第一個元素,“p+”用于將指針指向下一個元素。第19行代

31、碼,通過“->”用于獲取某個成員的值。從圖9-11中可以看出,程序輸出了結(jié)構(gòu)體數(shù)組stu中所有元素的成員值。9.4 結(jié)構(gòu)體類型數(shù)據(jù)在函數(shù)間的傳遞在函數(shù)間不僅可以傳遞簡單的變量、數(shù)組、指針等類型的數(shù)據(jù),還可以傳遞結(jié)構(gòu)體類型的數(shù)據(jù)。本節(jié)將針對結(jié)構(gòu)體類型數(shù)據(jù)在函數(shù)間的傳遞進(jìn)行詳細(xì)講解。9.4.1 結(jié)構(gòu)體變量作為函數(shù)參數(shù)結(jié)構(gòu)體變量作為函數(shù)參數(shù)的用法與普通變量類似,都需要保證調(diào)用函數(shù)的實參類型和被調(diào)用函數(shù)的形參類型相同。結(jié)構(gòu)體變量作函數(shù)參數(shù)時,也是值傳遞,被調(diào)函數(shù)中改變結(jié)構(gòu)體成員變量的值,主調(diào)函數(shù)中不受影響。如例9-8所示例9-8 1 #include <stdio.h> 2 stru

32、ct Student 3 4 char name50; 5 int studentID; 6 ; 7 void change(struct Student stu) 8 9 strcpy(stu->name, "lisi"); 10 stu.studentID = 2; 11 12 void main() 13 14 struct Student student = "Zhang San", 1 ; 15 change(student); 16 printf("name = %s studentID = %dn", studen

33、, student.studentID); 17 運行結(jié)果如圖9-12所示。圖9-12 運行結(jié)果在例9-8中,定義了一個用于改變數(shù)據(jù)的change()函數(shù),該函數(shù)需要接收一個結(jié)構(gòu)體類型的參數(shù)。從代碼第15行可以看出,當(dāng)將結(jié)構(gòu)體變量作為參數(shù)傳遞給函數(shù)時,其傳參的方式與普通變量相同。在主調(diào)函數(shù)中調(diào)用change()函數(shù)后,主函數(shù)中結(jié)構(gòu)體中成員的值并沒有改變。9.4.2 結(jié)構(gòu)體數(shù)組作為函數(shù)參數(shù)函數(shù)間不僅可以傳遞一般的結(jié)構(gòu)體變量,還可以傳遞結(jié)構(gòu)體數(shù)組。接下來通過一個案例來演示如何使用結(jié)構(gòu)體數(shù)組作為函數(shù)參數(shù)傳遞數(shù)據(jù),如例9-9所示。例9-9 1 #include <stdio.h>

34、; 2 struct Student 3 4 char name50; 5 int studentID; 6 ; 7 void printInfo(struct Student stu,int length) 8 9 for (int i = 0; i < length; i+) 10 11 printf("name: %sn", ); 12 printf("id: %inn", stui.studentID); 13 14 15 void main() 16 17 struct Student students3 = "

35、;Zhang San", 1 , 18 "Li Si",2, 19 "Wang Wu", 3 ; 20 printInfo(students, 3); 21 運行結(jié)果如圖9-13所示。圖9-13 運行結(jié)果在例9-9中,由于無法通過數(shù)組直接獲取到其長度,因此,在定義的printfInfo()函數(shù)中,需要傳遞兩個參數(shù),其中一個是結(jié)構(gòu)體數(shù)組,另一個是數(shù)組的長度。printfInfo()函數(shù)接收到傳遞來的數(shù)組名和長度后,使用for循環(huán),將結(jié)構(gòu)體數(shù)組中的所有成員輸出。9.4.3 結(jié)構(gòu)體指針作為函數(shù)參數(shù)結(jié)構(gòu)體指針變量用于存放結(jié)構(gòu)體變量的首地址,所以將指針作

36、為函數(shù)參數(shù)傳遞時,其實就是傳遞結(jié)構(gòu)體變量的首地址,在被調(diào)函數(shù)中改變結(jié)構(gòu)體成員的值,那么主調(diào)函數(shù)中結(jié)構(gòu)體成員的值也會被改變。如例9-10所示。例9-10 1 #include <stdio.h> 2 struct Student 3 4 char name50; 5 int studentID; 6 ; 7 void change(struct Student* stu) 8 9 strcpy(stu->name, "lisi"); 10 stu->studentID = 2; 11 12 void main() 13 14 struct Studen

37、t student = "Zhang San", 1 ; 15 change(&student); 16 printf("name = %s studentID = %dn", , student.studentID); 17 運行結(jié)果如圖9-14所示。圖9-14 運行結(jié)果在例9-10中,定義了一個改變數(shù)據(jù)的change()函數(shù),該函數(shù)需要接收一個結(jié)構(gòu)體指針類型的參數(shù),由于結(jié)構(gòu)體指針作為函數(shù)參數(shù)時,需要傳遞的是結(jié)構(gòu)體變量的首地址,因此,在代碼第15行中,通過“&”運算符獲取結(jié)構(gòu)體變量student的首地址,然后將其

38、作為參數(shù)傳遞給change()函數(shù)。在change()函數(shù)中改變結(jié)構(gòu)體變量成員的值,則main()函數(shù)中的結(jié)構(gòu)體成員值也隨著改變了。9.5 union共用體共用體又叫聯(lián)合體,是一種特殊的數(shù)據(jù)類型,它允許多個成員使用同一塊內(nèi)存。靈活地使用共用體可以減少程序所使用的內(nèi)存。本節(jié)將針對共用體進(jìn)行詳細(xì)地講解。9.5.1 共用體數(shù)據(jù)類型的定義在C語言中,共用體類型同結(jié)構(gòu)體類型一樣,都屬于構(gòu)造類型,它在定義上與結(jié)構(gòu)體類型十分相似,定義共用體類型的語法格式如下所示:union 共用體類型名稱 數(shù)據(jù)類型 成員名1; 數(shù)據(jù)類型 成員名2; 數(shù)據(jù)類型 成員名n;在上述語法格式中,“union”是定義共用體類型的關(guān)鍵

39、字,其后是所定義 “共用體類型名稱”,在“共用體類型名稱”下的大括號中,定義了共用體類型的成員項,每個成員是由“數(shù)據(jù)類型”和“成員名”共同組成的。例如下面這段代碼:union data int m; float x; char c; ;上述代碼定義了一個名為data的共用體類型,該類型由三個不同類型的成員組成,這些成員共享同一塊存儲空間。9.5.2 共用體變量的定義共用體變量的定義和結(jié)構(gòu)體變量的定義類似,假如要定義兩個data類型的共用體變量a和b,則可以采用下列三種方式。1、先定義共用體類型,再定義共用體變量,具體示例如下:union data int m; float x; char c;

40、union data a,b;2、在定義共用體類型的同時定義共用體變量,具體示例如下:union data int m; float x; char c;a,b;3、直接定義共用體類型變量,具體示例如下:union int m; Double x; char c;a,b; 上述三種方式都用于定義共用體變量a和b, 和結(jié)構(gòu)體變量的定義相同。&多學(xué)一招:共用體內(nèi)存分配共用體的內(nèi)存分配必須要符合兩項準(zhǔn)則,具體如下:1、 共用體的內(nèi)存必須大于或等于其成員變量中大數(shù)據(jù)類型(包括基本數(shù)據(jù)類型和數(shù)組)的大小2、共用體的內(nèi)存必須是最寬基本數(shù)據(jù)類型的整數(shù)倍,如果不是,則填充字節(jié)。接下來通過兩個共用體的內(nèi)

41、存分析來解釋上述準(zhǔn)則。(1)成員變量都是基本數(shù)據(jù)類型的共用體,具體如下union int m; float x; char c;a;共用體a的內(nèi)存大小如圖9-15所示。圖9-15 共用體a的內(nèi)存大小共用體a的內(nèi)存大小是最大數(shù)據(jù)類型所占的字節(jié)數(shù),即int和float的大小,所以共用體a的內(nèi)存大小為4字節(jié)。(2)成員變量包含數(shù)組類型的共用體,具體如下union int m; float x; char c; char name5;b;共用體b的內(nèi)存大小如圖9-16所示。圖9-16 共用體b的內(nèi)存大小共用體b的內(nèi)存大小是按最大數(shù)據(jù)類型char name5來分配, char name5占5個字節(jié)。共用

42、體b的內(nèi)存大小還必須是最寬基本數(shù)據(jù)類型的整數(shù)倍,所以填充3個字節(jié),共8個字節(jié)。關(guān)于共用體變量的內(nèi)存大小,讀者可以通過sizeof()來驗證。9.5.3 共用體變量的初始化和引用在共用體變量定義的同時,只能對其中一個成員的類型值進(jìn)行初始化,這與它的內(nèi)存分配也是相應(yīng)的。共用體變量初始化的方式如下所示:union 共用體類型名 共用體變量=其中一個成員的類型值從上述語法格式可以看出,盡管只能給其中一個成員賦值,但必須用大括號括起來。例如,下列語句用于對data類型的共用體變量a進(jìn)行初始化。union data a=8; 完成了共用體變量的初始化后,就可以引用共用體中的成員了,共用體變量的引用方式與結(jié)

43、構(gòu)體類似,例如,下列代碼定義了一個共用體變量a和一個共用體指針p。union data int m; float x; char c;union data a, *p=&a;如果要引用共用體變量中的m成員,則可以使用下列方式:a.m; / 引用共用體變量a中的成員m p->m / 引用共用體指針變量p所指向的變量成員m需要注意的是,雖然共用體變量的引用方式與結(jié)構(gòu)體類似,但兩者是有區(qū)別的,其主要區(qū)別是,在程序執(zhí)行的任何特定時刻,結(jié)構(gòu)體變量中的所有成員是同時駐留在該結(jié)構(gòu)體變量所占用的內(nèi)存空間中,而共用體變量僅有一個成員駐留在共用體變量所占用的內(nèi)存空間中。接下來通過一個案例來驗證,如例

44、9-11所示。例9-11 1 #include <stdio.h> 2 union Data 3 4 int i; 5 char j; 6 ; 7 void main() 8 9 union Data d;/定義了一個union 10 d.i = 15; 11 printf("d.i = %dn", d.i); 12 printf("d.j = %dn", d.j); 13 printf("d = %dn", d); 14 15 d.j = 'a' 16 printf("d.i = %dn&quo

45、t;, d.i); 17 printf("d.j = %dn", d.j); 18 printf("d = %dn", d); 19 20 printf("d.i的地址%pn", &d.i); 21 printf("d.j的地址%pn", &d.j); 22 printf("d的地址%pn", &d); 23 運行結(jié)果如圖9-17所示。圖9-17 運行結(jié)果在例9-11中,定義了一個Data類型的共用體變量d,其中包含了兩個int類型的變量i和char類型的變量j,當(dāng)將i賦

46、值為15時,則此時結(jié)構(gòu)體d中只有一個值15,取i的值、j的值和結(jié)構(gòu)體變量d的值,其實都是取對應(yīng)內(nèi)存中的同一個值。當(dāng)將j的值為字符a時,則此時d對應(yīng)的內(nèi)存中只有字符a,取i,j,d的值都是97。最后打印d、i、j的地址,三者的地址是相同的,更進(jìn)一步說明共用體變量在任何時該都只有一個成員值在內(nèi)存中。9.6 Typedef給數(shù)據(jù)類型取別名在前面章節(jié)中,講解了C語言提供的各種數(shù)據(jù)類型和用戶自己聲明的結(jié)構(gòu)體、共用體、指針類型等。除了這些數(shù)據(jù)類型,C語言還允許用戶使用typedef關(guān)鍵字為現(xiàn)有數(shù)據(jù)類型取別名。使用typedef關(guān)鍵字可以方便程序的移植,減少對硬件的依賴性。接下來將針對typedef關(guān)鍵字進(jìn)

47、行詳細(xì)地講解。使用typedef關(guān)鍵字語法格式如下:typedef 數(shù)據(jù)類型 別名;在上述語法格式中,數(shù)據(jù)類型包括基本數(shù)據(jù)類型、構(gòu)造數(shù)據(jù)類型、指針等,接下來針對這幾項進(jìn)行詳細(xì)講解。1、為基本類型取別名使用typedef關(guān)鍵字為int類型取別名,示例代碼如下:typedef int ZX;ZX i,j,k;上面的語句將int數(shù)據(jù)類型定義成ZX,則在程序中可以用ZX定義整型變量。2、為數(shù)組類型取別名使用typedef關(guān)鍵字為數(shù)組取別名,示例代碼如下:typedef char NAME10;NAME class1,class2;上面的語句定義了一個可含有10個字符的字符數(shù)組名NAME,并用NAME定

48、義了兩個字符數(shù)組class1和class2,等效于char class110和char class210。3、為結(jié)構(gòu)體取別名使用typedef關(guān)鍵字為結(jié)構(gòu)體類型Student取別名,示例代碼如下:typedef struct Student int num; char name10; char sex;STU;STU stu1; 上面的語句定義了一個Student類型的結(jié)構(gòu)體STU,STU stu1;語句等效于struct Student stu1;語句。需要注意的是,使用typedef關(guān)鍵字只是對已存在的類型取別名,而不是定義了新的類型。有時也可以用宏定義來代替typedef的功能,但是宏定

49、義是由預(yù)處理完成的,而typedef是在編譯時完成的,使用typedef更加靈活。9.7 進(jìn)階案例求學(xué)生平均成績學(xué)習(xí)完了結(jié)構(gòu)體與共用體的相關(guān)知識,接下來通過一個計算平均成績的案例來加深對結(jié)構(gòu)體的理解,具體需求如下:l 一個小組中有3個學(xué)生,每個學(xué)生修4門課程(三個學(xué)生修的課程相同)l 在程序中輸入這3個同學(xué)的4門課程成績,程序能自動計算出這4門課程的小組平均成績接下來用代碼來實現(xiàn)上述功能,如例9-12所示。例9-12 1 #define _CRT_SECURE_NO_WARNINGS 2 #include<stdio.h> 3 #include<stdlib.h> 4

50、5 typedef struct stu 6 char name20; /學(xué)生姓名 7 float score4; /4門課成績 8 STU; 9 10 void main() 11 12 int i, j; 13 float sum = 0, avg; 14 STU stu3; /定義一個結(jié)構(gòu)體數(shù)組,數(shù)組中有3個元素 15 16 /從鍵盤輸入學(xué)生姓名及成績 17 for (i = 0; i < 3; i+) 18 19 printf("請輸入第%d個學(xué)生的姓名及四門課成績:n", i + 1); 20 scanf("%s", ); 21 for (j = 0; j < 4; j+) 22 scanf("%f", &stui.scorej); 23 24 25 /將3個學(xué)生的每科成績相加,然后求平均成績 26 for (j = 0; j < 4; j+) 27 28 for (i = 0; i < 3;

溫馨提示

  • 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

提交評論