书上典型例题总结:
如何去定义一个结构体数组:
#include<stdio.h>
#include<string.h>
struct Person
{
char name[20];
int count;
}leader[3]={"Li",0,"Zhang",0,"Sun",0};
int main()
{
int i,j;
char leader_name[20];
for (i=1;i<=10;i++)
{
scanf("%s",leader_name);
for(j=0;i<3;i++)
if(strcmp(leader_name,leader[j].name)==0)leader[j].count++;
}
printf("\nResult:\n");
for(i=0;i<3;i++)
printf("%5s:%d\n",leader[i].name,leader[i].count);
return 0;
}
指向结构体变量的指针:
#include<stdio.h>
#include<string.h>
int main()
{
struct Student
{
long num;
char name[20];
char sex;
float score;
};
struct Student_stu_1;
struct Student*p;
p=stu&_1; //p指向stu_1
stu_1.num=10101;
strcpy(stu_1.name,"Li Lin");
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("No.:%ld\nname:%s\nsex:%c\nscore:%5.1f\n");
(*p).num,(*p).name,(*p).sex,(*p).score); //(*p)表示p指向的结构体变量,(*p).num表示p所指向的结构体变量中的成员num。注意*两侧的括号不可省,因为成员运算符“.”优先于“*”运算符
return 0;
}
如果p指向一个结构体变量stu,以下三种用法等价
(1)stu.成员名(如stu.num);
(2)(*p).成员名(如(*p).num);
(3)p->成员名(如p->num)。
306页例9.7:
学生成绩管理系统
#include<stdio.h>
#include<stdlib.h>
#include<stdlib.h>
#include<string.h>
struct Student{ //每个学生对应一个结构体
char ID[20];//学号
char Name[10];//姓名
float Mark1;//语文成绩
float Mark2;//数学成绩 //四个变量
float Mark3;//英语成绩
float Mark4;//计算机成绩
float All; //总分
float Average;//平均成绩
}students[1000];
int num=0; //计数器
void Copy(struct Student *arr,int i,int j)
{
strcpy(arr[i].ID,arr[j].ID); //strcpy()函数的简介:
是将一个字符串复制到另一块空间地址中 的函数,‘\0’是停止拷贝的终止条件,
也复制到目标空间。下面是库中的strcpy()函数声明:
strcpy(arr[i].Name,arr[j].Name);
arr[i].Mark1 = arr[j].Mark1;
arr[i].Mark2 = arr[j].Mark2;
arr[i].Mark3 = arr[j].Mark3;
arr[i].Mark4 = arr[j].Mark4;
arr[i].All = arr[j].All;
arr[i].Average = arr[j].Average;
}
int Student_SearchByName(char name[])//通过姓名来检索学生
{
int i;
for (i=0;i<num;i++)
{
if (strcmp(students[i].Name,name)==0) //通过strcmp函数来对比学生姓名,找到返回在数组的位置
{
return i;
}
}
return -1; //未找到返回 -1
}
int Student_SearchByIndex(char id[])//通过学号来检索学生信息
{
int i;
for (i=0;i<num;i++)
{
if (strcmp(students[i].ID,id)==0) //通过strcmp函数来对比学生id,找到返回位置
{
return i;
}
}
return -1; //未找到返回 -1
}
void Student_DisplaySingle(int index)//输出表头
{
printf("%10s%10s%8s%8s%8s%10s\n","学号","姓名","语文","数学","英语","计算机","总成绩","平均成绩");
printf("-------------------------------------------------------------\n");
printf("%10s%10s%8.2f%8.2f%8.2f%8.2f%10.2f%10.2f\n",students[index].ID,students[index].Name,
students[index].Mark1,students[index].Mark2,students[index].Mark3,students[index].Mark4,students[index].All,students[index].Average);
}
void inputt()//利用循环录入学生信息
{
while(1)
{
printf("请输入学号:");
scanf("%s",&students[num].ID);
getchar();
printf("请输入姓名:");
scanf("%s",&students[num].Name);
getchar();
printf("请输入成绩:");
scanf("%f",&students[num].Mark1);
getchar();
printf("请输入成绩:");
scanf("%f",&students[num].Mark2);
getchar();
printf("请输入成绩:");
scanf("%f",&students[num].Mark3);
getchar();
printf("请输入成绩:");
scanf("%f",&students[num].Mark4); //依次输入各项数据
getchar();
students[num].All=students[num].Mark1+students[num].Mark2+students[num].Mark3+students[num].Mark4; //输完数据后自动计算总成绩与平均成绩
students[num].Average=(students[num].Mark1+students[num].Mark2+students[num].Mark3+students[num].Mark4)/4;
if(Student_SearchByIndex(students[num].ID) == -1)
{
num++; //移向下一个位置
}
else
{
printf("学号重复,输入数据无效 !!!\n");
}
printf("是否继续?(y/n)");
if (getchar()=='n')
{
break;
}
}
}
void modify()//修改成绩
{
while(1)
{
char id[20];
int index;
printf("请输入要修改的学生的学号:");
scanf("%s",&id);
getchar();
index=Student_SearchByIndex(id); //调用搜查id函数,根据其返回值确定位置
if (index==-1)
{
printf("学生不存在!\n");
}
else
{
printf("你要修改的学生信息为:\n");
Student_DisplaySingle(index);
printf("-- 请输入新值--\n");
printf("请输入学号:");
scanf("%s",&students[index].ID);
getchar();
printf("请输入姓名:");
scanf("%s",&students[index].Name);
getchar();
printf("请输入语文成绩:");
scanf("%f",&students[index].Mark1);
getchar();
printf("请输入数学成绩:");
scanf("%f",&students[index].Mark2);
getchar();
printf("请输入英语成绩:");
scanf("%f",&students[index].Mark3);
getchar();
printf("请输入计算机成绩:");
scanf("%f",&students[index].Mark4); //重新录入一套新的数据替代
getchar();
students[index].All=students[index].Mark1+students[index].Mark2+students[index].Mark3+students[index].Mark4;
students[index].Average=(students[index].Mark1+students[index].Mark2+students[index].Mark3+students[index].Mark4)/4;
}
printf("是否继续?(y/n)");
if (getchar()=='n')
{
break;
}
}
}
void deletee()//删除学生信息
{
int i;
while(1)
{
char id[20];
int index;
printf("请输入要删除的学生的学号:");
scanf("%s",&id);
getchar();
index=Student_SearchByIndex(id); //调用搜查id函数,根据其返回值确定位置
if (index==-1)
{
printf("学生不存在!\n");
}
else
{
printf("你要删除的学生信息为:\n");
Student_DisplaySingle(index);
printf("是否真的要删除?(y/n)");
if (getchar()=='y')
{
for (i=index;i<num-1;i++)
{
Copy(students,i,i+1);
//students[i]=students[i+1]; //把后边的对象都向前移动
}
num--;
}
getchar();
}
printf("是否继续?(y/n)");
if (getchar()=='n')
{
break;
}
}
}
void display()//打印已录入的学生信息
{
int a;
printf("%10s%10s%8s%8s%8s%8s%10s%10s\n","学号","姓名","语文","数学","英语","计算机","总成绩","平均成绩");
printf("-------------------------------------------------------------\n");
for (a=0;a<num;a++)
{
printf("%10s%10s%8.2f%8.2f%8.2f%8.2f%10.2f%10.2f\n",students[a].ID,students[a].Name,
students[a].Mark1,students[a].Mark2,students[a].Mark3,students[a].Mark4,students[a].All,students[a].Average);
}
}
void insert()//指定位置插入学生信息
{
int a,b,c;
printf("请输入你要插入的位置");
scanf("%d",&a);
if(a>num) {
printf("输入的位置有误,请重新输入,当前共%d条数据\n",num);
scanf("%d",&a);}
b=num-1;
for(;b>=a-1;b--)
{
//strcpy(students[b+1].ID,students[b].ID);
//strcpy(students[b+1].Name,students[b].Name);
//students[b+1].Mark1=students[b].Mark1;
//students[b+1].Mark2=students[b].Mark2;
//students[b+1].Mark3=students[b].Mark3;
//students[b+1].Mark4=students[b].Mark4;
//students[b+1].All=students[b].All;
//students[b+1].Average=students[b].Average;
Copy(students,b+1,b); //根据其输入的位置,将其及以后的数据向后移动一个位置
}
num++;
printf("请输入学号:");
scanf("%s",&students[a-1].ID);
getchar();
printf("请输入姓名:");
scanf("%s",&students[a-1].Name);
getchar();
printf("请输入语文成绩:");
scanf("%f",&students[a-1].Mark1);
getchar();
printf("请输入数学成绩:");
scanf("%f",&students[a-1].Mark2);
getchar();
printf("请输入英语成绩:");
scanf("%f",&students[a-1].Mark3);
getchar();
printf("请输入计算机成绩:");
scanf("%f",&students[a-1].Mark4); //输入新数据
getchar();
students[a-1].All=students[a-1].Mark1+students[a-1].Mark2+students[a-1].Mark3+students[a-1].Mark4;
students[a-1].Average=(students[a-1].Mark1+students[a-1].Mark2+students[a-1].Mark3+students[a-1].Mark4)/4;
}
void search()//查询学生信息
{
while(1)
{
char name[20];
int index;
printf("请输入要查询的学生的姓名:");
scanf("%s",&name);
getchar();
index=Student_SearchByName(name); //调用搜查name函数,根据其返回值确定位置
if (index==-1)
{
printf("学生不存在!\n");
}
else
{
printf("你要查询的学生信息为:\n");
Student_DisplaySingle(index);
}
printf("是否继续?(y/n)");
if (getchar()=='n')
{
break;
}
}
}
voidsort()//根据平均分排序
(此时注意按照题目要求应该排序两个)
{
int i,j;
//struct students tmp;
for (i=0;i<num;i++)
{
students[i].Average=(students[i].Mark1+students[i].Mark2+students[i].Mark3+students[i].Mark4)/4;
}
for (i=0;i<num;i++)
{
for (j=1;j<num-i;j++)
{
if (students[j-1].Average<students[j].Average)
{
Copy(students,num,j-1);
Copy(students,j-1,j);
Copy(students,j,num);
//tmp=students[j-1];
//students[j-1]=students[j];
//students[j]=tmp; //冒泡排序
}
}
}
int a;
printf("%10s%10s%8s%8s%8s%10s\n","学号","姓名","语文","数学","英语","计算机","总成绩","平均成绩");
printf("-------------------------------------------------------------\n");
for (a=0;a<num;a++)
{
printf("%10s%10s%8.2f%8.2f%8.2f%8.2f%10.2f%10.2f\n",students[a].ID,students[a].Name,
students[a].Mark1,students[a].Mark2,students[a].Mark3,students[a].Mark4,students[a].All,students[a].Average);
}
}
void SearchLow()//搜索不及格的并输出
{
int a;
printf(" 语文不及格的有%10s%10s%8s\n","学号","姓名","语文");
for(a=0;a<num;a++)
{
if(students[a].Mark1<60)
printf("%10s%10s%8.2f\n",students[a].Name,students[a].ID,students[a].Mark1); //从头搜索到尾,若小于60就输出
}
printf(" 数学不及格的有%10s%10s%8s\n","学号","姓名","数学");
for(a=0;a<num;a++)
{
if(students[a].Mark2<60)
printf("%10s%10s%8.2f\n",students[a].Name,students[a].ID,students[a].Mark2);
}
printf(" 英语不及格的有%10s%10s%8s\n","学号","姓名","英语");
for(a=0;a<num;a++)
{
if(students[a].Mark3<60)
printf("%10s%10s%8.2f\n",students[a].Name,students[a].ID,students[a].Mark3);
}
printf(" 计算机不及格的有%10s%10s%8s\n","学号","姓名","计算机");
for(a=0;a<num;a++)
{
if(students[a].Mark4<60)
printf("%10s%10s%8.2f\n",students[a].Name,students[a].ID,students[a].Mark4);
}
system("pause"); //这个好像没作用
}
void SearchHigh()//搜索成绩最高者输出
{
int a;
int max ;
printf(" 语文最高分为%10s%10s%8s\n","学号","姓名","语文");
max=students[0].Mark1;
for(a=1;a<num;a++)
{
if(students[a].Mark1>max)
max=students[a].Mark1;
}
for(a=0;a<num;a++)
{
if(max==students[a].Mark1)
printf("%10s%10s%8.2f\n",students[a].Name,students[a].ID,students[a].Mark1);
}
printf(" 数学最高分为%10s%10s%8s\n","学号","姓名","数学");
max=students[0].Mark2;
for(a=1;a<num;a++)
{
if(students[a].Mark2>max)
max=students[a].Mark2;
}
for(a=0;a<num;a++)
{
if(max==students[a].Mark2)
printf("%10s%10s%8.2f\n",students[a].Name,students[a].ID,students[a].Mark2);
}
printf(" 英语最高分为%10s%10s%8s\n","学号","姓名","英语");
max=students[0].Mark3;
for(a=1;a<num;a++)
{
if(students[a].Mark3>max)
max=students[a].Mark3;
}
for(a=0;a<num;a++)
{
if(max==students[a].Mark3)
printf(" %10s%10s%8.2f\n",students[a].Name,students[a].ID,students[a].Mark3);
}
printf(" 计算机最高分为%10s%10s%8s\n","学号","姓名","计算机");
max=students[0].Mark4;
for(a=1;a<num;a++)
{
if(students[a].Mark4>max)
max=students[a].Mark4;
}
for(a=0;a<num;a++)
{
if(max==students[a].Mark4)
printf(" %10s%10s%8.2f\n",students[a].Name,students[a].ID,students[a].Mark4);
}
system("pause");
}
void Save()
{
FILE*fp = fopen("temp.txt","w+");
fprintf(fp,"%d\n",num);
for(int i = 0 ; i< num ;i++)
{
fprintf(fp,"%s %s %f %f %f %f %f %f\n",students[i].ID,students[i].Name,students[i].Mark1,students[i].Mark2,students[i].Mark3,students[i].Mark4,students[i].All,students[i].Average);
}
fclose(fp);
}
void Load()
{
FILE*fp = fopen("temp.txt","r");
fscanf(fp,"%d",&num);
for(int i = 0 ; i< num ;i++)
{
fscanf(fp,"%s %s %f %f %f %f %f %f\n",students[i].ID,students[i].Name,&students[i].Mark1,&students[i].Mark2,&students[i].Mark3,&students[i].Mark4,&students[i].All,&students[i].Average);
}
fclose(fp);
}
/*主程序*/
int main(){
int i;
while(1){
Load();
printf("\t\t\t\t\t-------- 学生成绩管理系统-------\n\n\n\n"); //菜单
printf("\t\t\t\t\t1. 增加学生记录\n\n");
printf("\t\t\t\t\t2. 修改学生记录\n\n");
printf("\t\t\t\t\t3. 删除学生记录\n\n");
printf("\t\t\t\t\t4. 插入学生记录\n\n");
printf("\t\t\t\t\t5. 显示所有记录\n\n");
printf("\t\t\t\t\t6. 查询学生记录\n\n");
printf("\t\t\t\t\t7. 按平均成绩排序\n\n");
printf("\t\t\t\t\t8. 输出各科目不及格学生\n\n");
printf("\t\t\t\t\t9. 输出各科目最高分\n\n");
printf("\t\t\t\t\t0. 退出\n\n\n");
printf("请选择(0-9):");
scanf("%d",&i);
switch(i){
case 1:inputt();break;
case 2:modify();break;
case 3:deletee();break;
case 4:insert();break;
case 5:display();break;
case 6:search();break;
case 7:sort();break;
case 8:SearchLow();break;
case 9:SearchHigh();break;
case 0:exit(0);
default: ;
}
Save();
}
return 0;
}
void Save() {
FILE *fp = fopen("temp.txt", "w+");
fprintf(fp, "%d\n", num);
for (int i = 0 ; i < num ; i++) {
fprintf(fp, "%s %s %f %f %f %f %f %f\n", students[i].ID, students[i].Name, students[i].Mark1, students[i].Mark2,
students[i].Mark3, students[i].Average1);
}
fclose(fp);
}
void Load() {
FILE *fp = fopen("temp.txt", "r");
fscanf(fp, "%d", &num);
for (int i = 0 ; i < num ; i++) {
fscanf(fp, "%s %s %f %f %f %f %f %f\n", students[i].ID, students[i].Name, &students[i].Mark1, &students[i].Mark2,
&students[i].Mark3, &students[i].Average1);
}
fclose(fp);
}
调试示例error09_1.cpp(结构)
输入一个正整数n(3≤n≤10),再输入n个雇员的信息,包括姓名、基本工资、浮动工资和支出,输出每人的姓名和实发工资,实发工资=基本工资+浮动工资-支出。
输入输出示例:括号内为说明
输入:
3 (n=3)
zhao 240 400 75
qian 360 120 50
zhou 560 0 80
输出:
zhao 实发工资: 565.00
qian 实发工资: 430.00
zhou 实发工资: 480.00
#include <stdio.h>
int main (void)
{
int i, n;
struct emp{
char name[10];
double jbg;
double fdg;
double zc;
} s[10];
scanf("%d", &n);
for(i=0;i<n;i++)
scanf("%s%lf%lf%lf",s[i].name, &s[i].jbg,&s[i].fdg,&s[i].zc);
for (i = 0; i < n; i++)
printf ("%5s 实发工资:%7.2f\n", s[i].name, s[i].jbg + s[i].fdg - s[i].zc);
}
90002 时间换算(结构)
输入一个正整数 repeat (0<repeat<10),做 repeat 次下列运算:
输入一个时间数值,再输入秒数 n,输出该时间再过 n 秒后的时间值,时间的表示形式为时:分:秒,超过 24 时从 0 时重新开始计时。
输入输出示例:括号内为说明
输入:
3 (repeat=3)
0:0:1
59 (秒数n=59)
11:59:40
30 (秒数n=30)
23:59:40
301 (秒数n=301)
输出:
time: 0:1:0 (0:0:01加上59秒的新时间)
time: 12:0:10 (11:59:40加上30秒的新时间)
time: 0:4:41 (23:59:40加上301秒的新时间)
#include <stdio.h>
int main(void)
{
int n;
int repeat, ri;
struct time{
int hour, minute, second;
}time;
scanf("%d", &repeat);
for(ri = 1; ri <= repeat; ri++){
scanf("%d:%d:%d", &time.hour, &time.minute, &time.second);
scanf("%d",&n);
time.second=time.second+n;
if(time.second>=60){
time.minute=time.minute+time.second/60;
time.second=time.second%60;
if(time.minute>=60){
time.hour=time.hour+time.minute/60;
time.minute=time.minute%60;
if(time.hour>=24)
time.hour=time.hour-24;
}
}
printf("time: %d:%d:%d\n", time.hour, time.minute, time.second);
}
}
90003 计算平均成绩(结构)
输入整数n(n<10),再输入n个学生的基本信息,包括序号、姓名和成绩,要求计算并输出他们的平均成绩(保留2位小数)。
输入输出示例:括号内为说明
输入:
3 (n=3)
1 zhang 70
2 wang 80
3 qian 90
输出:
average: 80.00
#include <stdio.h>
int main(void)
{
int i, n;
double average, sum;
struct student{
int num;
char name[10];
int score;
}s[10];
scanf("%d", &n);
sum=0;
for(i=0;i<n;i++){
scanf("%d%s%d",&s[i].num,s[i].name,&s[i].score);
sum+=s[i].score;
}
average=sum/n;
printf("average: %.2f\n", average);
}
90004 计算两个复数之积(结构)
输入4个整数a1,b1,a2,b2,分别表示两个复数的实部与虚部,求两个复数之积(a1+b1i)*(a2+b2i),乘积的实部为:a1*a2-b1*b2,虚部为:a1*b2+a2*b1。
输入输出示例:括号内为说明
输入:
3 4 5 6
输出:
(3+4i) * (5+6i) = -9 + 38i
#include <stdio.h>
int main(void)
{
struct complex{
int real;
int imag;
}product, x, y;
scanf("%d%d%d%d", &x.real, &x.imag, &y.real, &y.imag);
product.real=x.real*y.real-x.imag*y.imag;
product.imag=x.real*y.imag+x.imag*y.real;
printf("(%d+%di) * (%d+%di) = %d + %di\n", x.real, x.imag, y.real, y.imag, product.real, product.imag);
}
示例问题:创建图书目录
Gwen Glenn要打印一份图书目录。她想打印每本书的各种信息:书名、
作者、出版社、版权日期、页数、册数和价格。其中的一些项目(如,书
名)可以储存在字符数组中,其他项目需要一个int数组或float数组。用 7 个
不同的数组分别记录每一项比较繁琐,尤其是 Gwen 还想创建多份列表:一
份按书名排序、一份按作者排序、一份按价格排序等。如果能把图书目录的
信息都包含在一个数组里更好,其中每个元素包含一本书的相关信息。
因此,Gwen需要一种即能包含字符串又能包含数字的数据形式,而且
还要保持各信息的独立。C结构就满足这种情况下的需求。我们通过一个示
例演示如何创建和使用数组。但是,示例进行了一些限制。第一,该程序示
例演示的书目只包含书名、作者和价格。第二,只有一本书的数目。当然,
别忘了这只是进行了限制,我们在后面将扩展该程序。请看程序清单14.1及
其输出,然后阅读后面的一些要点。
程序清单14.1 book.c程序
//* book.c -- 一本书的图书目录 */
#include <stdio.h>
#include <string.h>
char * s_gets(char * st, int n);
#define MAXTITL41 /* 书名的最大长度 + 1 */
#define MAXAUTL31 /* 作者姓名的最大长度 + 1*/
struct book { /* 结构模版:标记是 book */
char title[MAXTITL];
1007char author[MAXAUTL];
float value;
}; /* 结构模版结束 */
int main(void)
{
struct book library; /* 把 library 声明为一个 book 类型的变量 */
printf("Please enter the book title.\n");
s_gets(library.title, MAXTITL); /* 访问title部分*/
printf("Now enter the author.\n");
s_gets(library.author, MAXAUTL);
printf("Now enter the value.\n");
scanf("%f", &library.value);
printf("%s by %s: $%.2f\n", library.title,
library.author, library.value);
printf("%s: \"%s\" ($%.2f)\n", library.author,
library.title, library.value);
printf("Done.\n");
return 0;
}
1008char * s_gets(char * st, int n)
{
char * ret_val;
char * find;
ret_val = fgets(st, n, stdin);
if (ret_val)
{
find = strchr(st, '\n'); // 查找换行符
if (find) // 如果地址不是 NULL,
*find = '\0'; // 在此处放置一个空字符
else
while (getchar() != '\n')
continue; //处理输入行中剩余的字符
}
return ret_val;
}
我们使用前面章节中介绍的s_gets()函数去掉fgets()储存在字符串中的换
行符。下面是该例的一个运行示例:
Please enter the book title.
1009Chicken of the Andes
Now enter the author.
Disma Lapoult
Now enter the value.
29.99
Chicken of the Andes by Disma Lapoult: $29.99
Disma Lapoult: "Chicken of the Andes" ($29.99)
Done.
程序清单14.1中创建的结构有3部分,每个部分都称为成员(member)
或字段(
field)。这3部分中,一部分储存书名,一部分储存作者名,一部
分储存价格。下面是必须掌握的3个技巧:
为结构建立一个格式或样式;
声明一个适合该样式的变量;
访问结构变量的各个部分
建立结构声明
结构声明(
structure declaration)描述了一个结构的组织布局。声明类
似下面这样:
struct book {
char title[MAXTITL];
char author[MAXAUTL];
float value;
};
该声明描述了一个由两个字符数组和一个float类型变量组成的结构。该
声明并未创建实际的数据对象,只描述了该对象由什么组成。〔有时,我们
把结构声明称为模板,因为它勾勒出结构是如何储存数据的。如果读者知道
C++的模板,此模板非彼模板,C++中的模板更为强大。〕我们来分析一些
细节。首先是关键字 struct,它表明跟在其后的是一个结构,后面是一个可
选的标记(该例中是 book),稍后程序中可以使用该标记引用该结构。所
以,我们在后面的程序中可以这样声明:
struct book library;
这把library声明为一个使用book结构布局的结构变量。
在结构声明中,用一对花括号括起来的是结构成员列表。每个成员都用
自己的声明来描述。例如,title部分是一个内含MAXTITL个元素的char类型
数组。成员可以是任意一种C的数据类型,甚至可以是其他结构!右花括号
后面的分号是声明所必需的,表示结构布局定义结束。可以把这个声明放在
所有函数的外部(如本例所示),也可以放在一个函数定义的内部。如果把
结构声明置于一个函数的内部,它的标记就只限于该函数内部使用。如果把
结构声明置于函数的外部,那么该声明之后的所有函数都能使用它的标记。
1011例如,在程序的另一个函数中,可以这样声明:
struct book dickens;
这样,该函数便创建了一个结构变量dickens,该变量的结构布局是
book。
结构的标记名是可选的。但是以程序示例中的方式建立结构时(在一处
定义结构布局,在另一处定义实际的结构变量),必须使用标记。我们学完
如何定义结构变量后,再来看这一点。
访问结构成员
结构类似于一个“超级数组”,这个超级数组中,可以是一个元素为char
类型,下一个元素为forat类型,下一个元素为int数组。可以通过数组下标单
独访问数组中的各元素,那么,如何访问结构中的成员?使用结构成员运算
符——点(
.)访问结构中的成员。例如,library.value即访问library的value
部分。可以像使用任何float类型变量那样使用library.value。与此类似,可以
像使用字符数组那样使用 library.title。因此,程序清单 14.1 中的程序中有
s_gets(library.title, MAXTITL);和scanf("%f", &library.value);这样的代码。
本质上,.title、.author和.value的作用相当于book结构的下标。
注意,虽然library是一个结构,但是library.value是一个float类型的变
量,可以像使用其他 float 类型变量那样使用它。例如,scanf("%f",...)需要一
个 float 类型变量的地址,而&library.float正好符合要求。.比&的优先级高,
因此这个表达式和&(library.float)一样。
指向结构的指针
喜欢使用指针的人一定很高兴能使用指向结构的指针。至少有 4 个理由
可以解释为何要使用指向结构的指针。第一,就像指向数组的指针比数组本
身更容易操控(如,排序问题)一样,指向结构的指针通常比结构本身更容
易操控。第二,在一些早期的C实现中,结构不能作为参数传递给函数,但
是可以传递指向结构的指针。第三,即使能传递一个结构,传递指针通常更
有效率。第四,一些用于表示数据的结构中包含指向其他结构的指针。
下面的程序(程序清单14.4)演示了如何定义指向结构的指针和如何用
这样的指针访问结构的成员。
程序清单14.4 friends.c程序
/* friends.c -- 使用指向结构的指针 */
#include <stdio.h>
#define LEN 20
struct names {
char first[LEN];
char last[LEN];
};
struct guy {
struct names handle;
char favfood[LEN];
char job[LEN];
1031float income;
};
int main(void)
{
struct guy fellow[2] = {
{ { "Ewen", "Villard" },
"grilled salmon",
"personality coach",
68112.00
},
{ { "Rodney", "Swillbelly" },
"tripe",
"tabloid editor",
432400.00
}
};
struct guy * him; /* 这是一个指向结构的指针 */
printf("address #1: %p #2: %p\n", &fellow[0], &fellow[1]);
him = &fellow[0]; /* 告诉编译器该指针指向何处 */
1032printf("pointer #1: %p #2: %p\n", him, him + 1);
printf("him->income is $%.2f: (*him).income is $%.2f\n",
him->income, (*him).income);
him++; /* 指向下一个结构 */
printf("him->favfood is %s: him->handle.last is %s\n",
him->favfood, him->handle.last);
return 0;
}
该程序的输出如下:
address #1: 0x7fff5fbff820 #2: 0x7fff5fbff874
pointer #1: 0x7fff5fbff820 #2: 0x7fff5fbff874
him->income is $68112.00: (*him).income is $68112.00
him->favfood is tripe: him->handle.last is Swillbelly
关键概念
我们在编程中要表示的信息通常不只是一个数字或一些列数字。程序可
能要处理具有多种属性的实体。例如,通过姓名、地址、电话号码和其他信
息表示一名客户;或者,通过电影名、发行人、播放时长、售价等表示一部
电影DVD。C结构可以把这些信息都放在一个单元内。在组织程序时这很重
要,因为这样可以把相关的信息都储存在一处,而不是分散储存在多个变量
中。
设计结构时,开发一个与之配套的函数包通常很有用。例如,写一个以
结构(或结构的地址)为参数的函数打印结构内容,比用一堆printf()语句强
得多。因为只需要一个参数就能打印结构中的所有信息。如果把信息放到零
散的变量中,每个部分都需要一个参数。另外,如果要在结构中增加一个成
员,只需重写函数,不必改写函数调用。这在修改结构时很方便。
联合声明与结构声明类似。但是,联合的成员共享相同的存储空间,而
且在联合中同一时间内只能有一个成员。实质上,可以在联合变量中储存一
个类型不唯一的值。
enum 工具提供一种定义符号常量的方法,typedef 工具提供一种为基本
或派生类型创建新标识符的方法。
指向函数的指针提供一种告诉函数应使用哪一个函数的方法。
本章小结
C 结构提供在相同的数据对象中储存多个不同类型数据项的方法。可以
使用标记来标识一个具体的结构模板,并声明该类型的变量。通过成员点运
算符(.)可以使用结构模版中的标签来访问结构的各个成员。
如果有一个指向结构的指针,可以用该指针和间接成员运算符(->)代
替结构名和点运算符来访问结构的各成员。和数组不同,结构名不是结构的
地址,要在结构名前使用&运算符才能获得结构的地址。
一贯以来,与结构相关的函数都使用指向结构的指针作为参数。现在的
C允许把结构作为参数传递,作为返回值和同类型结构之间赋值。然而,传
递结构的地址通常更有效。
联合使用与结构相同的语法。然而,联合的成员共享一个共同的存储空
间。联合同一时间内只能储存一个单独的数据项,不像结构那样同时储存多
种数据类型。也就是说,结构可以同时储存一个int类型数据、一个double类
型数据和一个char类型数据,而相应的联合只能保存一个int类型数据,或者
一个double类型数据,或者一个char类型数据。
通过枚举可以创建一系列代表整型常量(枚举常量)的符号和定义相关
联的枚举类型。
typedef工具可用于建立C标准类型的别名或缩写。
函数名代表函数的地址,可以把函数的地址作为参数传递给其他函数,
然后这些函数就可以使用被指向的函数。如果把特定函数的地址赋给一个名
为pf的函数指针,可以通过以下两种方式调用该函数:
#include <math.h> /* 提供sin()函数的原型:double sin(double) */
...
double (*pdf)(double);
1121double x;
pdf = sin;
x = (*pdf)(1.2); // 调用sin(1.2)
x = pdf(1.2); // 同样调用 sin(1.2)
第九章目录:
9.1定义和使用结构体变量293
9.1.1自己建立结构体类型293
9.1.2定义结构体类型变量295
9.1.3结构体变量的初始化和引用296
9.2使用结构体数组300
9.2.1定义结构体数组300
9.2.2结构体数组的应用举例301
9.3结构体指针303
9.3.1指向结构体变量的指针303
9.3.2指向结构体数组的指针304
9.3.3用结构体变量和结构体变量的指针作函数参数306
9.6使用枚举类型322
*9.7用typedef声明新类型名326
第九章课后题答案:
C语言程序设计第五版谭浩强课后答案 第九章习题答案_月已满西楼的博客-CSDN博客_在第三题的基础上,编写一个函数input