C语言第六次课讲义
- 格式:doc
- 大小:364.00 KB
- 文档页数:26
第六次课第十一章结构体本章考点教学内容一、结构体的说明1.判断下列数据的类型“liudehua”→字符串,存储形式: char sname[10]=“liudehua”;20110101 →整型,存储形式: int sno=20100101;92.5 →实型,存储形式: float score=92.5;本章将学习有多种数据类型融合在一起的数据类型,例如包括学生学号sno(整型),学生姓名sname(字符串),学生成绩(实型)2.结构体类型说明的一般形式struct 结构体名{类型名1 成员名1;类型名2 成员名2;…类型名n 成员名n;};(1)“struct”关键字的书写,且必须为小写。
(2)结构体类型中的成员必须用“{}”括起来,且不要忘记花括号外的分号。
(3)结构体类型所占存储空间是各成员占用的存储空间之和。
3.结构体类型说明的举例例1:P148struct student{ char name[10];char sex;short age;float score;};二、定义结构体类型的变量、指针和数组1.直接在结构体类型说明之后定义结构体变量例3:P148struct student{ char name[10];char sex;short age;float score;}s1,*ps,stu[3];首先说明了一个结构体student,里面有4个成员:name、sex、age、score定义了一个结构体student类型的变量s1,一个结构体student类型指针变量ps,和一个结构体student类型数组stu例4:P149struct{ char name[10];char sex;short age;float score;}s1,*ps,stu[3];说明结构体时省略了结构体的名字,语法上无错,但一般不采用该方法!定义了一个结构体student类型的变量s1,一个结构体student类型指针变量ps,和一个结构体student类型数组stu2. 先说明结构体类型,再进行变量的定义例5:P149struct student{ char name[10]; char sex; short age; float score;};struct student s1,*ps,stu[3];此考点为上机考试重点,请考生注意!student s1,*ps,stu[3];是错误的!3. 使用typedef 说明一个结构体类型名(1) typedef的使用方法:typedef 只是说明一种新的数据类型名typedef int myintint a, b,c;等价于myint a,b,c; typedef 刘德华 华仔 刘德华的歌 等价于 华仔的歌(2) 讲解P150例6typedef struct { char name[10];char sex; short age; float score;}STU;STU s1,*ps,stu[3];STU 是一个具体的结构体类型,前面不用加struct4. 重点讲解P155习题2以下结构体类型说明和变量定义正确的是( )三、 结构体变量赋初值 1. 结构体变量赋初值A)typedef struct {int n; char c; }REC;B)struct REC{ int n; char c;}; REC t1,t2;C)typedef struct REC; { int n=0; char c=‘A ’; }t1,t2;D)struct {int n; char c; }REC t1,t2;例7:struct student{ char name[10];char sex;short age;float score;2.结构体数组赋初值例8:struct student{ char name[10];char sex;short age;float score;3.结构体指针赋初值例7(补充):struct student{ char name[10];char sex;short age;float score;}s1={“Jim”,’M’,20,89};struct student *ps;ps=&s1;四、引用结构体变量1.对结构体成员的引用方法(1)结构体变量名.成员名;注:结构体数组中的每一个元素也可看作是一个结构体变量名。
(2)结构体指针变量->成员名;(3)(*结构体指针变量).成员名;2.引用结构体数组元素及输出struct student{ char name[10];char sex;struct date{ int year;int month;int day;}birthday;int age;float score[3];}s1,*ps,s[3];struct student stu={“Jim”,‘M’,1989,10,10,21,70.0,80,92};(1)分析结构体student的成员包括:name、sex、birtyday(结构体date的变量)、age、score共5个成员(2)引用结构体student中的age成员s1.ageps->ages[0].ageprintf(“%d”,stu.age);→输出:21printf(“%c”,stu.sex);→输出:M(3)引用结构体student中的name成员ps->names[0].nameprintf(“%s”,);→输出:Jimname是一个字符串,输出的时候必须使用“%s”(4)引用结构体student中的score成员s1.score[1]ps->score[1]s[0].score[1]printf(“%d”,stu.score[0]);→输出:70printf(“%d”,stu.score[2]);→输出:92(5)引用结构体student中的year成员s1.birthday.yearps->birthday.years[0].birthday.yearprintf(“%d”,stu.birthday.year);→输出:1989printf(“%d”,stu.birthday.month);→输出:10printf(“%d”,stu.birthdat.day);→输出:103. 对结构体变量中成员进行输入不作讲解,考试不涉及 五、 函数间结构体变量的数据传递 1. 讲解P154例10#include<string.h> typedef struct{ char name[10]; char sex; int age; float score; }STU;函数调用后,继续执行printf(“(2) s:%s %c %d %f\n ”,,s.sex,s.age,s.score); 输出的结果为:(2)s:Jone W 21 78.52. 讲解P155例11void fun(STU *ps){ strcpy(ps->name,”Jone ”); ps->sex=‘W ’; ps->age=21; ps->score=78.5; }main(){ STU s={“Jim ”,’M ’,20,89};printf(“(1)s:%s%c%d%f\n ”,,s.sex,s.age,s.score);fun(&s );printf(“(2) s:%s %c %d %f\n ”,,s.sex,s.age,s.score);#include<string.h> typedef struct { char name[10]; char sex; int age; float score; }STU;实参传递地址给形参,因此形参的改变到值实参的改变,因此输出的结果为: (1)s:Jim M 20 89 (2)s:Jone M 22 89void fun(char *pname,char *page) { strcpy(pname,”Jone ”); *page=22; } main() { STU s={“Jim ”,’M ’,20,89}; printf(“(1)s:%s%c%d%f\n ”, ,s.sex,s.age,s.score); fun(,&s.age); printf(“(2) s:%s %c %d %f\n ”,,s.sex,s.age,s.score);}六、结构体在上机填空题中的考点)1.结构体成员引用:上机题库P18第9题(和92题一致),P27第23题(和51题一样读清楚题目要求:(1)要求将形参a所指结构体变量的数据赋值给函数中的结构体变量b(2)从例如可以看出来:结构体中的学号和姓名变为了1002和“LiSi”,但是3门课成绩没有变化#include <stdio.h>#include <string.h>struct student {long sno;char name[10];float score[3];};void fun(struct student a){ struct student b; int i;/**********found**********/b = __1__;→题目要求将形参a的值赋值给结构体变量b,因此填:ab.sno = 10002;→学号变为了10002/**********found**********/strcpy(__2__, "LiSi");→姓名要变为”LiSi”,则要引用b中的name成员printf("\nThe data after modified :\n");/*讲解是一句带过不用多讲*/printf("\nNo: %ld Name: %s\nScores: ",b.sno, ); /*讲解是一句带过不用多讲*//**********found**********/for (i=0; i<3; i++) printf("%6.2f ", b.__3__);→分析:这个是一个循环语句,执行3次循环,printf("%6.2f ", b.__3__)要求输出是一个实型数据的成员,因此可以得知是score成员,因为score是一个数组,因此填:b.score[i],当i变化就可以取出第一门、第二门、第三门课的成绩printf("\n");}main(){ struct student s={10001,"ZhangSan", 95, 80, 88};int i;printf("\n\nThe original data :\n");printf("\nNo: %ld Name: %s\nScores: ",s.sno, );for (i=0; i<3; i++) printf("%6.2f ", s.score[i]);23题:(1)从例如中可以看出:变化的是结构体中的学号和姓名#include <stdio.h>#include <string.h>struct student {long sno;char name[10];float score[3];};void fun( struct student *b){ int i;/**********found**********/b__1__ = 10004;→题目中t的学号变化为了10004,因此填写:b->sno,不能填写b.sno,因为b是一个指针/**********found**********/strcpy(b__2__, "LiJie");→t的姓名变为了”LiJie”,因此填写:b->name}main(){ struct student t={10002,"ZhangQi", 93, 85, 87};int i;printf("\n\nThe original data :\n");printf("\nNo: %ld Name: %s\nScores: ",t.sno, );for (i=0; i<3; i++) printf("%6.2f ", t.score[i]);printf("\n");/**********found**********/fun(__3__);→此处为函数调用,根据形参的类型来判定实参,形参struct student *b为结构体指针,联系main函数定义部分只有struct student t和b 的类型相同,因此可知需要填的是:&tprintf("\nThe data after modified :\n");printf("\nNo: %ld Name: %s\nScores: ",t.sno, );for (i=0; i<3; i++) printf("%6.2f ", t.score[i]);printf("\n");}2.函数调用and结构体:上机题库P22第16题(和78、82题一样)重点注意:(1)把a中地址作为函数返回值返回函数(2)观察可知a中的学号、姓名边为了10002和“zhangSan”,每门课的成绩增加了1分#include <stdio.h>#include <string.h>struct student {long sno;char name[10];float score[3];};/**********found**********/__1__ fun(struct student *a)→根据函数调用t = fun(&s);可知函数返回类型和t的类型相同,struct student s={10001,"ZhangSan", 95, 80, 88}, *t;可知t的类型为struct student *{ int i;a->sno = 10002;strcpy(a->name, "LiSi");/**********found**********/for (i=0; i<3; i++) __2__ += 1;→题目要求将每门课成绩增加1分,因此填为:a->score[i],不能为a.score[i]或是a.score/**********found**********/return __3__ ;→题目要求返回a的地址,a本身就是一个指针,因此填入a即可}main(){ struct student s={10001,"ZhangSan", 95, 80, 88}, *t;int i;printf("\n\nThe original data :\n");printf("\nNo: %ld Name: %s\nScores: ",s.sno, );for (i=0; i<3; i++) printf("%6.2f ", s.score[i]);printf("\n");t = fun(&s);printf("\nThe data after modified :\n");printf("\nNo: %ld Name: %s\nScores: ",t->sno, t->name);for (i=0; i<3; i++) printf("%6.2f ", t->score[i]);printf("\n");}3.结构体和排序:上机题库P14第2题(和)重点注意:(1)排序的格式:红色部分为考试中的重点,必须记住从小到大排序: for(i=0;i<n-1;i++) for(j=i+1;j<n;j++) if(a[i]>a[j]) {t=a[i];a[i]=a[j];a[j ]=t;}从大到小排序: for(i=0;i<n-1;i++)for(j=i+1;j<n ;j++) if(a[i]<a[j]){t=a[i];a[i]=a[j];a[j ]=t;} void fun(struct student a[], int n){/**********found**********/__1__ t;→此处要求填入t 的类型,可以从t = a[i];中得知t 和a 数组的类型必须一致,void fun(struct student a[], int n)中得知a 为结构体类型,因此填写:struct student int i, j;/**********found**********/for (i=0; i<__2__; i++)→根据排序的格式填空,因此记住是关键 for (j=i+1; j<n; j++) /**********found**********/if (strcmp(__3__) > 0)→按照姓名字典顺序从小到大排序,因此: strcmp(a[i].name,a[j].name),此处需要特别注意 { t = a[i]; a[i] = a[j]; a[j] = t; } }main(){ struct student s[4]={{10001,"ZhangSan", 95, 80, 88},{10002,"LiSi", 85, 70, 78},{10003,"CaoKai", 75, 60, 88},{10004,"FangFang", 90, 82, 87}};int i, j;printf("\n\nThe original data :\n\n"); for (j=0; j<4; j++){ printf("\nNo: %ld Name: %-8s Scores: ",s[j].sno, s[j].name); for (i=0; i<3; i++) printf("%6.2f ", s[j].score[i]); printf("\n"); }fun(s, 4);printf("\n\nThe data after sorting :\n\n"); for (j=0; j<4; j++){ printf("\nNo: %ld Name: %-8s Scores: ",s[j].sno, s[j].name); for (i=0; i<3; i++) printf("%6.2f ", s[j].score[i]); printf("\n"); } }七、链表1.链表的结构:结构体:struct student{int sno;float score; }; 链表:struct link{char data;struct link *next; };讲解P156习题3 struct tt{ int x;struct tt*y;}*p;struct tt a[4]={20,a+1,15,a+2,30,a+3,17,a};main(){ int i; p=a; for(i=1;i<=2;i++) { printf(“%d ,”,p->x); p=p->y; }}八、 链表在上机考试中的形式1. 带头结点的链表:p=h->next,上机题库P21第15题 考点分析:(1)带头结点链表的表现形式:带头结点的链表,头结点head 不存放任何的数据,从头结点的下一个结点开p=a;执行for 循环:(1)i=1,判断:i<=2为真,执行循环体:printf(“%d,”,p->x);→输出:20 p=p->y;→p 指向了a[1](2)i=2,判断:i<=2为真,执行循环体:printf(“%d ,”,p->x);→输出:15p=p->y;→p 指向了a[2](3)i=3,判断:i<=2为假,结束循环,最终输出:20,15始存放数据,因此考试中如果出现 p = __1__ ;则填入p=h->next(2)链表数据排序对数组元素从小到大排序:for(i=0;i<n-1;i++)for(j=i+1;j<n;j++)if(a[i]>a[j]){t=a[i];a[i]=a[j];a[j ]=t;}对链表元素进行从小到大排序:while (p) /*相当于数组排序中的for(i=0;i<n-1;)*/{q = p->next;/*相当于j=i+1*/while (q) /*相当于for(;j<n;){if (p->data > q->data) /*相当于if(a[i]>a[j])*/{ t = p->data; p->data = q->data; q->data = t; }/*如果a[i]>a[j]成立,则交换数据元素,让数据变成从小到大排序*/ q = q->next;/*相当于q++*/}p = p->next;/*相当于p++*/}15题:#include <stdio.h>#include <stdlib.h>#define N 6typedef struct node {int data;struct node *next;} NODE;void fun(NODE *h){ NODE *p, *q; int t;/**********found**********/p = __1__ ;→链表为带头结点,因此填写:p=h->nextwhile (p) {/**********found**********/q = __2__ ;→比较两个链表中元素的大小,因此q=p->next,这样q指向了p的下一位while (q) {/**********found**********/if (p->data __3__ q->data)—>从小到大排序,因此使用大于符号,填写:>{ t = p->data; p->data = q->data; q->data = t; }q = q->next;}p = p->next;}}main(){ NODE *head;int a[N]= {0, 10, 4, 2, 8, 6 };head=creatlist(a);printf("\nThe original list:\n");outlist(head);fun(head);printf("\nThe list after sorting :\n");outlist(head);}2.不带头结点的链表:p=h(1)不带头结点链表的表示形式:(2)讲解P38第42题(和15题类似)void fun(NODE *h){ NODE *p, *q; int t;p = h;→不带头结点的链表while (p) {/**********found**********/q = __1__ ;→q指向p的下一位,因此填入:q=p->next/**********found**********/while (__2__)→判断q有没有到末尾,因此填入p或是p!=NULL{ if (p->data > q->data){ t = p->data; p->data = q->data; q->data = t; }q = q->next;}/**********found**********/p = __3__ ;→ while (p)为循环条件,要构成循环p就得自加或是自减,从循环体中得知没有进行p++之类的操作,因此此处填入:p=p->next或是p++}}main(){ NODE *head;int a[N]= {0, 10, 4, 2, 8, 6 };head=creatlist(a);printf("\nThe original list:\n");outlist(head);fun(head);}3.链表的返回值:P43第50题(和43题类似)/**********found**********/__1__ fun(NODE *h)→根据函数调用head=fun(head);和 NODE *head; 知道函数的返回值为NODE *{ NODE *p, *q, *r;p = h;if (p == NULL)—>如果p数据位空,则表示p中没有任何的数据,因此就无需再进行逆置,故return NULL;return NULL;q = p->next;p->next = NULL;/**********found**********/while (__2__)→此空判断q有没有为空,讲解时候不容易理解,考生记住即可,填入:while(q)或是while(q!=NULL){ r = q->next;q->next = p;p = q;/**********found**********/q = __3__ ;→填入:q=r;次空理解起来较难,因此考生必须认真记忆,老师无需多讲}return p;}main(){ NODE *head;int a[N]={2,4,6,8,10};head=creatlist(a);printf("\nThe original list:\n");outlist(head);head=fun(head);printf("\nThe list after inverting :\n");outlist(head);}上机考题教学内容一、填空题之方法1.填空题做题之前必须弄清题目含义,抓住关键字,例如:要求对数组进行从小到大排序,则将会出现大于符号,如果是从大到小排序则出现小于符号;2.填空题中出现频率最高的就是函数的调用、函数的首部、函数的返回值等和函数相关的问题,因此必须牢牢掌握祝函数的基本特征;3.填空题中有的“空”比较难,考生除了掌握必须的C语言知识之外,还需要很好的逻辑思路,如果一个空将花很多时间来解决,那么建议使用“死记硬背”的方法来缩短复习时间;4.上机题库中100题有部分题目是重复的或是相似的题目很多,同学们要使用比对的方法尽量去理解;二、填空题之文件相关1.文件指针定义(1)文件定义的形式:FILE *fp;(课本P115)(2)举例:上机题库P30第28题第一空/**********found**********/__1__ fp;分析:在涉及文件类型的上机题目时fp指的就是文件指针,因此在前面填写类型时候直接写入:FILE *fp;(3)类似题目:P32第32题第1个空、P67第88题第2个空2.文件打开(1)文件打开的格式:fopen(“文件名”,“打开方式”);(课本P115)(2)举例:P31第30题第1个空void fun(char *filename, STU n){ FILE *fp;/**********found**********/fp = fopen(__1__, "rb+");分析:缺少了文件名,形参filename是实参传过来的文件名,因此这里直接填入:fp = fopen(filename, "rb+");表示以“读和写”的方式打开一个二进制文件filename(3)类似的题目:P41第47题第1个空、P71第94题第1个空、P72第96题第3空3.文件关闭(1)文件关闭的格式:fclose(文件指针);(课本P117)(2)举例:上机题库P30第28题第2空fp = fopen("file1.txt", "w");/*第一次以写的形式打开文件file1.txt*/fprintf(fp, "%s %d %f\n", s, a, f);/**********found**********/__2__ ;fp = fopen("file1.txt", "r");/*第二次以读的形式打开文件file1.txt*/分析:打开文件以后必须将它关闭,因此该空要填:fclose(fp);(3)类似题目:P72第96题第2空4.测试文件结束(1)判断文件结束的feof函数形式:feof(fp)(课本P118)(2)经常出现在while()的表达式里面,常见形式为:while(!feof(fp))测试指针fp 有没有结束(3)举例:上机题目P26第22题第1空FILE *fp;STU n; int i;fp = fopen(filename,"rb+");/**********found**********/while (!__1__)分析:填写feof(fp)测试fp指针又没有结束(4)类似题目:P32第32题第2个空、P61第80题第1个空、P71第94题第2个空5.设置文件位置函数(1) fseek设置文件位置:fseek(文件指针,位移量,移动起始点)(课本P118)(2)考试一般考查的是移动的起始点:SEEK_SET表示文件开始,SEEK_CUR表示文件当前位置,SEEK_END表示文件末尾(3)举例:上机题库P31第30题第2个空/**********found**********/fseek(fp, -1L*sizeof(STU), __2__);分析:题目要求:重写形参filename所指文件中最后一个学生的数据,因此文件指针fp要指向最后的位置,则填入:fseek(fp, -1L*sizeof(STU), SEEK_END);(4)类似题目:P26第22题第3空、P61第80第3空、6.读二进制文件(1)fwrite(存入数据的指针,每一个数据占有的字节,输入数据的个数,文件指针);(课本P120)(2)举例:P31第30题第3空void fun(char *filename, STU n){ FILE *fp;/**********found**********/fp = fopen(filename, "rb+");/*打开文件filename*//**********found**********/fseek(fp, -1L*sizeof(STU), SEEK_END);/*定位到最后一个学生的位置*//**********found**********/fwrite(__3__, sizeof(STU), 1, fp);/*将形参n新学生的数据覆盖最后一个学生的数据,因为fp已经定位到了最后一个学生的位置*/fclose(fp);}分析:题目要求用新数据覆盖最后一个学生的数据,因此填入:fwrite(&n, sizeof(STU), 1, fp);填入的是地址,不能是:fwrite(n, sizeof(STU), 1, fp);(3)类似题目:P41第47题第3空,P67第88题第3空7.写二进制文件函数(1)fread(读出数据的指针,每一个数据占有的字节,输出数据的个数,文件指针);(2)上机考试填空题没有出现需要填写的空,考生作一般的了解8.fcanf函数数和fprintf函数(1)fscanf(文件指针,格式控制字符串,输入列表项);(2)fprintf(文件指针,格式控制字符串,输出列表项);fscanf函数和fprintf函数在上机编程题中详细介绍,这里不作重点讲解,了解即可三、填空题之字符串相关1.删除字符串(1)主要考查二维字符数组与字符串的操作(2)举例1:P18第8题(和65题一样)#define N 5#define M 10int fun(char (*ss)[M], int k)/*char (*ss)[M]行指针,下标与二维数组x的列下标相同,k通过实参传递过来后为7*/{ int i,j=0,len;/**********found**********/for(i=0; i< __1__ ; i++)/*根据len=strlen(ss[i]);可知i代表的是行,因此填入for(i=0; i< N ; i++)*/{ len=strlen(ss[i]);/**********found**********/if(len<= __2__);/*题目要求将串长超过k的字符串删除,换个说法就是将串小于等于k的字符串留下,因此该空填写if(len<= k)*//**********found**********/strcpy(ss[j++],__3__);/*将ss[i]行的值赋值到s[j]中,该空出现频率很高,因此要牢记。