第六章结构体和共用体
在过去的C语言教科书中,结构体称为结构,共用体称为联合,这两种构造类型是C 语言所特有的。它们都是用户自定义的类型,用户可以根据自己的需要构造出各种不同的结构体或共用体类型。Pascal语言虽然没有这两种类型,但却有记录类型和集合类型,其中,记录类型类似于C的结构体。
结构体类型和共用体类型的数据都包含有多个不同成员,对这两种类型的数据一般是按逐个成员进行访问的。对结构体类型的数据,每个成员要求分配不同的存储空间;而共用体类型的数据,则是按最大成员所需的内存空间进行分配,因为每个成员都共用相同一片内存空间。这样,就使得结构体类型的变量可以同时保存各个成员的数据,而共用体在某一时刻只能保留其中一个成员的数据。这是他们之间的根本区别。
利用动态存储分配,可以将同一结构体类型的数据(称为结点)构成一个链表。链表也是一种线性数据结构,其性质类似于数组,但数组要求在编译时就静态分配内存一片连续空间;而链表的构成则是采用动态内存分配,每次分配的结点空间在内存中是可以不连续的。围绕着对链表中数据的处理,也需要研究各种有关链表操作的算法。
【例1】定义一个包括年、月、日的结构体变量,将结构体中年、月、日的值传递给函数days,计算该日在本年中是第几天。
分析:以结构体变量作为函数参数,可以用一个变量一次性将年、月、日数据传递到函数中。闰年的判断可以利用前面介绍过的带参的宏定义。该题还可以利用数组存放各个月份的天数,根据情况再进行累加。
在外部设计宏定义如下:
定义带参的宏 LEAP_YEAR(y) 为 (y%4==0&&y%100!=0||y%400==0)
在外部设计存放年月日的结构体类型如下:
struct date
{int year,month,day;};
函数算法如下:
int days(struct date x)      /*返回值为该年第几天*/
1.h)
{case 1:sum=x.day;break;
case 2:sum=31+x.day;break;
case 3:sum=59+x.day;break;
case 4:sum=90+x.day;break;
case 5:sum=120+x.day;break;
case 6:sum=151+x.day;break;
case 7:sum=181+x.day;break;
case 8:sum=212+x.day;break;
case 9:sum=243+x.day;break;
case 10:sum=273+x.day;break;
case 11:sum=304+x.day;break;
case 12:sum=334+x.day;
}
2.若 (LEAP_ar) 且x.month>2) 则 sum=sum+1;/*闰年增加1天*/
3.返回 sum;
主函数算法如下:
void main( )
1.定义结构体变量d;
2.输入结构体数据年月日:d.year,d.month,d.day;
2.输出days(d);
【例2】编写一个input函数,用于输入5个学生的数据记录;编写一个print函数,用于输出5个学生的数据记录(结构体数组元素包含成员num、name、score[3])。
分析:由于结构体数据的复杂性,一般不能采用scanf进行成功输入。除字符型数据外,其余一律应采用字符串输入,然后再进行转换,以保证数据输入的正确性。
在外部设计存放学生信息的结构体类型如下:
struct stud_type
{long num;
char name[20];
float score[3];
};
函数算法如下:
void input(struct stu_type s[ ],int n)
1.for(i=0;i<n;i++)
1.1.  输入 (numstr);
1.2.  转换为long型:s[i].num=atol(numstr);
1.3.  输入 (s[i].name);
1.4.  for(j=0;j<3;j++)
1.4.1.  输入 (numstr);
1.4.
2.  转换为float型:s[i].score[j]=atof(numstr);
void print(struct stu_type s[ ],int n)
1.for(i=0;i<n;i++)
1.1.  输出s[i].num,s[i].name,s[i].score[0],s[i].score[1],s[i].score[2];
主函数算法如下:
void main( )
1.定义结构体数组stu[5];
2.调用函数input(stu,5) 输入数据;
3.调用函数input(stu,5) 输出数据;
【例3】有一批图书(共5本),每本图书要登记作者姓名、书名、书号、出版年份、价格。试编一程序完成下列任务:1)输入每本书的信息到一个记录数组中;2)打印出价格在20元以上的书号;3)打印出2000年以后出版的书名。
分析:图书信息的数据输入全部采用字符串方式输入,然后再行转换,以保证数据输入
的正确性。5本图书信息存放在book[5]的一维数组中,数组元素的类型是结构体。
设计存放图书信息的结构体类型及数组如下:
struct book_type
{char author[20];
char bookname[20];
long num;
int year;
float price;molloc函数
} book[5];/*全局变量*/
函数算法如下:
struct book_type new_book( )      /*返回值为结构体数据*/
1.定义结构体类型变量:struct book_type book;
2.输入 (book.author);
3.输入 (book.bookname);
4.输入 (numstr);
5.转换为long型:book.num=atol(numstr);
6.输入 (numstr);
7.转换为int型:ar=atoi(numstr);
8.输入 (numstr);
9.转换为float型:book.price=atof(numstr);
10.返回 (book);
void print1( )
1.for (i=0;i<5;i++) /*扫描5本书信息*/
1.1.  若 (book[i].price>20) 则输出 book[i].num;
void print2( )
1.for (i=0;i<5;i++)      /*扫描5本书信息*/
1.1.  若 (book[i].year>2000) 则输出 book[i].bookname;
主函数算法如下:
main( )
1.for (i=0;i<5;i++) /*输入5本书的信息*/
1.1.  book[i]=new_book( );
2.输出表头;
3.调用print1() 输出价格20元以上的书号;
4.输出表头;
5.调用print2() 输出2000年以后出版的书名;
【例4】建立一个链表,每个结点包含成员为:职工号、工资和指针。用malloc函数申请新结点。要求链表包含5个结点,从键盘输入结点的有效数据,然后把这些结点的数据按链表顺序打印出来。要求用函数create来建立链表,用list函数来输出数据。(要求用前插法建立链表)
分析:用前插法建立链表:从空链表开始反方向建立链表,即是先建立链尾结点,至最后建立链头结点,head指针始终指向链头结点。空表时head的值为空指针NULL。create 函数有两种设计:一种是
没有返回值(通过外部指针变量获取该链表);另一种是函数的返回值就是该链表的链头指针。下面介绍第一种方式的设计。
设计结点的结构和指针如下:
struct node
{int num;
float salary;
struct node *next;
} *p,*head;
函数算法如下:
void create(int n)      /*建立含n个结点的链表*/
1.head=NULL;
2.for(i=n;i>=1;i--)
2.1.  申请一个结点:p=(struct node *)malloc(sizeof(struct node));

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。