一 行字符串在主函数中输入,规定所有单词由小写字母组成,单词之间由若干个空格隔开,一 行的开始没有空格。 - 59 - #include #include #define N 80 int fun( char *s) { } main() { char line[N]; int num=0; printf("Enter a string :\n"); gets(line); num=fun( line ); printf("The number of word is : %d\n\n",num); } 程序 3 统计各个阶段年龄段的人数。 #include #define N 50 #define M 11 void fun(int a[], int 数器 { b[]) //数组 a 有 50 个年龄,数组 b 有 11 个计 } double rnd() { static t=29,c=217,m=1024,r=0; r=(r*t+c)%m; return((double)r/m); } main() { int age[N], i, d[M]; for(i=0; i=’A’ && s[i]<=’Z’) n++; return n; } 任务 2 程序 1: void fun(char *tt, int pp[]) { int i; //计数器清 0 for(i=0; i<26; i++) pp[i]=0; //统计 for(i=0; tt[i]; i++) { if(tt[i]>='a' && tt[i]<='z') pp[tt[i]-'a']++; } } 任务 2 程序 2: int fun( char *s) { int k=1; while (*s) { if (*s==' ')k++; s++; } return k ; } 任务 2 程序 3: void fun(int a[], int 数器 b[]) //数组 a 有 50 个年龄,数组 b 有 11 个计 - 61 - { int i; //计数器置 0 for(i=0; idata; 访问节点中地址域:p->next; 当前节点指针 p 向后移动一位:p=p->next; 申请一个节点: NODE *p; p=(NODE * )malloc(sizeof(struct Node)); free(p);//释放节点 5. 链表的遍历 链表遍历方法:先指向链表的第 1 个节点,然后向后移,直到最后一个节点。 链表的头节点:通常用 h 或 head 来表示。 链表的第 1 个节点:带头节点的链表,p=h->next; 不带头节点的链表,p=h; 遍历链表中的元素的代码段(带头节点的链表) : 方法一: Node *p=head->next; while(p!=NULL) { 访问某个节点中的数据 p->data p=p->next; } 方法二: Node *p=head->next; while(p) { - 64 - 访问某个节点中的数据 p->data p=p->next; } 6. 动态内存的申请 申请一个长度为 size 的动态内存: #include #include void main() { //动态内存申请 int *p; p = (int *)malloc(sizeof(int)); //申请内存 *p = 100; //使用内存 printf("%d\n",*p); //使用内存 free(p); //释放内存 } 申请 n 个长度为 size 的动态内存(假设 n=5) : #include #include void main() { //动态内存申请 int *p; int i; p = (int *)calloc(5,sizeof(int)); //申请动态数组 p[0]=100; p[1]=200; p[2]=300; p[3]=400; p[4]=500; //使用动态数组 for(i=0; i<5; i++) printf("%d\n",*(p+i)); free(p); //释放动态数组 } ? 程序编制 程序 1: N 名学生的成绩已在主函数中放入一个带头节点的链表结构中,h 指向链表的头节点。 请编写函数 fun,它的功能是:求出平均分,由函数值返回。 例如, 若学生的成绩是: 85, 76, 69, 85, 91, 72, 64, 87; 则平均分应当是: 78.625。 #include #include - 65 - //使用动态数组 #define N 8 struct slist { double s; struct slist *next; }; typedef struct slist STREC; double fun( STREC *h ) //求链表的平均分 { } STREC * creat( double *s) //创建一个链表 { STREC *h,*p,*q; int i; //创建一个头节点,头节点中没有数据 h=p=(STREC *)malloc(sizeof(STREC)); p->s=0; //遍历数组 s for(i=0; is=s[i]; //新节点放到链表的最后一个位置。 p->next=q; //p 始终是指向链表的最后一个节点 p=q; //p=p->next; } p->next=NULL; //将最后一个节点的指针域置为 NULL return h; //返回一个链表头指针 } outlist( STREC *h) //输出链表(带头节点) { STREC *p; p=h->next; printf("head"); while(p!=NULL) - 66 - { printf("->%4.1f",p->s); //p->s 是数据域 p=p->next; //让 p 指向后面一个节点,功能类似字符串中的 i++ p++ } printf("\n\n"); } main() { double s[N]={85,76,69,85,91,72,64,87},ave; STREC *h; //head 链表的头指针 h=creat(s); //创建一个链表(依据一个数组) ,链表的头指针 outlist(h); //输出一个链表 ave=fun(h); //求链表中所有元素的平均分 printf("ave= %6.3f\n",ave); //输出平均分 } 任务 2:链表的节点插入 ? 程序编制 程序 1: 给定程序中已建立一个带有头结点的单向链表, 链表中的各结点按结点数据域中的数据 从小到大顺序链接。函数 fun 的功能是:把形参 x 的值放入一个新结点并插入到链表中, 插入后各结点仍保持从小到大顺序排列。 #include #include #define N 8 typedef struct list { int data; struct list *next; } SLIST; void fun( SLIST *h, int x) { SLIST *p, *q, *s; s=(SLIST *)malloc(sizeof(SLIST)); s->data= x; q=h; p=h->next; while(p!=NULL && x>p->data) { q= p; p=p->next; } s->next=p; q->next= s; } - 67 - SLIST *creatlist(int *a) { SLIST *h,*p,*q; int i; h=p=(SLIST *)malloc(sizeof(SLIST)); for(i=0; idata=a[i]; p->next=q; p=q; } p->next=0; return h; } void outlist(SLIST *h) { SLIST *p; p=h->next; if (p==NULL) printf("\nThe list is NULL!\n"); else { printf("\nHead"); do { printf("->%d",p->data); p=p->next; } while(p!=NULL); printf("->End\n"); } } main() { SLIST *head; int x; int a[N]={11,12,15,18,19,22,25,29}; head=creatlist(a); printf("\nThe list before inserting:\n"); outlist(head); printf("\nEnter a number : "); scanf("%d",&x); fun(head,x); printf("\nThe list after inserting:\n"); outlist(head); } 任务 3:链表的节点删除 ? 程序编制 程序 1: 给定程序中已建立一个带有头结点的单向链表,在 main 函数中将多次调用 fun 函数, 每调用一次 fun 函数,输出链表尾部结点中的数据,并释放该结点,使链表缩短。 #include #include #define N 8 typedef struct list { int data; struct list *next; } SLIST; - 68 - void fun( SLIST *p) { SLIST *t, *s; t=p->next; s=p; while(t->next != NULL) { s=t; t=t->next; } printf(" %d ", t->data); s->next=NULL; free(t); } SLIST *creatlist(int *a) { SLIST *h,*p,*q; int i; h=p=(SLIST *)malloc(sizeof(SLIST)); for(i=0; idata=a[i]; p->next=q; p=q; } p->next=0; return h; } void outlist(SLIST *h) { SLIST *p; p=h->next; if (p==NULL) printf("\nThe list is NULL!\n"); else { printf("\nHead"); do { printf("->%d",p->data); p=p->next; } while(p!=NULL); printf("->End\n"); } } main() { SLIST *head; int a[N]={11,12,15,18,19,22,25,29}; head=creatlist(a); printf("\nOutput from head:\n"); outlist(head); printf("\nOutput from tail: \n"); while (head->next != NULL){ fun(head); printf("\n\n"); printf("\nOutput from head again :\n"); outlist(head); } } - 69 - 程序 2: 给定程序中已建立一个带有头结点的单向链表,链表中的各结点按数据域递增有序链 接。函数 fun 的功能是,删除链表中数据域相同的结点,使之只保留一个。 #include #include #define N 8 typedef struct list { int data; struct list *next; } SLIST; void fun( SLIST *h) { SLIST *p, *q; p=h->next; if (p!=NULL) { q=p->next; while(q!=NULL) { if (p->data==q->data) { p->next=q->next; free(q); q=p->next; } else { p=q; q=q->next; } } } } SLIST *creatlist(int *a) { SLIST *h,*p,*q; int i; h=p=(SLIST *)malloc(sizeof(SLIST)); for(i=0; idata=a[i]; p->next=q; p=q; } p->next=0; return h; } void outlist(SLIST *h) { SLIST *p; p=h->next; if (p==NULL) printf("\nThe list is NULL!\n"); else { printf("\nHead"); - 70 - do { printf("->%d",p->data); p=p->next; } while(p!=NULL); printf("->End\n"); } } main( ) { SLIST *head; int a[N]={1,2,2,3,4,4,4,5}; head=creatlist(a); printf("\nThe list before deleting :\n"); outlist(head); fun(head); printf("\nThe list after deleting :\n"); outlist(head); } 任务 4:链表的节点排序 ? 程序编制 程序 1: 函数 fun 的功能是将带头节点的单向链表结点数据域中的数据从小到大排序。即若原 链表结点数据域从头至尾的数据为:0、10、4、2、8、6,排序后链表结点数据域从头至 尾的数据为:0、2、4、6、8、10。 #include #include #define N 6 typedef struct node { int data; struct node *next; } NODE; void fun(NODE *h) { NODE *p, *q; int t; p = h->next ; while (p) { q = p->next ; while (q) { if (p->data > q->data) { t = p->data; p->data = q->data; q->data = t; } q = q->next; } p = p->next; } } NODE *creatlist(int a[]) { NODE *h,*p,*q; int i; - 71 - h = (NODE *)malloc(sizeof(NODE)); h->next = NULL; for(i=0; idata=a[i]; q->next = NULL; if (h->next == NULL) h->next = p = q; else { p->next = q; p = q; } } return h; } void outlist(NODE *h) { NODE *p; p = h->next; if (p==NULL) printf("The list is NULL!\n"); else { printf("\nHead "); do { printf("->%d", p->data); p=p->next; } while(p!=NULL); printf("->End\n"); } } 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); } 任务 5:链表的节点逆序 ? 程序编制 程序 1: 函数 fun 的功能是将不带头结点的单向链表逆置。即若原链表中从头至尾结点数据域 依次为:2、4、6、8、10,逆置后,从头至尾结点数据域依次为:10、8、6、4、2。 #include #include #define N 5 - 72 - typedef struct node { int data; struct node *next; } NODE; NODE * fun(NODE *h) { NODE *p, *q, *r; p = h; if (p == NULL) return NULL; q = p->next; p->next = NULL; while (q) { r = q->next; q->next = p; p = q; q = r ; } return p; } NODE *creatlist(int a[]) { NODE *h,*p,*q; int i; h=NULL; for(i=0; idata=a[i]; q->next = NULL; if (h == NULL) h = p = q; else { p->next = q; p = q; } } return h; } void outlist(NODE *h) { NODE *p; p=h; if (p==NULL) printf("The list is NULL!\n"); else { printf("\nHead "); do { printf("->%d", p->data); p=p->next; } while(p!=NULL); printf("->End\n"); } } - 73 - 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 程序 1: double fun( STREC *h ) //求链表的平均分 { double sum = 0.0; int i,n=0; STREC *p; p=h->next; while(p!=NULL) { sum += p->s; n++; p = p->next; } return sum/n; } 拓展:如果题目要求求和,则 return sum;即可。 - 74 - 实训项目八 文件的应用 一、实训目的与要求 通过文件操作类的程序编制,熟悉掌握 C 语言文件处理函数及相关技巧。 二、实训内容 任务 1:文件的打开与关闭 ? 编程思路 (1)文件的概念 磁盘上,可以存放数据,文本文件(.txt,.c) ,二进制文件(.obj,.exe) (2)文件类型指针 #include FILE *fp; //fp 文件指针,用来指向一个文件 (3)文件的基本操作:打开,关闭,读写 fopen fclose f+.... (4)文件的打开操作 文件:文本文件、二进制文件 1. 打开文件,文件的路径,打开的方式(文本或二进制的 只读、只写、追加、读写) , 判断文件打开是否成功。 判断文件打开是否成功 if((fp=fopen(.......))==NULL) //注意 fp 两层括号,不能省略 { //打开失败 printf("Can not open the file.\n"); return; } fopen(文件的路径,文件打开的方式) ? 文件的路径:"aa.txt" 当前目录下的 aa.txt 文件 ? "c:\\txt\\aa.dat" C 盘下 txt 文件夹下的 aa.dat 文件 ? 打开方式: 文本文件 "r":只读,该文件必须存在,否则返回 NULL。 "w":只写,如果文件不存在,则新建一个文件。如果文件存在,文件中原有信息会被 删除。 - 75 - "a":追加,如果文件不存在,则新建一个文件。如果文件存在,文件中原有信息会被 保留,新内容追加在文件尾部。 二进制文件 "rb":只读,该文件必须存在,否则返回 NULL。 "wb":只写,如果文件不存在,则新建一个文件。如果文件存在,文件中原有信息会 被删除。 "ab":追加,如果文件不存在,则新建一个文件。如果文件存在,文件中原有信息会 被保留,新内容追加在文件尾部。 文本文件 "r+":读写,该文件必须存在,否则返回 NULL。 "w+":读写,如果文件不存在,则新建一个文件。如果文件存在,文件中原有信息会 被删除。 "a+":读写,如果文件不存在,则新建一个文件。如果文件存在,文件中原有信息会 被保留,新内容追加在尾部。 “rt+”: 读写打开一个文本文件,允许读和写。 “wt+”: 读写打开或建立一个文本文件,允许读写。 “at+”: 读写打开一个文本文件,允许读,或在文件末追加数据。 二进制文件 "rb+":读写,该文件必须存在,否则返回 NULL。读写打开一个二进制文件,允许读 和写 "wb+":读写,如果文件不存在,则新建一个文件。如果文件存在,文件中原有信息会 被删除。读写打开或建立一个二进制文件,允许读和写 "ab+":读写,如果文件不存在,则新建一个文件。如果文件存在,文件中原有信息会 被保留,新内容追加在尾部。读写打开一个二进制文件,允许读,或在文件末追加数据 FILE *fp; if((fp=fopen("in.dat","r")==NULL) //打开 { } //读写操作 fclose(fp); //关闭 (5)文件的读写操作 ch=fgetc(fp); //从文件中读字符(文本) fputc(ch,fp); //往文件中写字符(文本) //从文件中读二进制数据,放到 buffer 所指向的内存中。