第十章 结构
坚持、积累
机修工只知道修理一种类型的机动车就足够了吗?答案当然是否定的。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页。