版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第7章復(fù)合的數(shù)據(jù)類型7.1結(jié)構(gòu)概念的引入 7.2結(jié)構(gòu)體的描述與存儲7.3結(jié)構(gòu)的使用7.4結(jié)構(gòu)體與函數(shù)的關(guān)系7.5共用體7.6枚舉7.7typedef聲明新的類型名7.8本章小結(jié)
【主要內(nèi)容】
給出結(jié)構(gòu)體類型變量的定義、使用規(guī)則及方法實例;
通過結(jié)構(gòu)體與數(shù)組的對比,說明其表現(xiàn)形式與本質(zhì)含義;
通過結(jié)構(gòu)體類型與基本類型的對比,說明其表現(xiàn)形式與本質(zhì)含義;
通過結(jié)構(gòu)成員與普通變量的對比,給出其使用的規(guī)則;
讀程序的訓(xùn)練;
自頂向下算法設(shè)計的訓(xùn)練;
結(jié)構(gòu)的空間存儲特點及調(diào)試要點。
【學(xué)習(xí)目標(biāo)】
理解自定義數(shù)據(jù)類型結(jié)構(gòu)體的意義;
掌握結(jié)構(gòu)體的類型定義、變量定義、初始化、引用的步驟和方法;
掌握結(jié)構(gòu)體與數(shù)組、指針、函數(shù)的關(guān)系;
了解聯(lián)合的概念及其使用;
了解枚舉的概念及其使用。
【引例1】先來回顧一下在第5章“函數(shù)”中舉過的例5-7。
程序?qū)崿F(xiàn):
1 /*一維數(shù)組中求m到n項的和*/
2 #include<stdio.h>
3 intfunc(intb[],intm,intn)
7.1結(jié)構(gòu)概念的引入
4 {
5 inti,sum=0;
6 for(i=m;i<=n;i++)
7 {
8 sum=sum+b[i];/*累加下標(biāo)為m到n的元素*/
9 }
10 returnsum;
11 }
12
13 intmain()
14 {
15 intx,a[]={1,2,3,4,5,6,7,8,9,0};
16 intp=3,q=7;/*下標(biāo)范圍*/
17 x=func(a,p,q);
18 printf("%d\n",x);
19 return0;
20 }我們把上述題目主函數(shù)中的a數(shù)組由一維改為二維,子函數(shù)除了原先的功能外,再添加一個,把累加的結(jié)果放在每行的最后一個元素位置上,見圖7.1。
圖7.1a數(shù)組的信息
1 /*二維數(shù)組求每行m到n項的和*/
2 #include<stdio.h>
3 voidfunc(intb[],intm,intn,intlast);
4
5 voidfunc(intb[],intm,intn,intlast)
6 {
7 inti,sum=0;
8 for(i=m;i<=n;i++)
9 {
10 sum=sum+b[i]; /*累加下標(biāo)為m到n的元素*/
11 }
12 b[last]=sum; /*把累加和放在指定位置*/
13 }
14
15 intmain()
16 {/*a數(shù)組由一維變?yōu)槎S*/
17 inta[][10]={ {1,2,3,4,5,6,7,8,9,0},
18 {2,3,4,5,6,7,8,9,10,0},
19 {3,4,5,6,7,8,9,10,11,0}
20
};
21 intp=3,q=8,last=9;
22 /*a數(shù)組有3行信息,則調(diào)用3次func函數(shù)即可*/
23 for(inti=0;i<3;i++)
24 {
25 func(a[i],p,q,last);
26 }
27
28 for(i=0;i<3;i++) /*輸出a數(shù)組內(nèi)容*/
29 {
30 for(intj=0;j<10;j++)
31 {
32 printf("%4d",a[i][j]);
33 }
34 printf("\n");
35 }
36 return0;
37 }
程序結(jié)果:
12345678939
234567891045
3456789101151
【引例2】把引例1的二維數(shù)組的內(nèi)容擴展成有實際意義的表格,如表7.1所示,求出每個學(xué)生的總分,并填在此表中。
表7.1學(xué)
生
信
息
表與二維數(shù)組相比,這個表格中的數(shù)據(jù)項并不都是同一種類型,要對這樣的表格進行處理,根據(jù)計算機解題的通用規(guī)則,首要的問題是如何把這樣的表格存儲到機器中。計算機解題的通用規(guī)則為:用合適的數(shù)據(jù)結(jié)構(gòu)存儲數(shù)據(jù);用相應(yīng)的算法處理數(shù)據(jù)。
(1)如何將表7.1所示的數(shù)據(jù)表格存儲到機器中?
答:根據(jù)已有數(shù)組存儲的概念,可以把表格中的每列信息都構(gòu)造成一個一維數(shù)組,但這樣做,顯然程序處理起來是非常麻煩的,首先就是主函數(shù)不能方便地把一行信息傳遞給子函數(shù)。借助二維數(shù)組的處理方式,我們希望一次就能傳遞表格的一行信息。
(2)如何把不同類型的一行數(shù)據(jù)組合在一起?
答:表格中的數(shù)據(jù)有多行,只要把一行的信息如何組合存儲的方式分析清楚即可,因為多行信息只是一行的多次重復(fù)。因此,現(xiàn)在解決問題的關(guān)鍵變成,如何把相關(guān)的一組不同類型的數(shù)據(jù)“打包”放在一個連續(xù)的空間,傳遞時只要傳遞這個空間的起始地址即可。
系統(tǒng)要給用戶的“打包”數(shù)據(jù)分配空間,首先就得定義它的存儲尺寸,即數(shù)據(jù)的類型。然而數(shù)據(jù)表中的內(nèi)容是用戶根據(jù)需要確定的,系統(tǒng)無法預(yù)先得知,這就需要用戶自己“構(gòu)造”出數(shù)據(jù)表的類型,然后才能進行存儲空間的分配。
根據(jù)上述結(jié)論,可列出所有已知的條件和希望的結(jié)果:
(1)有多個數(shù)據(jù)項,每個數(shù)據(jù)項都可以用已有的數(shù)據(jù)類型描述;
(2)數(shù)據(jù)項的多少、內(nèi)容是由用戶自己確定的;
(3)希望上述各數(shù)據(jù)項“組合”在一起,有連續(xù)的存儲空間,可以作為一個整體來方便傳址;
(4)要求每個數(shù)據(jù)項可以單獨引用。
根據(jù)上面這些條件和要求以及存儲三要素,可給出這種“組合的數(shù)據(jù)”類型與變量的特征如表7.2所示。
表7.2組合數(shù)據(jù)的特點
說明:類型的名字之所以是“關(guān)鍵字+標(biāo)識符”,是要有一個特別約定的關(guān)鍵詞來表明這是一個類型,又因為這個類型是用戶自己定義的,所以類型名中應(yīng)該有用戶自己命名的成分,以和其他類似的“組合的數(shù)據(jù)”類型名區(qū)別。
這種“組合的數(shù)據(jù)”在C語言中被稱為結(jié)構(gòu)體,其特點如下:
(1)結(jié)構(gòu)體是C語言中的構(gòu)造類型,是由不同數(shù)據(jù)類型的數(shù)據(jù)組成的集合體;
(2)結(jié)構(gòu)體為處理復(fù)雜的數(shù)據(jù)結(jié)構(gòu)提供了手段;
(3)結(jié)構(gòu)體為函數(shù)間傳遞不同類型的參數(shù)提供了便利。
7.2.1結(jié)構(gòu)體的類型定義
結(jié)構(gòu)體(struct):由一系列具有相同類型或不同類型的數(shù)據(jù)構(gòu)成的數(shù)據(jù)集合,也叫結(jié)構(gòu)。
結(jié)構(gòu)體由若干不同類型的數(shù)據(jù)項組成,構(gòu)成結(jié)構(gòu)體的各個數(shù)據(jù)項稱為結(jié)構(gòu)體成員。7.2結(jié)構(gòu)體的描述與存儲結(jié)構(gòu)體類型定義描述結(jié)構(gòu)的組織形式,是一種用戶自定義的類型,同C的基本類型中類型的概念一樣,只是一個存儲尺寸,不分配內(nèi)存。
結(jié)構(gòu)體類型定義形式如下:
struct結(jié)構(gòu)體名
{數(shù)據(jù)類型1成員名1;
數(shù)據(jù)類型2成員名2;
…
數(shù)據(jù)類型n成員名n;
};說明:
(1)結(jié)構(gòu)體類型名:struct與結(jié)構(gòu)體名合起來表示結(jié)構(gòu)體類型名。struct是關(guān)鍵字,結(jié)構(gòu)體名由用戶用標(biāo)識符標(biāo)示。結(jié)構(gòu)體類型也可簡稱結(jié)構(gòu)類型。
(2)結(jié)構(gòu)體成員:結(jié)構(gòu)體中的一個數(shù)據(jù)項。結(jié)構(gòu)體成員的數(shù)據(jù)類型可以是C語言允
許的所有類型。
【例7-1】結(jié)構(gòu)體類型定義的例子。將圖7.2中的各數(shù)據(jù)項組合在一個結(jié)構(gòu)里。
圖7.2學(xué)生信息數(shù)據(jù)項程序如下:
structstudent /*struct為結(jié)構(gòu)關(guān)鍵字,student為結(jié)構(gòu)名*/
{
intStudentId; /*學(xué)號*/
charStudentName[10]; /*姓名*/
charStudentSex[3]; /*性別*/
intTimeOfEnter; /*入學(xué)時間*/
intScore_1; /*成績1*/
intScore_2; /*成績2*/
intScore_3; /*成績3*/
intScore_4; /*成績4*/
}; 7.2.2結(jié)構(gòu)體變量定義及初始化
結(jié)構(gòu)體變量定義有下面三種格式,在實際編程時可以根據(jù)需要選用。
結(jié)構(gòu)體變量定義格式1:
struct結(jié)構(gòu)類型名變量名表;
結(jié)構(gòu)體變量定義格式2:
struct結(jié)構(gòu)類型名
{類型標(biāo)識符成員名1;
類型標(biāo)識符成員名2;
…
類型標(biāo)識符成員名n;
}變量名表;結(jié)構(gòu)體變量定義格式3:
struct
{類型標(biāo)識符成員名1;
類型標(biāo)識符成員名2;
…
類型標(biāo)識符成員名n;
}變量名表;說明:第三種格式用無名結(jié)構(gòu)體直接定義變量只能用一次,無法在后續(xù)程序中再使用這個結(jié)構(gòu)類型。
【例7-2】結(jié)構(gòu)變量定義的例子。結(jié)構(gòu)變量定義語句如下:
structstudentcom[30],*sPtr,x;
結(jié)構(gòu)類型structstudent是在例7-1中已經(jīng)定義的。
定義語句各項的含義見表7.3。
表7.3結(jié)
構(gòu)
相
關(guān)
量
結(jié)構(gòu)變量初始化格式如下:
struct結(jié)構(gòu)類型名變量名={初始數(shù)據(jù)}
【例7-3】結(jié)構(gòu)變量初始化的例子。結(jié)構(gòu)類型structstudent是在例7-1中已經(jīng)定義的。
structstudentcom[30]
={{1,"趙壹","男",1999,90,83,72,82},
{2,"錢貳","男",1999,78,92,88,78},
{3,"孫叁","女",1999,89,72,98,66},
{4,"李肆","女",1999,78,95,87,90}
};/*結(jié)構(gòu)數(shù)組的初始化*/
structstudent*sPtr;/*定義結(jié)構(gòu)指針*/
sPtr=com;/*結(jié)構(gòu)指針指向結(jié)構(gòu)數(shù)組*/7.2.3結(jié)構(gòu)體成員引用方法
結(jié)構(gòu)體成員引用有三種方法:
方法一:結(jié)構(gòu)體變量名.成員名;
方法二:結(jié)構(gòu)指針名→成員名;
方法三:(*結(jié)構(gòu)指針名).成員名。
【例7-4】結(jié)構(gòu)體成員引用方法。結(jié)構(gòu)類型定義如下:
structstudent
{
intStudentId;
charStudentName[10];
charStudentSex[3];
intTimeOfEnter;
intScore[4];
inttotal;
}
用structstudent結(jié)構(gòu)類型定義的結(jié)構(gòu)變量、結(jié)構(gòu)成員的引用見表7.4。
表7.4結(jié)構(gòu)成員引用方法7.2.4結(jié)構(gòu)變量的空間分配及查看方法
【例7-5】結(jié)構(gòu)變量、結(jié)構(gòu)指針和結(jié)構(gòu)數(shù)組的查看。
1 #include<stdio.h>
2 intmain()
3 {
4 structstudent
5 {
6 intStudentId;
7 charStudentName[10];
8 charStudentSex[3];
9 intTimeOfEnter;
10 intScore[4];
11 inttotal;
12 };
13
14 structstudentx;
15 structstudentcom[10]
16 ={{1,"趙壹","男",1999,90,83,72,82},
17 {2,"錢貳","男",1999,78,92,88,78},
18 {3,"孫叁","女",1999,89,72,98,66},
19 {4,"李肆","女",1999,78,95,87,90}
20 };
21 structstudent*sPtr;
22
23 sPtr=com;
24 x=com[0];
25 return0;
26 }
【解】(1)結(jié)構(gòu)變量定義:
structstudentx;(程序第14行)
對于變量x,系統(tǒng)將會以什么樣的方式給它分配空間呢?C規(guī)定按結(jié)構(gòu)類型中成員的前后順序及大小來給結(jié)構(gòu)變量分配空間。結(jié)構(gòu)變量X的成員如圖7.3所示。
圖7.3結(jié)構(gòu)變量x的成員結(jié)構(gòu)變量x的空間分配在程序第24行未執(zhí)行前的情形參見圖7.4~圖7.7。圖7.5是點開圖7.4中StudentName前的“+”號,顯示x的成員——數(shù)組Student-Name的元素。
圖7.4結(jié)構(gòu)變量x的空間分配(總)
圖7.5結(jié)構(gòu)變量x的空間分配(1)
圖7.6結(jié)構(gòu)變量x的空間分配(2)
圖7.7結(jié)構(gòu)變量x的空間分配(3)
(2)結(jié)構(gòu)數(shù)組定義:
structstudentcom[10];(程序第15行至第20行)
指針賦值:
sPtr=com;(程序第23行)
sPtr執(zhí)向com的位置及sPtr偏移9后指向的位置見圖7.8。
圖7.8結(jié)構(gòu)數(shù)組com的空間示意圖
圖7.9結(jié)構(gòu)數(shù)組com的空間分配
圖7.10結(jié)構(gòu)指針sPtr的指向
圖7.11結(jié)構(gòu)指針sPtr+3的指向
圖7.12x=com[0]賦值后的情形
內(nèi)存地址對齊(alignment)
為了提高CPU訪問內(nèi)存的效率,程序語言的編譯器在做變量的存儲分配時就進行了分配優(yōu)化處理,對于基本類型的變量,其優(yōu)化規(guī)則(也稱為“對齊”規(guī)則)如下:
變量地址%N=0
其中對齊參數(shù)N=sizeof(變量類型)。
注:不同的編譯器,具體的處理規(guī)則可能不一樣。
結(jié)構(gòu)體空間分配規(guī)則(VC++6.0環(huán)境)
1)結(jié)構(gòu)成員存放順序
結(jié)構(gòu)體的成員在內(nèi)存中順序存放,所占內(nèi)存地址依次增高,第一個成員處于低地址處,最后一個成員處于最高地址處。
2)結(jié)構(gòu)對齊參數(shù)
(1)結(jié)構(gòu)體一個成員的對齊參數(shù):
N=min(sizeof(該成員類型),n)
注:n為VC++6.0中可設(shè)置的值,默認為8字節(jié)。
(2)結(jié)構(gòu)體的對齊參數(shù)M:M=結(jié)構(gòu)體中所有成員的對齊參數(shù)中的最大值。
3)結(jié)構(gòu)體空間分配規(guī)則
(1)結(jié)構(gòu)體長度L:滿足條件L%M=0(不夠要補足空字節(jié))。
(2)每個成員地址x:滿足條件x%N=0(空間剩余,由下一個成員做空間補充)。結(jié)構(gòu)內(nèi)的成員空間分配以M為單位開辟空間單元;若成員大小超過M,則再開辟一個M單元;若此單元空間剩余,則由下一個成員按對齊規(guī)則做空間補充(結(jié)構(gòu)體嵌套也是一樣的規(guī)則)。
【例7-6】結(jié)構(gòu)存儲空間及內(nèi)存對齊的查看例子1。結(jié)構(gòu)體成員是基本數(shù)據(jù)類型時的內(nèi)存對齊。
struct
{
short
a1;
short
a2;
short
a3;
}A={1,2,3};
struct
{
long
a1;
short
a2;
}B={4,5};
struct
{
shorta1;
longa2;
}C={6,7};
sizeof(A)=6,sizeof(B)=8,sizeof(C)=8,為什么是這樣?
注:sizeof(short)=2,sizeof(long)=4。
圖7.13為例7-6的查看步驟1,結(jié)構(gòu)體A的對齊參數(shù)M=sizeof(short)=2(byte)。
圖7.13例7-6查看步驟1
圖7.14例7-6查看步驟2
圖7.15例7-6查看步驟3
【例7-7】結(jié)構(gòu)存儲空間及內(nèi)存對齊的查看例子2。結(jié)構(gòu)體成員是構(gòu)造數(shù)據(jù)類型時的內(nèi)存對齊。設(shè)
structstudentx={1,"趙壹","男",3,4,5,6,7};
圖7.16中,Memory窗口的地址是結(jié)構(gòu)變量x的起始地址。
圖7.16例7-7查看步驟
x的存儲空間長度=0x12ff7c-0x12ff58+4=0x28=40(byte)
x成員定義長度和=(int+char*10+char*3+int+int*4)=37(byte)
二者相差3
byte,即存在如圖7.17所示的內(nèi)存“空洞”,這是如何產(chǎn)生的呢?
結(jié)構(gòu)體x的對齊參數(shù)M=sizeof(int)=4
注意:
(1)0x12FF64、0x12FF65兩個單元放的是StudentName[8]和StudentName[9]。
圖7.17內(nèi)存“空洞”
(2)StudentSex的起始地址是0x12FF66。因為StudentSex的對齊參數(shù)N=min(sizeof(該成員類型),8)=sizeof(char)=1,0x12FF66%N=0,所以StudentSex的三個元素從0x0x12FF66開始存儲。
(3)TimeOfEnter的起始地址是0x12FF6C。因為TimeOfEnter的對齊參數(shù)
N=sizeof(int)=4,StudentSex存儲后的起始地址是0x12FF69,0x12FF69至0x12FF6B都不是4的整數(shù)倍
(如圖7.18所示),而0x12FF6C是4的整數(shù)倍,所以TimeOfEnter的起始地址是0x12FF6C。因此,StudentSex后的3
byte內(nèi)存“空洞”是由于TimeOfEnter的“對齊”產(chǎn)生的。圖7.18地址模4運算
【例7-8】結(jié)構(gòu)與數(shù)組類比的例子。請寫出一個程序,找出表7.5中的最高成績,顯示此組信息,并將之與表中的第一列信息交換。7.3結(jié)?構(gòu)?的?使?用
表7.5數(shù)據(jù)表
表格中的數(shù)據(jù)如何存儲?
答:根據(jù)計算機解題的通用規(guī)則,我們首先要解決的問題是如何把表格中的數(shù)據(jù)按什么形式存儲到機器中,然后才能在相應(yīng)的存儲結(jié)構(gòu)中進行算法處理。
數(shù)據(jù)結(jié)構(gòu)設(shè)計可采用以下三種方式:
(1)用一維數(shù)組。
成績數(shù)組:intscore[6]={90,80,65,95,75,97};
座位數(shù)組:intset[6]={1,2,3,4,5,6};
(2)用二維數(shù)組。成績與座位的組合:
intscore[2][6]={{90,80,65,95,75,97},{1,2,3,4,5,6}};
用一維或二維數(shù)組的方式存儲數(shù)據(jù)的規(guī)則我們已經(jīng)熟悉了,即把同類型的數(shù)據(jù)按序存放,元素用數(shù)組名配合下標(biāo)引用。
(3)用結(jié)構(gòu)。
方式1:
structnode{
intscore[6];
intset[6];}
structnodex={{90,80,65,95,75,97},{1,2,3,4,5,6}}
方式2:
structnode{
intscore;
intset;}
structnodey[6]={{90,1},{80,2},{65,3},{95,4},{75,5},{97,6}};用結(jié)構(gòu)的方式存儲的思路是,把相關(guān)的一組數(shù)據(jù)“打包”放在一起。結(jié)構(gòu)的類型是用戶自己定義的,結(jié)構(gòu)的空間是在定義結(jié)構(gòu)類型變量時分配的。
按照結(jié)構(gòu)的形式,把數(shù)據(jù)存儲到內(nèi)存后,要對它們進行處理,就引出了數(shù)據(jù)如何引用的問題。表7.6給出了一維數(shù)組、二維數(shù)組、結(jié)構(gòu)三種數(shù)據(jù)的組織形式以及其中數(shù)據(jù)項的引用形式。
表7.6數(shù)據(jù)存儲及引用
表7.7x與y的存儲
表7.8例7-8偽代碼
【方法1】
1 /*例7-8用一維數(shù)組實現(xiàn)*/
2 #include<stdio.h>
3 #defineMAX6
4
5 intmain()
6 {
7 intscore[MAX]={90,80,65,95,75,97};
8 intset[MAX]={1,2,3,4,5,6};
9 intmax,num;
10 inttemp1,temp2;
11
12 /*在score中找最大值,并將之記錄在max中,對應(yīng)下標(biāo)值記錄在num中*/
13 max=score[0];/*取第一組值做比較基準(zhǔn)*/
14 num=1;
15 for(inti=1;i<MAX;i++)
16 {
17 if(max<score[i])
18 {
19 max=score[i];
20 num=set[i];
21 }
22 }
23
24 /*最大值與第一個值交換*/
25 temp1=score[0];
26 temp2=set[0];
27 score[0]=max;
28 set[0]=num;
29 score[num-1]=temp1;
30 set[num-1]=temp2;
31
32 /*輸出*/
33 printf("第1名:%d號,%d分\n",set[0],score[0]);
34 return0;
35 }
程序結(jié)果:
第1名:6號,97分
【方法2】
1 /*例7-8用二維數(shù)組實現(xiàn)*/
2 #include<stdio.h>
3 #defineMAX6
4 intmain()
5 {
6 intscore[2][MAX]=
7 {{90,80,65,95,75,97},
8 {1,2,3,4,5,6}
9 };
10 intmax,num;
11 inttemp1,temp2;
12
13 /*在score中找最大值,并將之記錄在max中,對應(yīng)下標(biāo)值記錄在n中*/
14 max=score[0][0];/*取第一組值做比較基準(zhǔn)*/
15 num=1;
16 for(inti=1;i<MAX;i++)
17 {
18 if(max<score[0][i])
19 {
20 max=score[0][i];
21 num=score[1][i];
22 }
23 }
24
25 /*最大值與第一個值交換*/
26 temp1=score[0][0];
27 temp2=score[1][0];
28 score[0][0]=max;
29 score[1][0]=num;
30 score[0][num-1]=temp1;
31 score[1][num-1]=temp2;
32
33 /*輸出*/
34 printf("第1名:%d號,%d分\n",score[1][0],score[0][0]);
35 return0;
36 }
程序結(jié)果:
第1名:6號,97分
【方法3】
1 /*例7-8用結(jié)構(gòu)方式1實現(xiàn)*/
2 #include<stdio.h>
3 #defineMAX6
4 intmain()
5 {
6 structnode
7 {
8 intscore[MAX];
9 intset[MAX];
10 }x={{90,80,65,95,75,97},{1,2,3,4,5,6}};
11 intmax,num;
12 inttemp1,temp2;
13
14 /*在score中找最大值,并將之記錄在m中,對應(yīng)下標(biāo)值記錄在n中*/
15 max=x.score[0];/*取第一組值做比較基準(zhǔn)*/
16 num=1;
17 for(inti=1;i<MAX;i++)
18 {
19 if(max<x.score[i])
20 {
21 max=x.score[i];
22 num=x.set[i];
23 }
24 }
25
26 /*最大值與第一個值交換*/
27 temp1=x.score[0];
28 temp2=x.set[0];
29 x.score[0]=max;
30 x.set[0]=num;
31 x.score[num-1]=temp1;
32 x.set[num-1]=temp2;
33
34 /*輸出*/
35 printf("第1名:%d號,%d分\n",x.set[0],x.score[0]);
36 return0;
37 }
程序結(jié)果:
第1名:6號,97分
【方法4】
1 /*用結(jié)構(gòu)方式2實現(xiàn)*/
2 #include<stdio.h>
3 #defineMAX6
4 intmain()
5 {
6 structnode
7 {
8 intscore;
9 intset;
10 }y[6]={{90,1},{80,2},{65,3},{95,4},{75,5},{97,6}};
11 intmax,num;
12 inttemp1,temp2;
13
14 /*在score中找最大值,并將之記錄在m中,對應(yīng)下標(biāo)值記錄在n中*/
15 max=y[0].score;/*取第一組值做比較基準(zhǔn)*/
16 num=1;
17 for(inti=1;i<MAX;i++)
18 {
19 if(max<y[i].score)
20 {
21 max=y[i].score;
22 num=y[i].set;
23 }
24 }
25
26 /*最大值與第一個值交換*/
27 temp1=y[0].score;
28 temp2=y[0].set;
29 y[0].score=max;
30 y[0].set=num;
31 y[num-1].score=temp1;
32 y[num-1].set=temp2;
33
34 /*輸出*/
35 printf("第1名:%d號,%d分\n",y[0].set,y[0].score);
36 return0;
37 }
程序結(jié)果:
第1名:6號,97分
【例7-9】順序結(jié)構(gòu)程序的例子的改進。從鍵盤輸入四個學(xué)生的學(xué)號和英語考試成績,打印這四人的學(xué)號和成績,最后輸出四人的英語平均成績。
1 /*順序結(jié)構(gòu)程序的例子的改進*/
2 #include<stdio.h>
3 intmain()
4 {
5 structnode
6 {
7 intnumber[4];
8 floatgrade[4];
9 }stu;
10
11 floatgrade=0;
12 inti;
13 /*輸入四個學(xué)生的學(xué)號和英語考試成績*/
14 for(i=0;i<4;i++)
15 {
16 printf("inputnumber:\n");
17 scanf("%d",&stu.number[i]);
18 printf("inputgrader:\n");
19 scanf("%f",&stu.grade[i]);
20 grade=grade+stu.grade[i];
21 }
22 /*打印四人的學(xué)號和成績及平均成績*/
23 printf("numbergrade\n");
24 for(i=0;i<4;i++)
25 {
26 printf("%d:%0.1f\n",stu.number[i],stu.grade[i]);
27 }
28 printf("average=%0.1f\n",grade/4);
29 return0;
30 }
程序結(jié)果:
inputnumber:
101
inputgrader:
98
inputnumber:
102
inputgrader:
87
inputnumber:
103
inputgrader:
67
inputnumber:
104
inputgrader:
92
numbergrade
101:98.0
102:87.0
103:67.0
104:92.0
average=86.0
把數(shù)據(jù)按照結(jié)構(gòu)的形式存儲后,這個程序從形式上看,比“順序結(jié)構(gòu)程序”要簡潔。
【例7-10】結(jié)構(gòu)的例子2。請設(shè)計一個統(tǒng)計選票的程序。現(xiàn)設(shè)有三個候選人的名單,見表7.9,請分別統(tǒng)計出他們各得票的多少。由鍵盤輸入候選人的名字來模擬唱票過程,選票數(shù)為N(注:每次只能從三個候選者中選擇一人)。
表7.9選票【解】偽代碼見表7.10。
表7.10例7-10偽代碼
1 /*統(tǒng)計選票*/
2 #include<stdio.h>
3 #include<string.h>
4 #defineN50/*投票人數(shù)*/
5 structperson
6 { charname[20];/*候選人姓名*/
7 intsum;/*得票數(shù)*/
8 }
9
10 intmain()
11 {
12 structpersona[3]
13 ={"Zhang",0,"Tong",0,"Wang",0};/*選票結(jié)構(gòu)*/
14 inti,j;
15 charin_name[20];
16
17 for(i=1;i<=N;i++)/*N位投票人,處理N次*/
18 {
19 scanf("%s",in_name);/*輸入候選人名*/
20 for(j=0;j<3;j++)/*選中的候選者得票數(shù)加1*/
21 if(strcmp(in_name,a[j].name)==0)
22 {
23 a[j].sum++;
24 }
25 }
26 for(i=0;i<3;i++)/*輸出結(jié)果*/
27 {
28 printf("%s,%d\n",a[i].name,a[i].sum);
29 }
30 return0;
31 }
【例7-11】結(jié)構(gòu)的例子3——對“函數(shù)讀程練習(xí)1的例子”做一改進。
原題目:處理3個學(xué)生四門課程的成績,成績存儲在二維數(shù)組studentGrades中。
(1)求所有成績中的最低、最高成績;
(2)每個學(xué)生的平均成績;
(3)輸出結(jié)果。
intstudentGrades[STUDENTS][EXAMS]
=
{{
77,68,86,73
},
{
96,87,89,78
},
{
70,90,86,81
}
};
改進的題目:已知N個學(xué)生的學(xué)號、姓名及四門課程的成績,如表7.11所示。
(1)求所有成績中的最低、最高成績;
(2)求每個學(xué)生的總成績、平均成績;
(3)打印全班成績單。
表7.11學(xué)
生
成
績
單
【解】
(1)數(shù)據(jù)存放:選結(jié)構(gòu)存儲。
#defineN50
structstu
{
intnum;
charname[10];
floatmath;
floatphys;
floateng;
floatpro;
floattotal;
floatave;
};
structstua[N]
={ {1,"Zhao",77,68,86,73,0,0},
{2,"Qian",96,87,89,78,0,0},
{3,"Sun",70,90,86,81,0,0}
};
(2)算法描述:偽代碼見表7.12。
表7.12例7-11偽代碼
(3)程序?qū)崿F(xiàn)關(guān)鍵點分析:
inti;
floatlowGrade=100; /*初始化為可能的最高分數(shù)*/
floathighGrade=0; /*初始化為可能的最低分數(shù)*/
floattotal=0;
/*找比lowGrade低的值,記在lowGrade中*/
if(lowGrade>a[i].math)lowGrade=a[i].math;
if(lowGrade>a[i].phys)lowGrade=a[i].phys;
if(lowGrade>a[i].eng)lowGrade=a[i].eng;
if(lowGrade>a[i].pro)lowGrade=a[i].pro;
/*找比highGrade低的值,記在highGrade中*/
if(highGrade<a[i].math)highGrade=a[i].math;
if(highGrade<a[i].phys)highGrade=a[i].phys;
if(highGrade<a[i].eng)highGrade=a[i].eng;
if(highGrade<a[i].pro)highGrade=a[i].pro;
total=a[i].math+a[i].phys+a[i].eng+a[i].pro;
a[i].total=total; /*在表中填總成績*/
a[i].ave=total/4; /*在表中填平均成績*/
每項成績的引用形式都很繁瑣,最好能以一種簡潔的方式表示各項成績。如何改進?
改進方法:設(shè)置一個gradePtr指針,指向第一個成績,見圖7.19。
圖7.19對成績引用的改進
gradePtr[0]=a[0].math;
gradePtr[1]=a[0].phys;
gradePtr[2]=a[0].eng;
gradePtr[3]=a[0].pro;
因為在結(jié)構(gòu)中,成績各項的數(shù)據(jù)類型都是相同的,所以也是連續(xù)存儲的。各項成績通過指針的引用,就變得有規(guī)律了。
float*gradePtr;
gradePtr=&a[0].math;
total=0;
for(i=0;i<4;i++) /*循環(huán)結(jié)構(gòu)中一個學(xué)生的各科成績*/
{
if(gradePtr[i]<lowGrade)lowGrade=gradePtr[i];
if(gradePtr[i]>highGrade)highGrade=gradePtr[i];
total+=gradePtr[i];
}
a[0].total=total; /*在表中填總成績*/
a[0].ave=total/4; /*在表中填平均成績*/
或者
float*gradePtr;
gradePtr=&a[0].math;
total=0;
for(i=0;i<4;i++,gradePtr++)
{
if(*gradePtr<lowGrade)lowGrade=*gradePtr;
if(*gradePtr>highGrade)highGrade=*gradePtr;
total+=*gradePtr;
}
a[0].total=total;
a[0].ave=total/4;
完整的程序如下:
1 /*對結(jié)構(gòu)表中成績的統(tǒng)計*/
2 #include<stdio.h>
3 #defineN3
4 structstu
5 {intnum;
6 charname[10];
7 floatmath;
8 floatphys;
9 floateng;
10 floatpro;
11 floattotal;
12 floatave;
13 };
14
15 intmain()
16 {
17 structstua[N]
18 ={ {1,"Zhao",77,68,86,73,0,0},
19 {2,"Qian",96,87,89,78,0,0},
20 {3,"Sun",70,90,86,81,0,0}
21 };
22 float*gradePtr;
23 floatlowGrade=100; /*初始化為可能的最高分數(shù)*/
24 floathighGrade=0; /*初始化為可能的最低分數(shù)*/
25 floattotal=0; /*考試成績總和*/
26
27 for(intj=0;j<N;j++) /*循環(huán)結(jié)構(gòu)中的行*/
28 {
29 gradePtr=&a[j].math;
30 total=0;
31 for(inti=0;i<4;i++) /*循環(huán)結(jié)構(gòu)中一行的各個成績*/
32 {
33 if(gradePtr[i]<lowGrade)lowGrade=gradePtr[i];
34
if(gradePtr[i]>highGrade)highGrade=gradePtr[i];
35 total+=gradePtr[i];
36 }
37 a[j].total=total;
38 a[j].ave=total/4; /*計算平均成績*/
39 }
40 printf("\nLowestrade:%.1f\nHighestgrade:%.1f\n\n",
41 lowGrade,highGrade);
42 /*輸出成績表格*/
43 printf("numnamemath.P.totalave\n");
44 for(inti=0;i<N;i++)
45 {
46 printf("%3d%6s%6.1f%6.1f%6.1f%6.1f%6.1f%6.1f\n",
47
a[i].num,a[i].name,a[i].math,a[i].phys,a[i].eng,
48 a[i].pro,a[i].total,a[i].ave);
49 }
50 return0;
51 }/*結(jié)束main*/
程序結(jié)果:
Lowestgrade:68.0
Highestgrade:96.0
numnamemath.Phys.eng.pro.totalave
1Zhao77.068.086.073.0304.076.0
2Qian96.087.089.078.0350.087.5
3Sun70.090.086.081.0327.081.8
和普通變量一樣,結(jié)構(gòu)體變量、結(jié)構(gòu)體指針均可作為函數(shù)的參數(shù)和返回值,具體情形參見表7.13。7.4結(jié)構(gòu)體與函數(shù)的關(guān)系
表7.13函數(shù)中結(jié)構(gòu)體作參數(shù)的方式
【例7-12】結(jié)構(gòu)變量作形參的例子。
1 /*結(jié)構(gòu)變量做形參*/
2 #include<stdio.h>
3
4 structstudent
5 { intnum;
6 floatgrade;
7 };
8
9 structstudentfunc1(structstudentstu) /*形參為結(jié)構(gòu)變量*/
10 {
11 stu.num=101;
12 stu.grade=86;
13 return(stu); /*返回結(jié)構(gòu)變量*/
14 }
15
16 intmain()
17 {
18 structstudentx={0,0};
19 structstudenty;
20
21 y=func1(x); /*實際參數(shù)為整個結(jié)構(gòu)變量*/
22 return0;
23}
圖7.20~圖7.23分別為例7-12的調(diào)試步驟1~調(diào)試步驟4。
圖7.20例7-12調(diào)試步驟1圖7.21中,值傳遞,形參stu的地址為0x12ff14,與實參存儲單元不是同一個。實參的值被拷貝了一份,放在形參中。
圖7.22中,結(jié)構(gòu)成員在子函數(shù)func1中被修改。
圖7.23中,返回主函數(shù),結(jié)構(gòu)變量y接收func1返回的結(jié)構(gòu)變量的值。
圖7.21例7-12調(diào)試步驟2
圖7.22例7-12調(diào)試步驟3
圖7.23例7-12調(diào)試步驟4注意:x、y與stu三者的存儲單元地址都是各分單元的,x的值并未被修改。
【例7-13】返回值是結(jié)構(gòu)指針的例子。
1 /*返回值是結(jié)構(gòu)指針*/
2 #include<stdio.h>
3
4 structstudent
5 {intnum;
6 floatgrade;
7 };
8
9 structstudent*func2(structstudentstu)
10 {
11 structstudent*str=&stu;
12 str->num=101;
13 str->grade=86;
14 return(str); /*返回結(jié)構(gòu)指針*/
15 }
16
17 intmain()
18 {
19 structstudentx={0,0};
20 structstudent*stuPtr;
21
22 stuPtr=func2(x);
23 return0;
24 }圖7.24~圖7.31分別為例7-13的調(diào)試步驟1~調(diào)試步驟8。
圖7.24中,注意實參x的地址為0x12ff78。
圖7.25中,注意形參stu的地址為0x12ff20。
圖7.26中,修改stu結(jié)構(gòu)中的成員值。
圖7.27中,主函數(shù)中sutPtr接收返回的局部量str的值。
圖7.24例7-13調(diào)試步驟1
圖7.25例7-13調(diào)試步驟2
圖7.26例7-13調(diào)試步驟3
圖7.27例7-13調(diào)試步驟4注意:在第6章“指針”中討論過關(guān)于不要返回局部量的地址的問題。此程序若以結(jié)構(gòu)體指針為參數(shù),可以改進如下:
1 /*以結(jié)構(gòu)體指針為形式參數(shù)*/
2 #include<stdio.h>
3
4 structstudent
5 {intnum;
6 floatgrade;
7 };
8
9 voidfunc3(structstudent*str)
10 {
11 str->num=101;
12 str->grade=86;
13 }
14
15 intmain()
16 {
17 structstudentx={0,0};
18
19 func3(&x);
20 return0;
21}
圖7.28~圖7.31為改進后程序的調(diào)試步驟。
圖7.28中,實參為結(jié)構(gòu)變量的地址0x12ff78。
圖7.29中,形參為結(jié)構(gòu)指針,指向?qū)崊卧獂。
圖7.30中,子函數(shù)func3修改0x12ff78地址中的結(jié)構(gòu)成員數(shù)據(jù)。
圖7.28例7-13調(diào)試步驟5
圖7.29例7-13調(diào)試步驟6
圖7.30例7-13調(diào)試步驟7
圖7.31例7-13調(diào)試步驟8
結(jié)構(gòu)變量與結(jié)構(gòu)指針在函數(shù)的信息傳遞中的使用方法及原則與普通變量及指針是一樣的。
【例7-14】結(jié)構(gòu)成員作形參的例子。已知一個班學(xué)生信息如表7.14所示,要求在主函數(shù)中賦初值及打印結(jié)果,在子函數(shù)中求出一個人的總成績和平均成績。
表7.14成績表
【解】(1)數(shù)據(jù)存放:結(jié)構(gòu)存儲。
#defineN50
structstu
{intnum;
charname[10];
floatmath;
floatphys;
floateng;
floatpro;
floattotal;
floatave;
};
structstua[N]
={ {1,"Zhao",77,68,86,73,0,0},
{2,"Qian",96,87,89,78,0,0},
{3,"Sun",70,90,86,81,0,0}
};
(2)算法分析:子函數(shù)的功能是實現(xiàn)總分和均分的計算,因此只需把各科成績信息傳遞給子函數(shù)即可,結(jié)構(gòu)中的學(xué)號、姓名等信息是不必傳遞的。設(shè)
structstup;
float*gradePtr;
p=a; /*ptr指針指向結(jié)構(gòu)表格的一行*/
gradePtr=&a[0].math; /*gradePtr指向成績起始地址*/
指針gradePtr和p的指向見圖7.32。
圖7.32數(shù)據(jù)及引用成績信息傳遞方法設(shè)計:由于各科的成績數(shù)據(jù)類型都一樣,在結(jié)構(gòu)中是連續(xù)存儲的,因此把成績信息作地址傳遞即可。子函數(shù)設(shè)計見表7.15。
表7.15例7-14子函數(shù)設(shè)計說明:
(1)輸入信息是成績,有多個,可能的方案有傳值和傳址兩種,這里采用傳址方式;形式參數(shù)為float型指針,實際參數(shù)為結(jié)構(gòu)成員math的地址。
(2)輸出信息有兩個,這里采用形參共用地址的方式,故就不用return了,因此函數(shù)的類型為void。
(3)程序?qū)崿F(xiàn):
1 /*結(jié)構(gòu)成員作形參*/
2 #include<stdio.h>
3 #defineN3
4 voidcalculate(float*gradePtr);
5
6 structstu
7 { intnum;
8 char*name;
9 floatmath;
10 floatphys;
11 floateng;
12 floatpro;
13 floattotal;
14 floatave;
15 };
16
17 intmain()
18 {
19 structstua[N]
20 ={ {1,"Zhao",77,68,86,73,0,0},
21 {2,"Qian",96,87,89,78,0,0},
22 {3,"Sun",70,90,86,81,0,0}
23 };
24 structstu*p=a;
25 inti;
26
27 printf("NameNum.Math.Phys.Eng.Pro.Total.Ave\n");
28 for(p=a,i=0;i<N;i++,p++)
29 {
30 calculate(&(*p).math);
31 printf("%4d%6s%7.2f%7.2f%7.2f%7.2f%7.2f%7.2f\n",
32 (*p).num,(*p).name,(*p).math,(*p).phys,
33 (*p).eng,(*p).pro,(*p).total,(*p).ave);
34 }
35 return0;
36 }
37
38 /*計算一個學(xué)生的總成績和平均成績*/
39 voidcalculate(float*gradePtr)
40 {
41 floatsum=0;
42 inti;
43 for(i=0;i<4;++i,++gradePtr)
44 {
45 sum+=*gradePtr;
46 }
47 *gradePtr=sum; /*求總成績*/
48 gradePtr++;
49 *gradePtr=sum/4; /求平均成績*/
50 }
程序結(jié)果:
NameNum.Math.Phys.Eng.Pro.Total.Ave
1Zhao77.0068.0086.0073.00304.0076.00
2Qian96.0087.0089.0078.00350.0087.50
3Sun70.0090.0086.0081.00327.0081.75
共用體(聯(lián)合體)是指幾個不同時出現(xiàn)的變量成員共享一塊內(nèi)存單元。當(dāng)若干變量每次只使用其中之一時,可以采用“共用體”(union)數(shù)據(jù)結(jié)構(gòu)。給共用體數(shù)據(jù)中各成員分配同一段內(nèi)存單元,設(shè)置這種數(shù)據(jù)類型的主要目的就是節(jié)省內(nèi)存。7.5共用體
1.共用體類型的定義
共用體類型定義的一般形式為:
union共用體名
{
類型名1成員名1;
類型名2成員名2;
…
類型名n成員名n;
}說明:
(1)union為關(guān)鍵字。
(2)和struct聲明一樣,union聲明僅僅創(chuàng)建了一個類型,在任何函數(shù)之外加union和struct聲明,并不會創(chuàng)建實際變量。
例如:
unionnumber
{
intx;
charch;
floaty;
};
與struct成員不同的是,union中的成員x、ch和y具有同樣的地址,如圖7.33所示。sizeof(unionnumber)取決于占空間最多的成員變量y。
圖7.33共用體成員共用同一個地址共用體的特點及與結(jié)構(gòu)體的關(guān)系見表7.16。
表7.16共用體的特點及與結(jié)構(gòu)體的關(guān)系2.共用體變量的定義
與結(jié)構(gòu)體變量相同,共用體變量定義的一般形式為:
union共用體名
{
類型名1成員名1;
類型名2成員名2;
…
類型名n成員名n;
}變量名表;
3.共用體成員的引用方式
共用體成員引用方式有兩種:
方式一:共用體變量名.成員名;
方式二:共用體指針名->成員名。
【例7-15】共用體的例子1。
#include<stdio.h>
intmain()
{
unionnumber /*定義共用體類型*/
{
intx;
charch;
floaty;
};
unionnumberunit; /*定義共用體變量*/
unit.x=1; /*共用體成員引用*/
unit.ch='a';
unit.y=2;
return0;
}
圖7.34~圖7.36所示分別為例7-15的調(diào)試步驟1~調(diào)試步驟3。
由圖7.34可以看出三個共用體成員的地址都是0x12ff7c,其中顯示了給成員x賦值1時的情形。
圖7.35顯示了給成員ch賦值‘a(chǎn)’
時的情形。
圖7.36顯示了給成員y賦值2時的情形。注意Memory中的值顯示的是0x40000000,這是什么原因呢?請看下面的“思考與討論”。
圖7.34例7-15調(diào)試步驟1
圖7.35例7-15調(diào)試步驟2
圖7.36例7-15調(diào)試步驟3
圖7.36中,float型變量y的值是2,為什么在內(nèi)存中顯示為0x40000000?
答:根據(jù)第2章中介紹的IEEE754標(biāo)準(zhǔn),按float占32位的情形,實數(shù)2的存儲形式見表7.17,即為0x40
溫馨提示
- 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度智能化廠房內(nèi)墻抹灰及防水處理勞務(wù)分包合同4篇
- 2024蘇州租房合同模板:蘇州工業(yè)園區(qū)租賃市場規(guī)范化合同9篇
- 專業(yè)貨車駕駛員勞動協(xié)議格式版B版
- 2024裝飾合同補充協(xié)議范本
- 2025年廠房租賃與產(chǎn)業(yè)協(xié)同發(fā)展合同4篇
- 2025年度茶葉包裝設(shè)計及印刷合同書范本4篇
- 二零二五年度城市綜合體BIM施工協(xié)調(diào)與監(jiān)控合同3篇
- 專業(yè)工地食堂供應(yīng)承包條款及合同(2024版)版B版
- 2025年度教育用品寄賣代理合同范本3篇
- 2025年度現(xiàn)代農(nóng)業(yè)科技示范場承包合作協(xié)議4篇
- 臺資企業(yè)A股上市相關(guān)資料
- 電 梯 工 程 預(yù) 算 書
- 羅盤超高清圖
- 參會嘉賓簽到表
- 機械車間員工績效考核表
- 形式發(fā)票格式2 INVOICE
- 2.48低危胸痛患者后繼治療評估流程圖
- 人力資源管理之績效考核 一、什么是績效 所謂績效簡單的講就是對
- 山東省醫(yī)院目錄
- 云南地方本科高校部分基礎(chǔ)研究
- 廢品管理流程圖
評論
0/150
提交評論