A. 數組
一.一維數組
一維數組只有一個下標,定義的形式如下:
數據類型說明符 數組名[常量表達式][={初值,初值……}]
各部分說明如下:
(1)“數據類型說明符”說明了數組中各個元素存儲的數據的類型。
(2)“數組名”是整個數組的標識符,它的取名方法與變量的取名方法相同。
(3)“常量表達式”,常量表達式要求取值要爲整型常量,必須用方括號“[]”括起來。用於說明該數組的長度,即該數組元素的個數。
(4)“初值部分”用於給數組元素賦初值,這部分在數組定義時屬於可選項。對數組元素賦值,可以在定義時賦值,也可以定義之後賦值。在定義時賦值,後面須帶等號,初值須用花括號括起來,括號內的初值兩兩之間用逗號間隔,可以對數組的全部元素賦值,也可以只對部分元素賦值。初值爲0的元素可以只用逗號佔位而不寫初值0。
例如:下面是定義數組的兩個例子。
unsigned char x[5];
unsigned int y[3]={1,2,3};
第一句定義了一個無符號字符數組,數組名爲x,數組中的元素個數爲5。
第二句定義了一個無符號整型數組,數組名爲y,數組中元素個數爲3,定義的同時給數組中的三個元素賦初值,賦初值分別爲1、2、3。
需要注意的是,C51語言中數組的下標是從0開始的,因此上面第一句定義的5個元素分別是:x[0]、x[1]、x[2]、x[3]、x[4]。第二句定義的3個元素分別是:y[0]、y[1]、y[2]。賦值情況爲:y[0]=1;y[1]=2;y[2]=3。
C51規定在引用數組時,只能逐個引用數組中的各個元素,而不能一次引用整個數組。但如果是字符數組則可以一次引用整個數組。
【例】用數組計算並輸出Fibonacci數列的前20項。
Fibonacci數列在數學和計算機算法中十分有用。Fibonacci數列是這樣的一組數:第一個數字爲0,第二個數字爲1,之後每一個數字都是前兩個數字之和。設計時通過數組存放Fibonacci數列,從第三項開始可通過累加的方法計算得到。
程序如下:
#include <reg52.h> //包含特殊功能寄存器庫
#include <stdio.h> //包含I/O函數庫
extern serial_initial();
main()
{
int fib[20],i;
fib[0]=0;
fib[1]=1;
serial_initial();
for (i=2;i<20;i++) fib[i]=fib[i-2]+fib[i-1];
for (i=0;i<20;i++)
{
if (i%5= =0) printf(“\n”);
printf(“%6d”,fib[i]);
}
while(1);
}
程序執行結果:
0 1 1 2 3
5 8 13 21 34
55 89 144 233 377
610 987 1597 2584 4148
二.字符數組
用來存放字符數據的數組稱爲字符數組,它是C語言中常用的一種數組。字符數組中的每一個元素都用來存放一個字符,也可用字符數組來存放字符串。字符數組的定義下一般數組相同,只是在定義時把數據類型定義爲char型。
例如:char string1[10];
char string2[20];
上面定義了兩個字符數組,分別定義了10個元素和20個元素。
在C51語言中,字符數組用於存放一組字符或字符串,字符串以“\0”作爲結束符,只存放一般字符的字符數組的賦值與使用和一般的數組完全相同。對於存放字符串的字符數組。既可以對字符數組的元素逐個進行訪問,也可以對整個數組按字符串的方式進行處理。
【例】對字符數組進行輸入和輸出。
#include <reg52.h> //包含特殊功能寄存器庫
#include <stdio.h> //包含I/O函數庫
extern serial_initial();
main()
{
char string[20];
serial_initial();
printf(“please type any character:”);
scanf(“%s”,string);
printf(“%s\n”,string);
while(1);
}
B. 指針
指針是C語言中的一個重要概念。指針類型數據在C語言程序中使用十分普遍,正確地使用指針類型數據,可以有效地表示覆雜的數據結構;可以動態地分配存儲器,直接處理內存地址。
一.指針的概念
瞭解指針的基本概念,先要了解數據在內存中的存儲和讀取方法。
在彙編語言中,對內存單元數據的訪問是通過指明內存單元的地址。訪問時有兩種方式:直接尋址方式和間接尋址方式。直接尋址是通過在指令中直接給出數據所在單元的地址而訪問該單元的數據。例如:MOV A,20H。在指令中直接給出所訪問的內存單元地址20H,訪問的是地址爲20H的單元的數據,該指令把地址爲20H的片內RAM單元的內容送累加器A;間接尋址是指所操作的數據所在的內存單元地址不是通過指令中直接提供,該地址是存放在寄存器中或其它的內存單元中,指令中指明存放地址的寄存器或內存單元來訪問相應的數據。
在C語言中,可以通過地址方式來訪問內存單元的數據,但C語言作爲一種高級程序設計語言,數據通常是以變量的形式進行存放和訪問的。對於變量,在一個程序中定義了一個變量,編譯器在編譯時就在內存中給這個變量分配一定的字節單元進行存儲。如對整型變量(int)分配2個字節單元,對於浮點型變量(float)分配4個字節單元,對於字符型變量分配1個字節單元等。變量在使用時分清兩個概念:變量名和變量的值。前一個是數據的標識,後一個是數據的內容。變量名相當於內存單元的地址,變量的值相當於內存單元的內容。對於內存單元的數據訪問方式有兩種,對於變量也有兩種訪問方式:直接訪問方式和間接訪問方式。
直接訪問方式。對於變量的訪問,我們大多數時候是直接給出變量名。例如:printf(“%d”,a),直接給出變量a的變量名來輸出變量a的內容。在執行時,根據變量名得到內存單元的地址,然後從內存單元中取出數據按指定的格式輸出。這就是直接訪問方式。
間接訪問方式。例如要存取變量a中的值時,可以先將變量a的地址放在另一個變量b中,訪問時先找到變量b,從變量b中取出變量a的地址,然後根據這個地址從內存單元中取出變量a的值。這就是間接訪問。在這裏,從變量b中取出的不是所訪問的數據,而是訪問的數據(變量a的值)的地址,這就是指針,變量b稱爲指針變量。
關於指針,注意兩個基本概念:變量的指針和指向變量的指針變量。變量的指針就是變量的地址。對於變量a,如果它所對應的內存單元地址爲2000H,它的指針就是2000H。指針變量是指一個專門用來存放另一個變量地址的變量,它的值是指針。上面變量b中存放的是變量a的地址,變量b中的值是變量a的指針,變量b就是一個指向變量a的指針變量。
如上所述,指針實質上就是各種數據在內存單元的地址,在C51語言中,不僅有指向一般類型變量的指針,還有指向各種組合類型變量的指針。在本書中我們只討論指向一般變量的指針的定義與引用,對於指向組合類型的指針,大家可以參考其它書籍學習它的使用。
二.指針變量的定義
指針變量的定義與一般變量的定義類似,定義的一般形式爲:
數據類型說明符 [存儲器類型] *指針變量名;
其中:
“數據類型說明符”說明了該指針變量所指向的變量的類型。
“存儲器類型”是可選項,它是C5l編譯器的一種擴展.如果帶有此選項.指針被定義爲基於存儲器的指針。無此選項時,被定義爲一般指針,這兩種指針的區別在於它們佔的存儲字節不同。
下面是幾個指針變量定義的例子:
int * p1; /*定義一個指向整型變量的指針變量p1*/
char * p2; /*定義一個指向字符變量的指針變量p2*/
char data * p3; /*定義一個指向字符變量的指針變量p3,該指針訪問的數據在片內數據存儲器中,該指針在內存中佔一個字節*/
float xdata * p4; /*定義一個指向字符變量的指針變量p4,該指針訪問的數據在片外數據存儲器中,該指針在內存中佔兩個字節*/
三.指針變量的引用
指針變量是存放另一變量地址的特殊變量,指針變量只能存放地址。指針變量使用時注意兩個運算符:&和*。這兩個運算符在前面已經介紹,其中:“&”是取地址運算符,“*”是指針運算符。通過“&”取地址運算符可以把一個變量的地址送給指針變量,使指針變量指向該變量;通過“*”指針運算符可以實現通過指針變量訪問它所指向的變量的值。
指針變量經過定義之後可以象其他基本類型變量一樣引用。例如:
int x,* px,* py; /*變量及指針變量定義*/
px=&x; /*將變量x的地址賦給指針變量px,使px指向變量x*/
* px=5; /*等價於x=5*/
py=px; /*將指針變量px中的地址賦給指針變量py,使指針變量py也指向x*/
【例】輸入兩個整數x與y,經比較後按大小順序輸出。
程序如下:
#include <reg52.h> //包含特殊功能寄存器庫
#include <stdio.h> //包含I/O函數庫
extern serial_initial();
main()
{
int x,y;
int * p,* p1,* p2;
serial_initial();
printf(“input x and y:\n”);
scanf(“%d%d”,&x,&y);
p1=&x;p2=&y;
if (x<y) {p=p1;p1=p2;p2=p;}
printf(“max=%d,min=%d\n”,*p1,*p2);
while(1);
}
程序執行結果:
input x and y:
4 8
max=8,min=4
C. 結構
結構是一種組合數據類型,它是將若干個不同類型的變量結合在一起而形成的一種數據的集合體。組成該集合體的各個變量稱爲結構元素或成員。整個集合體使用一個單獨的結構變量名。
一.結構與結構變量的定義
結構與結構變量是兩個不同的概念,結構是一種組合數據類型,結構變量是取值爲結構這種組合數據類型的變量,相當於整型數據類型與整型變量的關係。對於結構與結構變量的定義有兩種方法。
1.先定義結構類型再定義結構變量
結構的定義形式如下:
struct 結構名
{結構元素表};
結構變量的定義如下:
struct 結構名 結構變量名1,結構變量名2,……;
其中,“結構元素表”爲結構中的各個成員,它可以由不同的數據類型組成。在定義時須指明各個成員的數據類型。
例如,定義一個日期結構類型date,它由三個結構元素year、month、day組成,定義結構變量d1和d2,定義如下:
struct date
{
int year;
char month,day;
}
struct date d1,d2;
2.定義結構類型的同時定義結構變量名
這種方法是將兩個步驟合在一起,格式如下:
struct 結構名
{結構元素表} 結構變量名1,結構變量名2,……;
例如對於上面的日期結構變量d1和d2可以按以下格式定義:
struct date
{
int year;
char month,day;
}d1,d2;
對於結構的定義說明如下:
(1)結構中的成員可以是基本數據類型,也可以是指針或數組,還可以是另一結構類型變量,形成結構的結構,即結構的嵌套。結構的嵌套可以是多層次的,但這種嵌套不能包含其自己。
(2)定義的一個結構是一個相對獨立的集合體,結構中的元素只在該結構中起作用,因而一個結構中的結構元素的名字可以與程序中的其它變量的名稱相同,它們兩者代表不同的對象,在使用時互相不影響。
(3)結構變量在定義時也可以像其它變量在定義時加各種修飾符對它進行說明。
(4)在C51中允許將具有相同結構類型的一組結構變量定義成結構數組,定義時與一般數組的定義相同,結構數組與一般變量數組的不同就在於結構數組的每一個元素都是具有同一結構的結構變量。
二.結構變量的引用
結構元素的引用一般格式如下:
結構變量名.結構元素名
或
結構變量名->結構元素名
其中,“.”是結構的成員運算符,例如:d1.year表示結構變量d1中的元素year,d2.day表示結構變量d2中的元素day等。如果一個結構變量中結構元素又是另一個結構變量,即結構的嵌套,則需要用到若干個成員運算符,一級一級找到最低一級的結構元素,而且只能對這個最低級的結構元素進行引用,形如d1.time.hour的形式。
【例】輸入3個學生的語文、數學、英語的成績,分別統計他們的總成績並輸出。
程序如下:
#include <reg52.h> //包含特殊功能寄存器庫
#include <stdio.h> //包含I/O函數庫
extern serial_initial();
struct student
{
unsigned char name[10];
unsigned int chinese;
unsigned int math;
unsigned int english;
unsigned int total;
}p1[3];
main()
{
unsigned char i;
serial_initial();
printf(“input 3 studend name and result:\n”);
for (i=0;i<3;i++)
{
printf(“input name:\n”);
scanf(“%s”,p1[i].name);
printf(“input result:\n”);
scanf(“%d,%d,%d”,&p1[i].chinese,&p1[i].math,&p1[i].english);
}
for (i=0;i<3;i++)
{
p1[i].total=p1[i].chinese+p1[i].math+p1[i].english;
}
for (i=0;i<3;i++)
{
printf(“%s total is %d”,p1[i].name,p1[i].total);
printf(“\n”);
}
while(1);
}
程序執行結果:
input 3 studend name and result:
input name:
wang
input result:
76,87,69
input name:
yang
input result:
75,77,89
input name:
zhang
input result:
72,81,79
wang total is 232
yang total is 241
zhang total is 232
D. 聯合
前面介紹的結構能夠把不同類型的數據組合在一起使用,另外,在C51語言中,還提供一種組合類型--聯合,也能夠把不同類型的數據組合在一起使用,但它與結構又不一樣,結構中定義的各個變量在內存中佔用不同的內存單元,在位置上是分開的,而聯合中定義的各個變量在內存中都是從同一個地址開始存放,即採用了所謂的“覆蓋技術”。這種技術可使不同的變量分時使用同一內存空間,提高內存的利用效率。
一.聯合的定義
1.先定義聯合類型再定義聯合變量
定義聯合類型,格式如下:
union 聯合類型名
{成員列表};
定義聯合變量,格式如下:
union 聯合類型名 變量列表;
例如:
union data
{
float i;
int j;
char k;
}
union data a,b,c;
2.定義聯合類型的同時定義聯合變量
格式如下:
union 聯合類型名
{成員列表}變量列表;
例如:
union data
{
float i;
int j;
char k;
}data a,b,c;
可以看出,定義時,結構與聯合的區別只是將關鍵字由struct換成union,但在內存的分配上兩者完全不同。結構變量佔用的內存長度是其中各個元素所佔用的內存長度的總和;而聯合變量所佔用的內存長度是其中各元素的長度的最大值。結構變量中的各個元素可以同時進行訪問,聯合變量中的各個元素在一個時刻只能對一個進行訪問。
二.聯合變量的引用
聯合變量中元素的引用與結構變量中元素的引用格式相同,形式如下:
聯合變量名.聯合元素
或
聯合變量名->聯合元素
例如:對於前面定義的聯合變量a、b、c中的元素可以通過下面形式引用。
a.i;
b.j;
c.k;
分別引用聯合變量a中的float型元素i,聯合變量b中的int型元素j,聯合變量c中的char型元素k。
E. 枚舉
枚舉數據類型是一個有名字的某些整型常量的集合。這些整型常量是該類型變量可取的所有的合法值。枚舉定義時應當列出該類型變量的所有可取值。
枚舉定義的格式與結構和聯合基本相同,也有兩種方法。
先定義枚舉類型,再定義枚舉變量,格式如下:
enum 枚舉名 {枚舉值列表};
enum 枚舉名 枚舉變量列表;
或在定義枚舉類型的同時定義枚舉變量,格式如下:
enum 枚舉名 {枚舉值列表}枚舉變量列表;
例如:定義一個取值爲星期幾的枚舉變量d1。
enum week {Sun,Mon,Tue,Wed,Thu,Fri,Sat};
enum week d1;
或
enum week {Sun,Mon,Tue,Wed,Thu,Fri,Sat} d1;
以後就可以把枚舉值列表中各個值賦值給枚舉變量d1進行使用了。