第十章 結構
堅持、積累
機修工隻知道修理一種類型的機動車就足夠了嗎?答案當然是否定的。C語言也是如此,如果它隻能處理所有的整型數、浮點型數或字元,它就不會那麼一直受歡迎。事實上,在處理真實資料時,常常并不處理它們本身的一些小細節(如整數、字元串等),相反,是要處理集合了一些屬性的實體,每一個實體都有它自己的屬性,如我們稱為“書”的實體,就是由書名、作者、電話号碼、出版社、頁數、出版日期等這樣一些屬性組成的集合。當然你肯定知道,這些資料都不相同,例如,作者可以是字元串,而書的頁數是整數。
那麼,為了處理這種集合,C語言提供了一種稱為“結構”的資料類型。結構将組成實體的不同資訊元素聚集在一起。是以呢,這一章讨論的主題就是結構。
10.1為什麼要使用結構?
舉個例子來說,假設你想要存儲一本書的資料,你可能需要儲存數的書名(一個字元串)、書的價格(浮點型數)和書的頁數(整型數),等等等…,
可以采用如下兩種方法:
●構造獨立的數組,一個存儲書名,一個存儲書的價格,一個存儲書的頁數,一個存儲…(哎…這種方法确實是太麻煩了)。
●使用一個結構變量。
10.2 結構是一種包含了許多資料類型的結合。舉個小例子。
#include <stdio.h>
int main(void)
{
struct book
{
char name;
float price;
int pages;
};
struct book b1,b2,b3;
printf("\nEnter names,prices&no. of pages of 3 books\n");
scanf("%c %f %d",&b1.name,&b1.price,&b1.pages);
scanf("%c %f %d",&b2.name,&b2.price,&b2.pages);
scanf("%c %f %d",&b3.name,&b3.price,&b3.pages);
printf("\nAnd this is what you entered");
printf("\n%c %f %d",b1.name,b1.price,b1.pages);
printf("\n%c %f %d",b2.name,b2.price,b2.pages);
printf("\n%c %f %d",b3.name,b3.price,b3.pages);
system("pause");
}
注意一下,下面這兩種是一樣的:
●struct book
{
char name;
float price;
int pages;
};
struct book b1,b2,b3;
●struct book
{
char name;
float price;
int pages;
}b1,b2,b3;
10.3 與普通變量和數組一樣,結構變量也可以在聲明的時候進行初始化。
struct book
{
char name[10];
float price;
int pages;
};
struct book b1={"Basic",130.00,550};
struct book b2={"Physics",150.80,800};
struct book b3={0};(如果一個結構變量被初始化為一個值{0},那麼所有的元素都被設定為0)
10.4通路結構元素很簡單,b1.pages,b1.price這樣就可以了,哈哈。
10.5 結構數組
為什麼要使用結構數組呢?想一想這種情況,如果要存儲100本書的資料,就需要用100個不同的結構變量,從b1到b100,這樣定義的時候好像很不友善。使用結構數組的方法會更好一些。例如:
#include <stdio.h>
int main(void)
{
struct book
{
char name;
float price;
int pages;
};
struct book b[100];
int i;
for(i=0;i<=99;i++)
{
printf("\nEnter name,price,and pages");
scanf("%c%f%d",&b[i].name,&b[i].price,&b[i].pages);
}
for(i=0;i<=99;i++)
{
printf("\n%c%f%d",b[i].name,b[i].price,b[i].pages);
}
}
linkfloat()
{
float a=0,*b;
b=&a;
a=*b;
}
幾點說明:
●函數linkfloat()在這裡起什麼作用?顧名思義,連接配接浮點型數,暫且這麼了解吧,因為本程式中用scanf()函數來讀取結構數組中的float型數。是以要使用函數linkfloat()。
●我們應該感謝Dennis Ritchie将這麼細緻的想法放到了C語言中,Dennis Ritchie不愧是一個天才。
從第10.6開始,我們來詳細讨論一下結構的其它特性。
10.6 結構變量可以通過指派運算符将其值賦給另一個相同類型的結構變量。不需要一個一個地去複制結構元素。但是呢,程式員好像更喜歡一個一個地複制元素的值。例如:
#include <stdio.h>
#include <string.h>
int main(void)
{
struct employee
{
char name[10];
int age;
float salary;
};
struct employee e1={"Sanjay",30,5500.50};
struct employee e2,e3;
strcpy(e2.name,e1.name);
e2.age=e1.age;
e2.salary=e1.salary;
e3=e2;
printf("\n%s %d %f",e1.name,e1.age,e1.salary);
printf("\n%s %d %f",e2.name,e2.age,e2.salary);
printf("\n%s %d %f",e3.name,e3.age,e3.salary);
system("pause");
}
小思考:如果要逐個元素來複制結構變量的話,結構還會受歡迎嗎?
10.7 一個結構可以嵌套在另一個結構中。例如:
#include <stdio.h>
#include <string.h>
int main(void)
{
struct address
{
char phone[15];
char city[25];
int pin;
};
struct emp
{
char name[25];
struct address a;
};
struct emp e={"jeru","531046","nagpur",10};
printf("\nname=%s phone=%s",e.name,e.a.phone);
printf("\ncity=%s pin=%d",e.a.city,e.a.pin);
system("pause");
}
當然,嵌套過程不應該隻停留在這個水準,應該多練練,可以将結構嵌套在結構中,在将這個嵌套的結構嵌套到另一個結構中。如此嵌套下去,知道我們還能了解自己定義的結構。可是呢,這種結構會引起變量自我描述出奇的多,如:
maruti.engine.bole.large.qty
10.8 跟一個普通變量一樣,結構變量也可以傳遞給函數。即可以傳遞單獨的結構成員,也可以一次傳遞整個結構變量。下面分别來了解這兩種方法。
方法一:傳遞單獨的結構成員
#include <stdio.h>
void display(char *,char *,int);
int main(void)
{
struct book
{
char name[25];
char author[25];
int callno;
};
struct book b1={"Let us C","YPK",102};
display(b1.name,b1.author,b1.callno);
}
void display(char *s,char *t,int n)
{
printf("\n%s %s %d",s,t,n);
system("pause");
}
方法二:傳遞整個結構變量(★★★★★)
#include <stdio.h>
struct book
{
char name[25];
char author[25];
int callno;
};
void display(struct book);
int main(void)
{
struct book b1={"Let us C","YPK",101};
display(b1);
system("pause");
}
void display(struct book b)
{
printf("\n%s %s %d",b.name,b.author,b.callno);
}
一點說明:由于struct book的資料類型對函數display()來說是未知的。是以,必須要在main()函數外面聲明結構類型struct book,使該結構對程式中的所有函數成為已知的資料類型。
10.9 可以有指向int型的指針,或者指向char型指針。類似的,也可以有指向struct型的指針。這種指針成為“結構指針”。例如:
#include <stdio.h>
int main(void)
{
struct book
{
char name[25];
char author[25];
int callno;
};
struct book b1={"Let us C","YPK",101};
struct book *ptr;
ptr=&b1;
printf("\n%s %s %d",b1.name,b1.author,b1.callno);
printf("\n%s %s %d",ptr->name,ptr->author,ptr->callno);
system("pause");
}
10.10 能不能把一個結構變量的位址傳給函數呢?當然可以。(注意與第7點中的方法二對比)
#include <stdio.h>
struct book
{
char name[25];
char author[25];
int callno;
};
void display(struct book *);
int main(void)
{
struct book b1={"Let us C","YPK",101};
display(&b1);
system("pause");
}
void display(struct book *b)
{
printf("\n%s %s %d",b->name,b->author,b->callno);
}
10.11 結構的使用還有其他很多很多,如#pragma pack、改變光标大小、清楚螢幕内容、在螢幕上繪制任意形狀的圖檔…,詳情參考《Let us C》(第八版)220頁。