




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
第2章數(shù)據(jù)類型
2.1數(shù)據(jù)類型的定義與分類2.2基本數(shù)據(jù)類型2.3構(gòu)造數(shù)據(jù)類型2.4空類型2.5常見錯誤2.6綜合實(shí)例習(xí)題2 實(shí)驗22.1數(shù)據(jù)類型的定義與分類把一組性質(zhì)相同的數(shù)據(jù)歸為一類,就叫一種數(shù)據(jù)類型。在C語言程序中,為了便于進(jìn)行數(shù)據(jù)的操作,C語言語法要求每個數(shù)據(jù)必須具有某種類型。以int型為例,在16位機(jī)(為什么會提到16位機(jī)后面會解釋)中它的取值范圍是?-32?768~32?767之間,可用的運(yùn)算符集合為加、減、乘、除、取模運(yùn)算(即?+、-、*、/、%)。
1.數(shù)據(jù)類型的分類在C語言中,數(shù)據(jù)類型可分為基本數(shù)據(jù)類型、構(gòu)造數(shù)據(jù)類型、指針類型、空類型四大類。其中:基本數(shù)據(jù)類型最主要的特點(diǎn)是,其值不可以再分解為其他類型。也就是說,基本數(shù)據(jù)類型是自我說明的。構(gòu)造數(shù)據(jù)類型是根據(jù)已定義的一個或多個數(shù)據(jù)類型,用構(gòu)造的方法來定義的。也就是說,一個構(gòu)造類型的值可以分解成若干個“成員”或“元素”。每個“成員”都是一個基本數(shù)據(jù)類型或又是一個構(gòu)造類型。在C語言中,構(gòu)造類型有數(shù)組類型、結(jié)構(gòu)體類型和共用體(聯(lián)合)類型。
指針類型是一種特殊的具有重要作用的數(shù)據(jù)類型。其值用來表示某個變量在內(nèi)存儲器中的地址。雖然指針變量的取值類似于整型量,但這是兩個類型完全不同的量,因此不能混為一談。指針類型在第3章中詳細(xì)講解。
在調(diào)用函數(shù)時,通常應(yīng)向調(diào)用者返回一個函數(shù)值。這個返回的函數(shù)值是具有一定類型的,應(yīng)在函數(shù)定義及函數(shù)說明中給予說明。例如在函數(shù)頭intmax(inta,intb);中,“int”類型說明符即表示該函數(shù)的返回值為整型量。又如在使用庫函數(shù)sin時,由于系統(tǒng)規(guī)定其函數(shù)返回值為雙精度浮點(diǎn)型,因此在賦值語句s=sin(x);中,s也必須是雙精度浮點(diǎn)型,以便與sin函數(shù)的返回值一致。所以在說明部分,把s說明為雙精度浮點(diǎn)型。但是,也有一類函數(shù),調(diào)用后并不需要向調(diào)用者返回函數(shù)值,這種函數(shù)可以定義為“空類型”,其類型說明符為void。
2.數(shù)據(jù)類型與變量的關(guān)系對于每一種類型的變量,都為其定義了一定大小(由類型決定)的內(nèi)存空間。例如,若變量a是整型,則用變量定義語句inta;定義后,系統(tǒng)為其分配整型類型的空間,即2個或4個字節(jié)。數(shù)據(jù)類型只是規(guī)格,變量定義才分配空間。2.2基本數(shù)據(jù)類型對于基本數(shù)據(jù)類型,按其取值是否可改變又分為常量和變量兩種類型。在程序執(zhí)行過程中,其值不發(fā)生改變的量稱為常量,其值可變的量稱為變量。在程序中,常量是可以不經(jīng)說明而直接引用的,而變量則必須先定義后使用。
C語言中有以下幾個基本數(shù)據(jù)類型:char(字符型)、int(整型)、float(單精度浮點(diǎn)型)和double(雙精度浮點(diǎn)型)。另外,還有4個修飾詞可以出現(xiàn)在上面幾個基本類型之前,從而改變原來的含義,它們是short(短型)、long(長型)、
signed(有符號)和unsigned(無符號)。例如:
shortint表示短整型;
unsignedchar表示無符號字符型;
longint表示長整型;
unsignedshortint表示無符號短整型。各種無符號類型量所占的內(nèi)存空間字節(jié)數(shù)與相應(yīng)的有符號類型量相同,但由于省去了符號位,故不能表示負(fù)數(shù)。數(shù)據(jù)的長度和取值范圍隨著CPU類型(16位、32位或64位等)和C編譯器的不同而不同。表2.1列出了16位機(jī)與32位機(jī)中的基本數(shù)據(jù)類型及其所占字節(jié)數(shù)。表2.2列出了在不同實(shí)現(xiàn)環(huán)境下的基本數(shù)據(jù)類型及其所占字節(jié)數(shù)。表2.116位與32位機(jī)中的基本數(shù)據(jù)類型及其所占字節(jié)數(shù)表2.2不同實(shí)現(xiàn)環(huán)境下的基本數(shù)據(jù)類型及其所占字節(jié)數(shù)下面討論變量在內(nèi)存中的存放形式,以進(jìn)一步了解基本數(shù)據(jù)類型。
1.整型數(shù)值在內(nèi)存中是以補(bǔ)碼的形式存放的,正數(shù)的補(bǔ)碼和原碼相同;負(fù)數(shù)的補(bǔ)碼為將該數(shù)的絕對值的二進(jìn)制形式按位取反再加1。因此,若有inta?=?10,b?=?-10,則a、b在內(nèi)存中的存放形式如下:
【程序2.1】
分析下面程序的結(jié)果。
main()
{
inta=-12,b=2;
unsignedu=10;
printf("a+u=%d,%u\n",a+u,a+u);
printf("b+u=%d,%u\n",b+u,b+u);
}在TC環(huán)境下的運(yùn)行結(jié)果:
a+u=-2, 65534
b+u=12,12在VC環(huán)境下的運(yùn)行結(jié)果:
a+u=-2, 4294967294
b+u=12,12【程序2.2】
分析下面程序的結(jié)果。main(){inta,b;shortc,d;
a=2147483647;b=a+1;c=32767;d=c+1;printf("a=%d,b=%d,c=%d,d=%d",a,b,c,d);}在TC環(huán)境下的運(yùn)行結(jié)果:a=-1,b=0,c=32767,d=-32768 在VC環(huán)境下的運(yùn)行結(jié)果:a=2147483647,b=-2147483648,c=32767,d=-32768通過上述例子可以看出,當(dāng)變量的值超出它所允許的范圍時,其值會變得不準(zhǔn)確。因此在定義變量時,一定要注意該變量類型所允許的取值范圍。思考:為什么在不同的環(huán)境下執(zhí)行會有不同的結(jié)果?
2.實(shí)型實(shí)型分單精度型與雙精度型。單精度型占4個字節(jié)的內(nèi)存空間,提供6~7位有效數(shù)字;雙精度型占8個字節(jié)的內(nèi)存空間,提供15~16位有效數(shù)字;longdouble占16個字節(jié),提供18~19位有效數(shù)字。實(shí)型數(shù)據(jù)的格式如下:其中,階符與數(shù)符均占一位,階碼和尾數(shù)部分的長度與計算機(jī)系統(tǒng)采用定點(diǎn)數(shù)還是浮點(diǎn)數(shù)表示有關(guān)系,在此不予詳細(xì)討論?!境绦?.3】
分析下面程序的結(jié)果。#include<stdio.h>main(){ floate=-563246658.123456789; doublef=7895306562678441359.143256234154613256; longdoubleg=-100000000000.22222222222222222222222; printf("thetypeofthisvariableisfloat.(%6f)\n",e); printf("thetypeofthisvariableisdouble.(%14f)\n",f); printf("thetypeofthisvariableislong
double.(%18f)\n",g);
}提到實(shí)型,有很多讀者可能遇到這種問題:
floatf=3.1;
printf("%f",f);輸出可能是3.0999999。其原因是:實(shí)型數(shù)據(jù)也是用二進(jìn)制來表示的。在十進(jìn)制下,0.1是個簡單、精確的小數(shù),但是用二進(jìn)制表示起來卻是個循環(huán)小數(shù)0.0001100110011…。所以3.1在十進(jìn)制下可以準(zhǔn)確地表達(dá),而在二進(jìn)制下不能。因此,在對一些二進(jìn)制中無法精確表示的小數(shù)進(jìn)行賦值或讀入再輸出,也就是將十進(jìn)制數(shù)轉(zhuǎn)成二進(jìn)制數(shù)再轉(zhuǎn)回十進(jìn)制數(shù)時,會觀察到數(shù)值的不一致。這是由編譯器的二進(jìn)制/十進(jìn)制轉(zhuǎn)換例程的精確度引起的。同樣,比較兩個實(shí)型數(shù)的最好方法是利用閾值,而不要直接作比較。這個閾值和作比較的浮點(diǎn)數(shù)值大小有關(guān)。例如,不要用下面的代碼:
doublea,b;
if(a==b)/*錯!*/要用類似下面的方法:
#include<math.h>
if(fabs(a-b)<=epsilon*fabs(a))
epsilon被賦為一個選定的值來控制“接近度”,當(dāng)然也還要確定a不會為0。
3.字符型字符型變量占一個內(nèi)存單元,存放字符的ASCII碼值,如charx='a';,則變量x在內(nèi)存中的存放形式如下:
C語言允許對整型變量賦予字符值,也允許對字符變量賦予整型值。在輸出時,允許把字符變量按整型量輸出,也允許把整型量按字符量輸出。但要注意:整型變量占2個字節(jié),字符變量占1個字節(jié),當(dāng)整型變量按字符變量處理時,只有低8位字節(jié)參與處理;當(dāng)字符變量按整型變量處理時,高8位為0。
char型是signedchar或unsignedchar,這一說法都是不準(zhǔn)確的。有些編譯器將char默認(rèn)為signedchar,有些則默認(rèn)為unsignedchar。TC和VC++?編譯器都將char默認(rèn)為signedchar。
4.枚舉類型如果一個變量只有幾種可能的取值,則可以將其定義為枚舉類型。枚舉就是將變量可能的值一一列舉出來,變量的值只能取列舉出來的值之一。枚舉在日常生活中很常見,例如表示星期的SUN、MON、TUE、WED、THUR、FRI、SAT就是一個枚舉。枚舉的說明與結(jié)構(gòu)和聯(lián)合相似(見2.3.1和2.3.2節(jié)),其形式為:
enum枚舉名{
標(biāo)識符[=整型常數(shù)],
標(biāo)識符[=整型常數(shù)],
標(biāo)識符[=整型常數(shù)],
};如果枚舉沒有初始化,即省掉“=整型常數(shù)”,則從第一個標(biāo)識符開始,順次賦給標(biāo)識符0,1,2,…。但當(dāng)枚舉中的某個成員賦值后,其后的成員按依次加1的規(guī)則確定其值。例如:enumcolor{red,green,blue,yellow};此時,標(biāo)識符依次被賦予0~3的整數(shù)。當(dāng)定義改變成:enumcolor{red,green=3,blue,yellow};則red=0,green=3,blue=4,yellow=5。大家知道,C語言沒有布爾類型,因此可以通過枚舉定義一個布爾類型:
typedefenum{false,true}Bool;/*typedef的作用在2.3.3節(jié)中有詳細(xì)介紹*/
Boolb;/*b可以賦值為false或true*/枚舉標(biāo)識符變量代表整數(shù),類似?#define定義的宏變量,是不能按標(biāo)識符樣子輸入/輸出的,只能通過其他辦法輸出?!境绦?.4】
了解枚舉變量的應(yīng)用。
enumWeek{MON=1,TUE,WED,THUR,FRI,SAT,SUN};
main()
{enumWeekday;
printf("What'sthedaytoday?");
scanf("%d",&day);
printf("\nTodayis:");
switch(day){ caseMON: printf("Mon"); break; caseTUE: printf("TUE"); break; caseWED: printf("WED"); break; caseTHUR: printf("THUR"); break;
caseFRI: printf("FRI"); break; caseSAT: printf("SAT"); break;
caseSUN: printf("SUN"); break; default: printf("**Entererror!");?}}程序執(zhí)行結(jié)果:
Wha’sthedaytoday:6
Todayis:SAT注意事項:
(1)枚舉變量的值表示的是整數(shù)。初始化時可以賦負(fù)數(shù),以后的標(biāo)識符仍依次加1。
(2)枚舉變量只能取枚舉說明結(jié)構(gòu)中的某個標(biāo)識符常量。2.3構(gòu)造數(shù)據(jù)類型在程序設(shè)計過程中,經(jīng)常會有一些數(shù)據(jù)無法用已有的原子數(shù)據(jù)類型進(jìn)行描述,這就需要用戶自己構(gòu)造數(shù)據(jù)類型。常用的構(gòu)造數(shù)據(jù)類型有以下幾種:①結(jié)構(gòu)體類型;②共用體類型;③數(shù)組類型。本節(jié)只講述結(jié)構(gòu)體類型和共用體類型。2.3.1結(jié)構(gòu)體實(shí)際應(yīng)用中,有時需要將不同數(shù)據(jù)類型的數(shù)據(jù)組合成一個有機(jī)的整體。比如在學(xué)生的學(xué)籍管理過程中,需要記錄學(xué)生的個人信息、學(xué)習(xí)成績以及其他情況,如果用原子類型進(jìn)行變量描述就顯得很不方便。此時,可以采用構(gòu)造的結(jié)構(gòu)體類型進(jìn)行變量描述,不過首先要定義一個結(jié)構(gòu)體類型。學(xué)生的個人信息有以下幾項:姓名、性別、年齡、系別、學(xué)號、個人成績,個人成績又可以細(xì)分為專業(yè)課程1、專業(yè)課程2、…、專業(yè)課程n。“結(jié)構(gòu)”是一種構(gòu)造類型,它是由若干“成員”組成的。每一個成員可以是一個基本數(shù)據(jù)類型或者又是一個構(gòu)造類型。結(jié)構(gòu)既然是一種“構(gòu)造”而成的數(shù)據(jù)類型,那么在說明和使用之前必須先定義它,也就是構(gòu)造它,如同在說明和調(diào)用函數(shù)之前要先定義函數(shù)一樣。
1.結(jié)構(gòu)體類型的定義結(jié)構(gòu)體類型定義的一般形式為:
struct結(jié)構(gòu)體名{
成員表列;
};成員表列由若干個成員組成,每個成員都是該結(jié)構(gòu)體的一個組成部分。對每個成員也必須作類型說明,其形式為:類型說明符成員名;/*成員的類型可以是基本類型,也可以是構(gòu)造類型*/例如:structstu{intnum;charname[20];charsex;floatscore[4];};有幾個注意事項:
(1)結(jié)構(gòu)體類型的定義可以在函數(shù)內(nèi)部定義,也可以在函數(shù)外部定義。如果在函數(shù)內(nèi)部定義,那么只有在該函數(shù)內(nèi)部可見;如果在外部定義,則從定義點(diǎn)到文件結(jié)尾處,對所有的函數(shù)都可見。
(2)結(jié)構(gòu)體類型中的成員在定義時不占用內(nèi)存空間,只有在定義了結(jié)構(gòu)體變量后才分配內(nèi)存空間。
(3)定義了結(jié)構(gòu)體類型后,可以像使用基本數(shù)據(jù)類型一樣去定義結(jié)構(gòu)體變量、數(shù)組、指針。
(4)結(jié)構(gòu)體定義時可以嵌套定義,如:
structstu
{
intnum;
charname[20];
structdate{
intyear;intmonth;intday;}birthday;
floatscore[4];
};以上等價于:structdate{intyear;intmonth;intday;};structstu{intnum;charname[20];structdatebirthday;floatscore[4];};2.結(jié)構(gòu)體變量的定義結(jié)構(gòu)體變量的定義有三種方法:(1)先定義結(jié)構(gòu)體類型,再定義結(jié)構(gòu)體變量。例如:structstu{intnum;charname[20];charsex;floatscore[4];};在使用時,采用以下方式定義結(jié)構(gòu)體變量:structstustu1,stu2;注意,此時structstu是結(jié)構(gòu)體類型的名稱,如同基本數(shù)據(jù)類型一樣。因此,定義結(jié)構(gòu)體變量時不要誤寫為structstu1;或者stustu1;,這些都是錯誤的。
(2)在定義結(jié)構(gòu)體類型的同時定義結(jié)構(gòu)體變量。例如:
structstu
{
intnum;
charname[20];
charsex;
floatscore[4];
}stu3;
stu3是結(jié)構(gòu)體變量。當(dāng)以后需要定義其他該結(jié)構(gòu)體變量時,仍舊可以采用structstu來定義,如structstustu_3;等。
(3)直接定義結(jié)構(gòu)體變量。例如:
struct
{
intnum;
charname[20];
charsex;
floatscore[4];
}stu4;這種方式下,如果需要定義其他結(jié)構(gòu)變量,只能在stu4之后繼續(xù)補(bǔ)充。注意:結(jié)構(gòu)名和結(jié)構(gòu)變量是兩個不同的概念,不能混淆。結(jié)構(gòu)名只能表示一個結(jié)構(gòu)形式,編譯系統(tǒng)并不對它分配內(nèi)存空間。只有當(dāng)某變量被說明為這種類型的結(jié)構(gòu)時,才對該變量分配存儲空間,且此時成員的變量空間是連續(xù)的。
3.結(jié)構(gòu)體變量的使用
(1)結(jié)構(gòu)體變量的賦值。結(jié)構(gòu)體變量可以在定義時直接賦初值,如:
structstustu1={1001,"wanglin",'f',{89,86,90,91}};/*正確*/但不能在定義后再直接賦值,如:
structstustu2;
stu2={1002,"wangwei",'m',{85,87,91,81}};/*錯誤*/只能通過給結(jié)構(gòu)體成員一一賦值的方式來進(jìn)行,如下:
stu2.num=1002; strcpy(,"wangwei"); stu2.sex='m';
stu2.score[0]=85;stu2.score[1]=87;stu2.score[2]=91;
stu2.score[3]=81;相同類型的結(jié)構(gòu)體變量可以直接賦值,如:
stu2=stu1;/*相當(dāng)于將stu1中的每一個成員的值賦給stu2中的每一個成員*/但不能采用if(stu1==stu2)來試圖判斷兩個結(jié)構(gòu)體變量是否相等,而必須通過比較每個成員的值來判斷。
(2)結(jié)構(gòu)體數(shù)組。如果數(shù)組的每一個元素是結(jié)構(gòu)類型的,那么該數(shù)組就是結(jié)構(gòu)體數(shù)組。在實(shí)際應(yīng)用中,經(jīng)常用結(jié)構(gòu)體數(shù)組來表示具有相同數(shù)據(jù)結(jié)構(gòu)的一個群體,如一個班的學(xué)生檔案、一個車間職工的工資表等。如:
structstucomputerStu[60];
(3)結(jié)構(gòu)體指針變量。結(jié)構(gòu)體指針變量說明的一般形式為:
struct結(jié)構(gòu)名*結(jié)構(gòu)指針變量名結(jié)構(gòu)體指針變量中的值是所指向的結(jié)構(gòu)體變量的首地址。通過結(jié)構(gòu)體指針即可訪問該結(jié)構(gòu)體變量。例如,在前面我們定義了stu這個結(jié)構(gòu),如要說明一個指向stu的指針變量pstu,可寫為:
structstu*pstu=computerStu;
(4)結(jié)構(gòu)體變量成員的引用。只能對結(jié)構(gòu)體變量的成員進(jìn)行訪問,其訪問形式有:結(jié)構(gòu)體變量.成員名結(jié)構(gòu)體指針->成員名
(*結(jié)構(gòu)體指針).成員名/*不常用*/
【程序2.5】
結(jié)構(gòu)體變量的使用。
structdate{
intyear;
intmonth;
intday;
};
structteacher{
intnum;
charname[20];
charsex;
structdatebirth;
};main(){structteachert1,*pt=&t1;t1.num=2007;
strcpy(,"liujing");t1.sex='f';t1.birth.year=1980;t1.birth.month=5;t1.birth.day=3;
printf("\nnum=%d\nname=%s\nsex=%c\nbirth=%d-%d-%d",pt->num,pt->name,
pt->sex,pt->birth.year,pt->birth.month,pt->birth.day);}
【程序2.6】
輸入一組學(xué)生的信息,用子函數(shù)計算學(xué)生的平均成績,并統(tǒng)計不及格學(xué)生人數(shù)。
#defineN3
structstudent{
intnumber;
charname[20];
floatscore;
};voidaverage(structstudents[],intn){floattemp=0;intcount=0,i;for(i=0;i<n;i++){temp+=s[i].score;if(s[i].score<60)count++;}printf("Averagescore=%f\nfailstus=%d",temp/n,count);}main(){structstudentstu[N];
inti;for(i=0;i<N;i++) scanf("%d%s%f",&stu[i].number,stu[i].name,&stu[i].score);average(stu,N);}該程序在輸入時會產(chǎn)生以下錯誤:
scanf:floatingpointformatsnotlinked
Abnormalprogramtermination其原因是:TC是在20世紀(jì)80年代在DOS下開發(fā)的,當(dāng)時存儲資源緊缺,因此TC編譯器在編譯時盡量不加入無關(guān)部分。TC編譯器在沒發(fā)現(xiàn)需要做浮點(diǎn)轉(zhuǎn)換時,就不將這個部分安裝到可執(zhí)行程序里,而實(shí)際上確實(shí)需要浮點(diǎn)轉(zhuǎn)換,因此就會出現(xiàn)以上錯誤。解決方法:設(shè)法告訴TC編譯器需要做浮點(diǎn)數(shù)輸入轉(zhuǎn)換。實(shí)現(xiàn)時有兩種方法:
(1)在主函數(shù)中加入floatarg,*point=&arg;,這樣就連接了浮點(diǎn)庫。
(2)采用“偷梁換柱”的方法,即在輸入時用一個實(shí)型變量替換,再將該實(shí)型變量的值賦值給結(jié)構(gòu)體變量中的實(shí)型成員。程序2.7是用第二種方法實(shí)現(xiàn)的。【程序2.7】
程序2.6的main函數(shù)改為:main(){structstudentstu[N];
inti;floatf;for(i=0;i<N;i++)
{scanf("%d%s%f",&stu[i].number,stu[i].name,&f);stu[i].score=f;}average(stu,N);}2.3.2共用體共用體也叫聯(lián)合,與結(jié)構(gòu)體類似,也是將一些不同類型的數(shù)據(jù)組織在一起而形成的一種數(shù)據(jù)類型。但共用體只為其中最大的成員分配足夠的內(nèi)存空間,其他成員變量共享這段內(nèi)存。因此,在某一時刻只能存放一個成員,而不能同時存放幾個成員。所以在使用共用體變量時,要注意起作用的成員是最后一次存入的成員,其他成員的值已被覆蓋掉。換句話說,共用體變量在對一個成員變量賦值后,原來的成員因被覆蓋而失去作用。共用體與結(jié)構(gòu)體類型唯一不同的是:對于結(jié)構(gòu)體變量,每個成員變量有其獨(dú)立的內(nèi)存儲空間,對某個成員變量的操作不影響其他成員變量的值;對于共用體變量,所有成員共享一個空間,每次只有一個成員的值有效。例如:
structSTest{ intnum; charc; floatf;
}stag;
unionUTest{
intnum; charc; floatf;
}utag;假設(shè)內(nèi)存起始地址為1000,stag與utag的內(nèi)存結(jié)構(gòu)如圖2.1所示。圖2.1共同體與結(jié)構(gòu)體變量的內(nèi)存結(jié)構(gòu)
【程序2.8】
分析下面程序的執(zhí)行結(jié)果。
union{
inta;
charch[2];
}test;
main()
{test.ch[0]=1;
test.ch[1]=2;
printf("%d",test.a);
}程序執(zhí)行結(jié)果:
513使用共用體,一方面可以節(jié)省空間,一方面可以構(gòu)造混合類型的數(shù)據(jù)結(jié)構(gòu)。
1.使用共用體節(jié)省空間假設(shè)要設(shè)計一個可以同時存儲學(xué)生和老師信息的數(shù)據(jù)結(jié)構(gòu),老師和學(xué)生的信息如下:老師信息:職工號,姓名,年齡,工資;學(xué)生信息:學(xué)號,姓名,年齡,班級。如果采用結(jié)構(gòu)體,則應(yīng)該如下定義:
structtable{
intnumber;
charname[10];
intage;
doublesalary;
intclass;
};前3項成員教師和學(xué)生都能使用,但如果存儲教師信息,則class無用;如果存儲學(xué)生信息,則salary無用,造成空間浪費(fèi)。因此,合理的結(jié)構(gòu)應(yīng)該是這樣:
structtable{
intnumber;
charname[10];
intage;
union{ doublesalary; intclass;}class_salary;
};
2.使用共用體構(gòu)造混合型數(shù)據(jù)結(jié)構(gòu)數(shù)組要求元素類型必須相同,所以,如果想創(chuàng)建一個既能存儲整型,也能存儲浮點(diǎn)型的數(shù)組就需要借助共用體。定義一個如下的共用體:
uniontype{
inti;
floatf;
};
uniontypearray[10];/*定義共用體數(shù)組*/
array[0].i=10;/*數(shù)組的0號單元存儲整數(shù)*/
array[1].f=10.1;/*數(shù)組的1號單元存儲浮點(diǎn)數(shù)*/2.3.3typedef的使用
1.基本概念關(guān)鍵字typedef可以用來建立已定義好的數(shù)據(jù)類型的別名。例如:
typedefintINTEGER;
typedeffloatREAL;以上定義給已有數(shù)據(jù)類型int起別名為INTEGER,給float起別名為REAL。根據(jù)上述定義,以下兩行等價:
inti,j;floata,b;
INTEGERi,j;
REAL
a,b;2.典型用途
(1)便于程序的移植。假定有兩種類型的機(jī)器,A型號機(jī)器上的int類型占4個字節(jié),B型號機(jī)器上的int占2個字節(jié),long占4個字節(jié)。我們編寫了一個程序,在A型號的機(jī)器上運(yùn)行正確,但如果將程序直接移植到B機(jī)器上,由于B機(jī)器上int類型只占2個字節(jié),可能會導(dǎo)致程序運(yùn)行失敗。此時,需要將程序中所有int改為long,工作量很大。如果我們在程序中有如下定義:
typedefintINTEGER;那么,在使用到int的地方,都要用INTEGER代替。如果在B機(jī)器上運(yùn)行程序,只需要將上面那條語句改為:
typedeflongINTEGER;即可保證程序的正確運(yùn)行,使程序具有很好的可移植性。
(2)使程序更加清晰。例如定義size_t數(shù)據(jù)類型,專用于內(nèi)存字節(jié)計數(shù):
typedefunsignedintsize_t
size_tsize;/*變量size用于內(nèi)存字節(jié)計數(shù)*/或定義COUNT數(shù)據(jù)類型,專用于計數(shù):
typedefintCOUNT
COUNTi,j;
(3)書寫簡單。例如定義:
typedefstructcardCard;以后就可以直接使用Card來代替structcard定義結(jié)構(gòu)體類型的變量了。通常使用以下形式定義:
typedefstructcard{
char*face;
char*suit;
}Card;/*Card不是結(jié)構(gòu)體變量,而是結(jié)構(gòu)體的別名*/一般為了強(qiáng)調(diào)用typedef定義的類型名是其他類型名的別名,建議以大寫字母開頭的形式書寫用typedef定義的類型名。定義好Card后,就可以用它來聲明變量了。語句Carddeck[52];與語句structcarddeck[52];是等價的,聲明了一個有52個元素的Card結(jié)構(gòu)(即structcard類型)的數(shù)組。注意:用typedef建立一個新的名字實(shí)際上并沒有建立一個新的類型,而只是建立了一個用作現(xiàn)有類型名別名的新的類型名而已。有意義的名字可以提高程序的可讀性。例如:在讀到上面的聲明語句時,我們可以知道“deck是有52張牌(Card)的數(shù)組”。2.4空類型空類型即void類型,void*?則為“無類型指針”。void幾乎只有“注釋”和限制程序的作用,因為從來沒有人會定義一個void變量。如果定義:
voida;編譯這行語句時會出錯,提示“illegaluseoftype‘void’”。void真正的作用在于:
(1)對函數(shù)返回的限定,該函數(shù)沒有返回值。
(2)對函數(shù)參數(shù)的限定,該函數(shù)沒有參數(shù)。眾所周知,如果指針p1和p2的類型相同,那么我們可以直接在p1和p2間互相賦值;如果p1和p2指向不同的數(shù)據(jù)類型,則必須使用強(qiáng)制類型轉(zhuǎn)換運(yùn)算符把賦值運(yùn)算符右邊的指針類型轉(zhuǎn)換為左邊的指針類型。例如:
float*p1;
int*p2;
p1=p2;其中p1=p2語句編譯時會出錯,提示“'=':cannotconvertfrom'int*'to'float*'”,所以必須改為:
p1=(float*)p2;而void*?則不同,任何類型的指針都可以直接賦值給它,無需進(jìn)行強(qiáng)制類型轉(zhuǎn)換,例如:
void*p1;
int*p2;
p1=p2;編譯時不會出錯,但這并不意味著void*?也可以無需強(qiáng)制類型轉(zhuǎn)換地賦給其他類型的指針,因為“無類型”可以包容“有類型”,而“有類型”則不能包容“無類型”。下面的語句編譯時會出錯:
void*p1;
int*p2;
p2=p1;提示“'=':cannotconvertfrom'void*'to'int*'”。2.5常見錯誤
(1)結(jié)構(gòu)體類型定義時缺少分號。如:
structcolor{
intred;
intgreen;
intblue;
}/*在此少了一個分號*/同樣的問題也可能會出在定義聯(lián)合和枚舉類型時。
(2)把結(jié)構(gòu)名當(dāng)作變量名。如:
structcolor{
intred;
intgreen;
intblue;
};
color.red=0;color.green=255;color.blue=0;/*color為結(jié)構(gòu)名稱,不是結(jié)構(gòu)體變量*/正確的應(yīng)該為:
structcolorc;
c.red=0;c.green=255;c.blue=0;
(3)定義結(jié)構(gòu)體變量時丟失struct或者只寫struct。如:
colorc1;/*錯誤*/
structc2;/*錯誤*/這多少有些受inta;的影響。覺得類型是一個單詞。正確的應(yīng)該為:
structcolorc1;
structcolorc2;
(4)將結(jié)構(gòu)體定義在某一函數(shù)之內(nèi),但在其他函數(shù)內(nèi)部卻用到了該結(jié)構(gòu)體。如:
main()
{
structcolor{
intred;
intgreen;
intblue;
};
}
intfun()
{
structcolorcc;
}結(jié)構(gòu)體名稱也是標(biāo)識符,有它的作用域。上述例子中,結(jié)構(gòu)體structcolor的作用域就是main函數(shù),main函數(shù)之外是不可見的。因此,一般將結(jié)構(gòu)體的定義放在程序的開始處,這樣對整個源文件都是可見的。
(5)結(jié)構(gòu)體變量值的交換。如:
structcolorc1,c2;
inttmp;
c1.red=0;c1.green=255;c1.blue=0;
c2.red=255;c2.green=0;c2.blue=0;欲交換c1和c2的值,很多初學(xué)者就會犯下面的錯誤(或許不該稱為錯誤,只能說太費(fèi)事):
tmp=c1.red;c1.red=c2.red;c2.red=tmp;
tmp=c1.green;c1.green=c2.green;c2.green=tmp;
tmp=c1.blue;c1.blue=c2.blue;c2.blue=tmp;試想想,如果一個結(jié)構(gòu)體中有幾十個成員時,需要寫多少代碼啊??刹捎孟旅娴娜龡l語句代替上面的九條語句:tmp=c1;c1=c2;c2=tmp;/*切記此時tmp的類型應(yīng)為structcolor,而不是int*/
(6)直接輸入結(jié)構(gòu)體。有了(5)的啟示,很多讀者就認(rèn)為編譯器很聰明,因此又會犯下面的錯誤:
structcolorc;
scanf("%d%d%d",&c);/*錯誤*/正確的應(yīng)該為:
structcolorc;
scanf(“%d%d%d”,&c.red,&c.green,&c.blue);
2.6綜合實(shí)例
【程序2.9】
每個城市的信息由城市名(字符串)和位置坐標(biāo)組成(x,y)。設(shè)計實(shí)現(xiàn)一程序,從鍵盤輸入各城市信息,并按城市名字非遞減排序后輸出。#include<stdio.h>#include<string.h>#defineN5/*城市個數(shù)*/typedefstructposition{intx; inty;}Pos;typedefstructcity{ charname[20]; Posloc;}City;voidsortByName(Citycy[]);main(){ inti; CitychinaCity[N]; /*輸入各城市信息*/ for(i=0;i<N;i++){ printf("Enter%dcityinfor:\n",i); scanf("%s%d%d",chinaCity[i].name,&chinaCity[i].loc.x,&chinaCity[i].loc.y); }
sortByName(chinaCity); /*按城市名非遞減排序*//*輸出排序后的各城市信息*/ printf("Aftersortbyname,thecityinforis:\n"); printf("namelocation\n"); for(i=0;i<N;i++) printf("%-10s(%d,%d)\n",chinaCity[i].name,chinaCity[i].loc.x,chinaCity[i].loc.y);}/*采用選擇排序算法按城市名非遞減排序*/voidsortByName(Citycy[]){inti,j,k; Citytemp; for(i=0;i<N-1;i++)
{k=i; for(j=i+1;j<N;j++)
if(strcmp(cy[j].name,cy[k].name)<0)
k=j;
if(k!=i) {temp=cy[i];cy[i]=cy[k];cy[k]=temp;}
}}讀者可在此基礎(chǔ)上添加如下功能:輸入某個位置信息,查詢該位置的城市名稱。
【程序2.10】
挖坑發(fā)牌程序。挖坑是一種比較流行的游戲,下面我們來模擬一下挖坑的發(fā)牌程序。游戲介紹:挖坑是三人游戲,一副牌去掉大小王不用,共52張牌,發(fā)牌時每人發(fā)16張牌,剩余4張為底牌。最后由三人叫分,誰叫的分多,4張底牌全部歸誰。分析:
(1)每張撲克牌有兩個屬性,花色和面值。因此,可采用結(jié)構(gòu)體來實(shí)現(xiàn)。其中花色的取值就四種:紅桃、黑桃、方塊和梅花,可采用枚舉來實(shí)現(xiàn)。其定義為
typedefenum{Hearts=1,Spade,Diamonds,Club}Suit;/*紅桃,黑桃,方塊,梅花*/
typedefstruct{ intrank;/*面值*/ Suitsuit;/*花色*/
}Card;
(2)回想一下我們現(xiàn)實(shí)生活中是如何進(jìn)行挖坑的:首先需要有一副撲克牌,然后經(jīng)過洗牌(洗的越均勻越好),再順次發(fā)給三人。因此需要一個創(chuàng)建撲克牌模塊、洗牌模塊和發(fā)牌模塊。程序如下:
#include"stdio.h"
#include"stdlib.h"
#defineM52
typedefenum{Hearts=1,Spade,Diamonds,Club}Suit;
typedefstruct{ intrank; Suitsuit;
}Card;voidcreat(Cardcard[]);/*創(chuàng)建一副撲克牌*/voidriffle(Cardcard[]);/*洗牌*/voiddeal(Cardcard[]);/*發(fā)牌*/
main(){ Cardcard[M]; creat(card); riffle(card); deal(card);}/*創(chuàng)建牌的思路:共52張牌,每個花色共13張牌。因此,將52與13取余的結(jié)果+1作為牌的面值,將52與13取整的結(jié)果+1作為花色*/voidcreat(Cardcard[]){ inti;
for(i=0;i<M;i++) { card[i].rank=i%13+1;
card[i].suit=(Suit)(i/13+1);/*將整數(shù)值強(qiáng)制轉(zhuǎn)換為枚舉類型*/ }}/*洗牌的思路是:隨機(jī)產(chǎn)生兩個代表撲克牌位置的整數(shù),將這兩個位置的牌交換(兩數(shù)交換),若干次后,牌的原有次序被打亂*/voidriffle(Cardcard[]){ inti,rand1,rand2; Cardtmp; for(i=0;i<1000;i++){ rand1=random(M); rand2=random(M); if(rand1!=rand2) { tmp=card[rand1]; card[rand1]=card[rand2]; card[rand2]=tmp; } }}voiddeal(Cardcard[]){ inti,j=0,num,p; /*p為拿最后4張牌的人*/ Cardperson[3][20]; /*3個人玩牌,只有一人最多20張牌*/ for(i=0;i<M-4;i=i+3) /*將洗好的牌依次發(fā)給3個人,最后留下4張*/ { person[0][j]=card[i]; person[1][j]=card[i+1]; person[2][j]=card[i+2]; j++; }/*為了簡化叫分過程,采用提問方式?jīng)Q定誰要最后的4張牌*/ clrscr();/*清屏*/ printf("\n\nFourcardsareleft,Whowantthem?(1~3)"); scanf("%d",&p); person[p-1][16]=card[M-4];person[p-1][17]=card[M-3]; person[p-1][18]=card[M-2];person[p-1][19]=card[M-1]; /*打印發(fā)牌結(jié)果*/
for(i=0;i<3;i++) { if(p==i+1)num=20; elsenum=16;printf("\n\n****person%dhasthe%dcards:****\n",i+1,num); for(j=0;j<num;j++) { switch(person[i][j].suit) { caseHearts:printf("(Hearts,");break; caseSpade:printf("(Spade,");break; caseDiamonds:printf("(Diamonds,");break; caseClub:printf("(Club,");break; }switch(person[i][j].rank) { case1:printf("A)");break; case2: case3: case4: case5: case6: case7: case8: case9: case10:printf("%d)",person[i][j].rank);break; case11:printf("J)");break; case12:printf("Q)");break; case13:printf("K)");break; } } }}執(zhí)行結(jié)果為:Fourcardsareleft,Whowantthem?(1~3)2****person1hasthe16cards:****(Club,5)(Club,3)(Hearts,2)(Hearts,Q)(Hearts,7)(Spade,7)(Spade,J)(Diamonds,J)(Hearts,3)(Club,8)(Diamonds,10)(Spade,8)(Hearts,4)(Diamonds,4)(Spade,6)(Spade,4)****person2hasthe20cards:****(Club,J)(Club,A)(Club,K)(Diamonds,8)(Diamonds,3)(Hearts,A)(Club,6)(Hearts,8)(Spade,A)(Hearts,J)(Diamonds,6)(Diamonds,A)(Spade,5)(Club,7)(Diamonds,9)(Spade,10)(Spade,Q)(Hearts,K)(Club,9)(Diamonds,7)****person3hasthe16cards:****(Diamonds,K)(Hearts,9)(Diamonds,Q)(Hearts,5)(Spade,9)(Spade,3)(Spa
溫馨提示
- 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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 寧夏2025自考環(huán)境設(shè)計馬克思概論模擬題及答案
- 陜西2025自考區(qū)域國別學(xué)國際政治經(jīng)濟(jì)學(xué)高頻題考點(diǎn)
- 江蘇2025自考數(shù)字戲劇三維動畫基礎(chǔ)易錯題專練
- 江蘇2025自考國際郵輪管理郵輪運(yùn)營管理主觀題專練
- 河南2025自考金融學(xué)市場營銷學(xué)易錯題專練
- 新疆2025自考社會工作社會統(tǒng)計學(xué)案例題專練
- 活動三 認(rèn)識可再生能源說課稿-2025-2026學(xué)年小學(xué)綜合實(shí)踐活動滬科黔科版六年級上冊-滬科黔科版
- 2025年歷史中考廣西試卷及答案
- 安徽2025自考金融學(xué)財務(wù)管理學(xué)簡答題專練
- 低空經(jīng)濟(jì)產(chǎn)業(yè)園飛行器運(yùn)行保障方案
- 《發(fā)展?jié)h語中級綜合1》第1課課件
- 《全科醫(yī)師培訓(xùn)眼科》課件
- DB21T 2732-2017 森林防火技術(shù)規(guī)程
- 腦卒中溶栓治療的注意事項
- 2024年高等教育文學(xué)類自考-00504藝術(shù)概論考試近5年真題附答案
- 物理原理在土木工程中的教學(xué)設(shè)計方案
- 網(wǎng)絡(luò)安全意識培訓(xùn)
- 中醫(yī)內(nèi)科學(xué):疾病辨證與中藥治療
- 滇西三部曲:松山戰(zhàn)役筆記
- 保險學(xué)(第五版)課件 附章:社會保險
- GB 5009.12-2023食品安全國家標(biāo)準(zhǔn)食品中鉛的測定
評論
0/150
提交評論