
程序代码如下:
#include
int main()
{
struct student
{
int num;
char name[20];
char sex;
char addr[20];
}student1={10101,"Li Lin",'M',"123 Beijing Road"};
printf("NO.: %d\nname: %s\nsex: %c\naddress: %s\n",student1.num,student1.name,student1.sex,student1.addr);
return 0;
}
运行结果如下:
引用结构体变量应遵守以下规则: (1)可以引用结构体变量中成员的值,引用方式为:结构体变量名.成员名“.”是成员运算符,它在所有的运算符中优先级最高,因此可以把studentl.num作为一个整体来看待。
上面赋值语句的作用是将整数10010赋给student1变量中的成员num。
只能对最低级的成员进行赋值或存取以及运算。
student1.num(结构体变量student1中的成员num)
student1.birthday.month (结构体变量student1中的成员birthday中的成员month)
(3)对结构体变量的成员可以像普通变量一样进行各种运算(根据其类型决定可以进行的运算)。
student2.score=student1.score;(赋值运算)
sum=student1.score+student2.score;(加法运算)
student1.age++;(自加运算)
由于“."运算符的优先级最高,因此studentl.age++是对studentl.age进行自加运算,而不是先对age进行自加运算。
student1=student2;//假设student1和student2已定义为同类型的结构体变量
(5)可以引用结构体变量成员的地址,也可以引用结构体变量的地址。
scanf ("&d", &student1.num);(输入student1.num的值)
printf("&o", &student1);(输出结构体变量student1的首地址)
但不能用以下语句整体读入结构体变量,例如:scanf ("d, s, c, d, f, s", &student1);
结构体变量的地址主要用作函数参数,传递结构体变量的地址。
例9.2 输人两个学生的学号、姓名和成绩,输出成绩较高的学生的学号、姓名和成绩。
程序代码如下:
#include
int main()
{
struct student
{
int num;
char name[20];
float score;
}student1,student2;
scanf("%d%s%f",&student1.num,student1.name,&student1.score);
scanf("%d%s%f",&student2.num,student2.name,&student2.score);
//student1.name前面没有&,因为name是数组名,本身就代表地址
printf("The higher score is:\n");
if(student1.score>student2.score)
printf("%d %s %6.2f\n",student1.num,student1.name,student1.score);
else if(student1.score
运行结果如下:
9.2 结构体数组 例9.3 有3个候选人,每个选民只能投票选一人,要求编写一个统计选票的程序,先后输入被选人的名字,最后输出各人得票结果。
程序代码如下:
#include
#include
struct person//声明结构体类型struct person
{
char name[20];//候选人姓名
int count;//候选人得票数
}leader[3]={"Li",0,"Zhang",0,"Fun",0};//定义结构体数组并初始化
int main()
{
int i,j;
char leader_name[20];//定义字符数组
for(i=1;i<=10;i++)
{
scanf("%s",leader_name);//输人所选的候选人姓名
for(j=0;j<3;j++)
if(strcmp(leader_name,leader[j].name)==0) leader[j].count++;
//如果输人的姓名和某一元素中的name成员相同,就给该元素的count成员加1
}
printf("\nResult:\n");
for(i=0;i<3;i++)
printf("%5s:%d\n",leader[i].name,leader[i].count);
//输出数组所有元素中的信息
return 0;
}
运行结果如下:
1.定义结构体数组一般形式是:(1) struct结构体名
{成员表列} 数组名[数组长度];
(2)也可以先声明一个结构体类型(如struct person),然后再用此类型定义结构体数组:
结构体类型 数组名[数组长度];
如:struct person leader[3];//leader是结构体数组名
={初值表列};
如:struct person leader[3]= {"Li",0, "Zhang",0, "Fun", 0};
例9.4 有N个学生的信息(包括学号、姓名、成绩),要求按照成绩的高低顺序输出各学生的信息。
程序代码如下:
#include
#define N 5
struct student
{
int num;
char name[20];
float score;
};
int main()
{
struct student stu[5]={{10101,"zhang",78},{10103,"wang",98.5},
{10106,"li",86},{10108,"ling",73.5},{10110,"fun",100}};
struct student temp;//定义结构体变量temp,用做交换时的临时变量
int i,j,k;
printf("The order is:\n");
for(i=0;istu[k].score)//进行成绩比较
k=j;
temp=stu[k];stu[k]=stu[i];stu[i]=temp;//stu[k]与stu[i]元素整体互换
}
for(i=0;i
运行结果如下:
9.3 结构体指针 所谓结构体指针就是指向结构体数据的指针,一个结构体变量的起始地址就是这个结构体变量的指针。
如果把一个结构体变量的起始地址存放在一个指针变量中,那么,这个指针变量就指向该结构体变量。
指针变量既可以指向结构体变量,也可以用来指向结构体数组中的元素。
指针变量的基类型必须与结构体变量的类型相同。
例如:
struct student *pt; //pt可以指向struct student类型的数据
例9.5 通过指向结构体变量的指针变量输出结构体变量中成员的信息。
程序代码如下:
#include
#include
int main()
{
struct student
{
long num;
char name[20];
char sex;
float score;
};
struct student stu_1;//定义struct student类型的变量stu_1
struct student *p;//定义指向struct student类型数据的指针变量p
p=&stu_1;//p指向结构体变量stu_1
stu_1.num=10101;
strcpy(stu_1.name,"Li Lin");//对结构体变量的name成员赋值
stu_1.sex='M';
stu_1.score=89.5;
printf("No.: %ld\nname: %s\nsex: %c\nscore: %5.1f\n",stu_1.num,
stu_1.name,stu_1.sex,stu_1.score);//输出各成员的值
printf("\nNo.: %d\nname: %s\nsex: %c\nscore: %5.1f\n",(*p).num,
(*p).name,(*p).sex,(*p).score);//输出各成员的值
return 0;
}
运行结果如下:
(*p).num是p指向的结构体变量中的成员num。
注意*p两侧的括号不可省,因为成员运算符“."优先于“*"运算符,*p.num就等价于* (p.num)了。
说明:为了使用方便和使之直观,C语言允许把p->num代替(* p).num,它表示p所指向的结构体变量中的num成员。
同样,p->name等价于(*p).name。
"->"称为指向运算符。
如果p指向一个结构体变量,以下3种形式等价:
①结构体变量.成员名
②(*p).成员名
③p->成员名
指向结构体变量的指针变量,也可以用来指向结构体数组元素。
程序代码如下:
#include
struct student
{
int num;
char name[20];
char sex;
int age;
};
struct student stu[3]={{10101,"Li Lin",'M',18},{10102,"Zhang Fun",'M',19},
{10104,"Wang Min",'F',20}};//定义结构体数组并初始化
int main()
{
struct student *p;//定义指向struct student 结构体变量的指针
printf(" No. Name sex age\n");
for(p=stu;pnum,p->name,p->sex,p->age);
return 0;
}
运行结果如下:
9.4 用结构体变量和结构体变量的指针作为函数参数 将一个结构体变量的值传递给另一个函数,有3个方法:
(1)用结构体变量的成员作参数。
例如,用stu[1].num或stu[2].name作函数实参,将实参值传给形参。
用法和用普通变量作实参是一样的,属于“值传递”方式。
应当注意实参与形参的类型保持一致。
(2)用结构体变量作实参。
用结构体变量作实参时,采取的也是“值传递”的方式,将结构体变量所占的内存单元的内容全部顺序传递给形参,形参也必须是同类型的结构体变量。
在函数调用期间形参也要占用内存单元。
这种传递方式在空间和时间上开销较大,如果结构体的规模很大时,开销是很可观的。
此外,由于采用值传递方式,如果在执行被调用函数期间改变了形参(也是结构体变量)的值,该值不能返回主调函数,这往往造成使用上的不便。
因此一般较少用这种方法。
(3)用指向结构体变量(或数组)的指针作实参,将结构体变量(或数组)的地址传给形参。
例9.7 有N个结构体变量stu,内含学生学号、姓名和3门课程的成绩。
要求输出平均成绩最高的学生的信息(包括学号、姓名、3门课程成绩和平均成绩)。
解题思路:
按照功能函数化的思想,分别用3个函数来实现不同的功能:
(1)用input函数来输入数据和求各学生平均成绩。
(2)用max函数来找平均成绩最高的学生。
(3)用print函数来输出成绩最高学生的信息。
在主函数中先后调用这3个函数,用指向结构体变量的指针作实参,最后得到结果。
程序代码如下:
#include
#define N 3//学生数为3
struct student
{
int num;
char name[20];
float score[3];//三门课成绩
float aver;//平均成绩
};
int main()
{
system("chcp 65001");//加上这句,中文就不会变成乱码
void input(struct student stu[]);//函数声明
struct student max(struct student stu[]);//函数声明
void print(struct student stu);//函数声明
struct student stu[N], *p=stu;//定义结构体数组和指针
input(p);//调用input函数
print(max(p));//调用print函数,以max函数的返回值作为实参
return 0;
}
void input(struct student stu[])//定义input函数
{
int i;
printf("请输入各学生的信息:学号、姓名、三门课成绩:\n");
for(i=0;istu[m].aver) m=i;//找出平均成绩最高的学生在数组中的序号
return stu[m];//返回包含该生信息的结构体元素
}
void print(struct student stud)
{
printf("\n成绩最高的学生是:\n");
printf("学号:%d\n姓名:%s\n三门成绩:%5.1f,%5.1f,%5.1f\n平均成绩:%6.2f\n",
stud.num,stud.name,stud.score[0],stud.score[1],stud.score[2],stud.aver);
}
运行结果如下:
以上3个函数的调用,情况各不相同:
调用input函数时,实参是指针变量p,形参是结构体数组名,传递的是结构体元素的地址,函数无返回值,作用是给stu数组各元素赋予确定的值。
input 函数的形参是struct student类型的数组stu。
用input函数时,将主函数中的stu数组的首元素的地址传给形参数组stu,使形参数组stu与主函数中的stu数组具有相同的地址。
因此在input函数中向形参数组stu输入数据就等于向主函数中的stu数组输入数据。
调用max函数时,实参是指针变量p,形参是结构体数组名,传递的是结构体元素的地址,函数的返回值是结构体类型数据。
stu[m]是一个结构体数组的元素,max函数的类型为struct student类型。
调用print函数时,实参是结构体变量(结构体数组元素),形参是结构体变量,传递的是结构体变量中各成员的值,函数无返回值。
print函数的形参是stud是struct student类型的变量。
结构体变量的一个重要的用途是和指针相结合,构造线性链表。
线性链表就是动态地进行存储分配的一种数据结构。
链表中的各元素称为“结点”,每个结点都应包括两个部分:用户需要用的实际数据和下一个结点的地址。
直到最后一个结点,该结点不再指向其他结点,它称为“表尾”,它的地址部分放一个“NULL”(表示“空地址”),链表到此结束,可以看到链表中各结点在内存中的地址可以是不连续的。
链表这种数据结构,必须利用结构体变量和指针变量才能实现。
在一个结点中包含两个部分:数据部分和一个指针变量(该指针变量存放下一结点的起始地址)
struct student
{int num;
float score;
struct student * next;//next成员是指针变量
};
next是指针类型的成员。
为了构造链表,应当把next定义为指向structstudent类型数据的指针变量。
这时,next既是struct student类型中的一个成员,又指向structstudent类型的数据,见图9.9。
输出各结点中的数据。
程序代码如下:
#include
#define NULL 0
struct student
{
int num;
float score;
struct student *next;
};
int main()
{
struct student a,b,c,*head,*p;//定义3个结构体变量作为链表的结点
a.num=10101;a.score=89.5;//对结点a的num和score成员赋值
b.num=10103;b.score=90;//对结点b的num和score成员赋值
c.num=10107;c.score=85;//对结点c的num和score成员赋值
head=&a;//将结点a的起始地址赋给头指针head
a.next=&b;//将结点b的起始地址赋给a结点的next成员
b.next=&c;//将结点c的起始地址赋给a结点的next成员
c.next=NULL;//c结点的next成员不存放其他结点地址
p=head;//使p也指向a结点
do
{printf("%ld %5.1f\n",p->num,p->score);//输出p指向的结点的数据
p=p->next;//使p指向下一个结点
}while(p!=NULL);//输出完c结点后p的值为NULL,循环终止
return 0;
}
运行结果如下:
建立动态链表是指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输人各结点数据,并建立起前后相连的关系。
解题思路:
(1)定义结构体变量,其成员包括学号、成绩和指针变量。
(2)动态地开辟一个新单元(动态开辟内存单元用malloc函数)。
使指针变量p和head指向此结点。
(3)向此结点输入数据。
(4)再开辟第2个新结点,并使指针变量p指向此结点。
(5)使第2个结点中的指针变量的值为NULL,即不指向任何对象,链表到此为止。
(6)输出两个结点中的数据。
程序代码如下:
#include
#include //用malloc函数开辟新单元时需用此头文件
#define LEN sizeof(struct student)//LEN代表struct student类型数据的字节数
struct student
{
int num;
float score;
struct student *next;//指针变量成员
};
int main()
{
struct student *head, *p;//定义指针变量head和p
//建立链表
head=p=(struct student * ) malloc(LEN);//开辟一个新单元,并让p和head指向它
scanf("%d,%f",&p->num,&p->score);//输入第一个结点的数据
p=(struct student *) malloc(LEN);//开辟第二个新单元,并让p指向它
scanf("%d,%f",&p->num,&p->score);//输入第二个结点数据
head->next=p;//使第1个结点中的next成员指向第2个结点
p->next=NULL;//使第2个结点中的next成员不指向任何对象
// 输出两结点中的数据
p=head;//使p指向第一个结点
printf("\n结点 1:%d,%6.2f\n",p->num,p->score);
p=p->next;//使p指向第二个结点
printf("结点 2:%d,%6.2f\n",p->num,p->score);
return 0;
}
运行结果如下:
共用体类型:
使几个不同类型的变量共占同一段内存的结构,称为“共用体"类型的结构。
定义共用体类型变量的一般形式为:
union 共用体名
{成员表列
}变量表列;
结构体变量所占内存长度是各成员占的内存长度之和。
每个成员分别占有其自己的内存单元。
而共用体变量所占的内存长度等于最长的成员的长度。
如果一个变量只有几种可能的值,则可以定义为枚举类型。
所谓“枚举”是指将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。
声明枚举类型用enum开头。
enum weekday {sun, mon, tue, wed, thu, fri, sat};
workday=mon;
week_end=sun;
enum {sun, mon, tue, wed, thu, fri, sat} workday, week_end;//直接定义枚举变量
中sun, mon,,sat称为枚举元素或枚举常量。
它们是用户定义的标识符。
workday和week_end被定义为枚举变量,它们的值只能是sun到sat之一。
每次从口袋中先后取出3个球,问得到3种不同色的球的可能排列,输出每种排列的情况。
解题思路:球只能是5种色之一,而且要判断各球是否同色,应该用枚举类型变量处理。
设取出的球为i、j、k。
根据题意,i、j、k分别是5种色球之一,并要求i≠j≠k。
可以用穷举法,即把每一种排列都试一下,看哪一组符合条件。
算法可用图9.12表示。
用n累计得到3种不同色球的次数。
外循环使第1个球i从red变到black。
中循环使第2个球j也从red变到black。
如果i和j同色则不可取,只有i和j不同色(i≠j)时才需要继续找第3个球,此时第3个球k也有5种可能(red到black),但要求第3个球不能与第1个球或第2个球同色,即k≠i,k≠j。
满足此条件就得到3种不同色的球。
输出这种3色组合方案,然后使n加1。
外循环全部执行完后,全部方案就已输出完了。
最后输出总数n。
下面的问题是如何实现图9.12中的“输出一种取法”,可以采用图9.13的方法。
为了输出3个球的颜色,显然应经过3次循环,第1次输出i的颜色,第2次输出j的颜色,第3次输出k的颜色。
在3次循环中先后将i、j、k赋予pri。
然后根据pri的值输出颜色信息。
在第1次循环时,pri的值为i,如果i的值为red,则输出字符串"red”,其余类推。
程序代码如下:
#include
int main()
{
enum color {red,yellow,blue,white,black};//声明枚举类型color
enum color i,j,k,pri; int n,loop;//定义枚举变量
n=0;
for(i=red;i<=black;i++)//逐个检查是否符合条件
for(j=red;j<=black;j++)
if(i!=j)
{
for(k=red;k<=black;k++)
if((k!=i) && (k!=j))
{
n=n+1;
printf("%-4d",n);
for(loop=1;loop<=3;loop++)
{
switch (loop)
{
case 1:pri=i;break;
case 2:pri=j;break;
case 3:pri=k;break;
default:break;
}
switch (pri)
{
case red:printf("%-10s","red");break;
case yellow:printf("%-10s","yellow");break;
case blue:printf("%-10s","blue");break;
case white:printf("%-10s","white");break;
case black:printf("%-10s","black");break;
default :break;
}
}
printf("\n");
}
}
printf("\ntotal:%5d\n",n);
return 0;
}
运行结果如下:
······
枚举类型是把可能的值全部一一列出,枚举变量的值只能是其中之一。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)