user-0 提问: 求分析这段代码

回复:
user: user-1
content: #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct subjects             { 	int num;                          //课程编号  	char name[20]; 	char kind[10];                    //课程性质 	int stime;                        //总学时 	int ttime;                        //授课学时 	int etime;                        //实验或上机学时  	int score;                        //学分 	int term;                         //开课学期 	struct subjects *next;            //结构体指针 }SUB;  SUB *create_form()                    //创建课表 { 	SUB *head, *tail, *p;             //head，tail指向head第一个结点，p指向新建结点（楼主可以区分链表有无头结点） 	int num, stime, ttime;            //这一行以及下两行的的变量主要存储你要输入课程的内容 	int etime, score, term; 	char name[20], kind[10]; 	int size = sizeof(SUB);           //其实这一行可以省略，然后将下面的p = (SUB *)malloc(size)修改一下，这行如果不修改意思是看一下这个结构体的大小，及所占的内存 	head = tail = NULL;               //在还没有开始创建课表的时候，这两个指针先赋空值，否则会报错（不懂，请百度指针初始化赋空值的缘由） 	printf("输入选修课程信息:\n"); 	scanf_s("%d %s %s %d %d %d %d %d", &num, &name, &kind, &stime, &ttime, &etime, &score, &term); //开始存你课程的内容 	while (num != 0){                //因为你的课表有很多课，所以是循环结构 		p = (SUB *)malloc(size);     //可以直接写p = (SUB *)malloc(SUB);在一个链表中添加一个新的节点，这个节点得先申请内存（详见sizeof的使用） 		p->num = num;                //这一行以及接下来几行的语句是将你输入的课程内容存入到这个新建节点中 		strcpy_s(p->name, name); 		strcpy_s(p->kind, kind); 		p->stime = stime; 		p->ttime = ttime; 		p->etime = etime; 		p->score = score; 		p->term = term; 		if (head == NULL)            //如果你刚建立这个表，你的表是没有内容的，所以你的第一个结点head指向NULL 		{ 			head= p;                //p成为第一个结点 			              		} 		else 			tail->next = p;         //如果这个表里面本来就有东西，那就tail->next指向新结点，换我，其实可以不用tail,直接head->next=p。。 		tail = p;                   //tail指向p（换我 ，我直接写head=p，觉得多设置这个指针没什么用...） 		scanf_s("%d %s %s %d %d %d %d %d", &num, &name, &kind, &stime, &ttime, &etime, &score, &term);  //继续输入内容，继续新建结点加入链表中 	} 	tail->next = NULL;             //最后记得链表尾赋NULL 	return head; }  void savefile(SUB *head)          //存课表到文件中，读写文件你会的吧？下面的存文件为什么不合并一起...明明是一毛一样的功能，非要分开文件存储 { 	SUB *p; 	FILE *fp; 	fp = fopen("subjects.txt", "w"); 	fprintf(fp, "课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n"); 	for (p = head; p; p = p->next) 		fprintf(fp, "%5d%12s%9s%9d%9d%11d%11d%7d\n", p->num, p->name, p->kind, p->stime, p->ttime, p->etime, p->score, p->term); 	fclose(fp); }  void savefileadd(SUB *head)       { 	SUB *p; 	FILE *fp; 	fp = fopen("subjectsadd.txt", "w"); 	fprintf(fp, "课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n"); 	for (p = head; p; p = p->next) 		fprintf(fp, "%5d%12s%9s%9d%9d%11d%11d%7d\n", p->num, p->name, p->kind, p->stime, p->ttime, p->etime, p->score, p->term); 	fclose(fp); }  void savefiledel(SUB *head) { 	SUB *p; 	FILE *fp; 	fp = fopen("subjectsdel.txt", "w"); 	fprintf(fp, "课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n"); 	for (p = head; p; p = p->next) 		fprintf(fp, "%5d%12s%9s%9d%9d%11d%11d%7d\n", p->num, p->name, p->kind, p->stime, p->ttime, p->etime, p->score, p->term); 	fclose(fp); }  void prin(SUB *head)                    //读文件 { 	SUB *ptr; 	if (head == NULL){ 		printf("没有此门课程记录\n"); 		return; 	} 	printf("课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n"); 	for (ptr = head; ptr; ptr = ptr->next) 		printf("%5d%12s%9s%9d%9d%11d%11d%7d\n", ptr->num, ptr->name, ptr->kind, ptr->stime, ptr->ttime, ptr->etime, ptr->score, ptr->term); } void search(SUB *head) { 	int a, num; 	int t = 1; 	char type[10]; 	char ch = 'a', ch1; 	SUB *ptr;  	while (ch != ' '){ 		printf("按课程性质查找输入1，按学分查找输入2:\n"); 		scanf("%d", &a); 		switch (a){ 		case 1:printf("输入要查找的课程性质:\n"); 			scanf_s("%s", type); 			printf("课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n"); 			for (ptr = head; ptr; ptr = ptr->next)         //这里ptr=head跟ptr=head->next都可以 			if (strcmp(type, ptr->kind) == 0){ 				printf("%5d%12s%9s%9d%9d%11d%11d%7d\n", ptr->num, ptr->name, ptr->kind, ptr->stime, ptr->ttime, ptr->etime, ptr->score, ptr->term); 				t = 0; 			} 			if (t) printf("未找到\n"); 			t = 1; 			break; 		case 2:printf("输入要查找的课程的学分\n"); 			scanf_s("%d", &num); 			printf("课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n"); 			for (ptr = head; ptr; ptr = ptr->next) 			if (ptr->score == num){ 				printf("%5d%12s%9s%9d%9d%11d%11d%7d\n", ptr->num, ptr->name, ptr->kind, ptr->stime, ptr->ttime, ptr->etime, ptr->score, ptr->term); 				t = 0; 			} 			if (t) printf("未找到\n"); 			t = 1;  		} 		printf("继续查找请按回车，结束请按空格:\n"); 		ch1 = getchar();                              //将回车键赋给CH1，否则CASE里面最后输入的回车键会赋给CH，因此用CH1填补。 		ch = getchar(); 	} }  SUB *insert(SUB *head)                               //添加函数跟创建表的函数内容差不多，看不懂你再问我吧.. { 	SUB *ptr, *ptr2, *subj; 	int size = sizeof(SUB); 	char ch = 'a', ch1; 	while (ch != ' '){ 		subj = (SUB *)malloc(size); 		ptr = subj; 		printf("输入要插入的课程信息:\n"); 		scanf_s("%d%s%s%d%d%d%d%d", &subj->num, subj->name, subj->kind, &subj->stime, &subj->ttime, &subj->etime, &subj->score, &subj->term); 		if (head == NULL){ 			head = ptr; 			head->next = NULL; 		} 		else{ 			for (ptr2 = head; ptr2; ptr2 = ptr2->next) 			if (ptr2->next == NULL){ 				ptr2->next = subj; 				subj->next = NULL; 				break; 			} 		} 		printf("继续插入请按回车，结束请按空格:\n"); 		ch1 = getchar();                      //将回车键赋给CH1，否则subj->term输完后输入的回车键会赋给CH，因此用CH1填补。 		ch = getchar(); 	} 	return head; }     SUB *del(SUB *head) { 	SUB *p1, *p2; 	char ch = 'a', ch1; 	int num; 	while (ch != ' '){ 		printf("输入要删除的课程编号:\n"); 		scanf_s("%d", &num); 		if (head->num == num){                    //如果你删除的课程刚好就是链表第一个结点，那么 			p2 = head;                            //指针p指向这个结点 			head = head->next;                    //让head指向自己下一个结点 			free(p2);                             //释放掉这个不想要的结点 		} 		if (head == NULL)                         //如果课程表本来就是空的，那就直接回去= =，一般逻辑思维这个应该放在前面，先判断课程表是否为空 			return NULL; 		p1 = head;                               //能运行到这个阶段说明，要删除的结点不是第一个结点，故让p1指向第一个结点 		p2 = head->next;                         //p2指向第二个结点 		while (p2){                              //p2不能为空 			if (p2->num == num){                 //当你找到要删除的点的时候 				p1->next = p2->next;             //直接让p1指向p2后一个结点，即p1直接无视了p2..跟p2后面的结点连在了一起 				free(p2);                        //依旧记得释放没用的结点 			} 			else p1 = p2;                        //如果没找到，p1就到了p2的位置 			p2 = p1->next;                       //不管有没有找到，一定要保证p2永远在p1后面 		} 		printf("继续删除请按回车，结束请按空格:\n"); 		ch1 = getchar();                       //将回车键赋给CH1，否则num输完后再输入的回车键会赋给CH，因此用CH1填补。 		ch = getchar(); 	} 	return head; }  void choose(SUB *head) { 	SUB *p, *q; 	int a[5]; 	int num, total = 0, i = 0, j; 	printf("输入要选修的课程的编号，编号之间以空格分开，输完后以0结束\n"); 	scanf_s("%d", &num); 	while (num != 0){ 		for (p = head; p; p = p->next) 		if (p->num == num){ 			total = total + p->score; 			a[i] = num; 			i++; 		} 		scanf_s("%d", &num); 	} 	if (total<60) printf("选修总学分未达到60,选修失败!\n"); 	else { 		printf("选修成功!!\n"); 		printf("您选修的课程为:\n"); 		for (j = 0; j<i; j++) 		for (q = head; q; q = q->next) 		if (q->num == a[j]) 			printf("%s  ", q->name); 		printf("\n"); 	} }  void main() { 	SUB *head = create_form();                 //创建表 	savefile(head);                            //存表 	prin(head);                               //打印表 	search(head);                             //查找 	head = insert(head);                        //函数insert的的返回值 	savefileadd(head);                         //存添加后的表 	printf("修改后的信息为:\n"); 	prin(head); 	head = del(head);                           //函数del的的返回值 	savefiledel(head); 	printf("修改后的课程信息为:\n"); 	prin(head); 	choose(head); }     .......写到最后写不下去了.....不是自己的代码，感觉看着一直想吐槽，有什么看不懂的可以问我，强烈建议，这种题创建链表要用带有头结点的,这道题，这道题没有......  （楼上说的有道理，代码功能归根结底不是别人帮自己看或讲解或注释出来的，只是毕竟自己学渣学链表的时候还是很希望有人带带自己。。。）

user: user-2
content: 代码功能归根结底不是别人帮自己看或讲解或注释出来的；而是被自己静下心来花足够长的时间和精力亲自动手单步或设断点或对执行到某步获得的中间结果显示或写到日志文件中一步一步分析出来的。 提醒：再牛×的老师也无法代替学生自己领悟和上厕所！ 单步调试和设断点调试（VS IDE中编译连接通过以后，按F10或F11键单步执行，按Shift+F11退出当前函数；在某行按F9设断点后按F5执行停在该断点处。）是程序员必须掌握的技能之一。

user: user-3
content: 仅供参考：//不带表头结点的单向链表 #include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <time.h> #include <locale.h> struct NODE {     int          data;     struct NODE *next; } *head,*p,*q,*s,*p1,*p2,*q1,**ta; int i,k,n,t,m,v,N=10; int main() {     setlocale(LC_ALL,"chs");     srand(time(NULL));      head=NULL;      printf("创建%d个节点的单链表:",N);//创建N个节点的单链表     p=head;     for (i=0;i<N;i++) {         q=(struct NODE *)malloc(sizeof(struct NODE));         if (NULL==q) exit(1);         q->data=rand()%100;//填写0..99的随机值         q->next=NULL;         if (NULL==p) {             head=q;             p=head;         } else {             p->next=q;             p=q;         }     }      //输出整个单链表     s=head;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      k=3;     v=5;     printf("将值为%d的结点插入到单链表的第%d个结点前:",v,k);//将值为v的结点插入到单链表的第k个结点前     n=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         n++;         if (k==1) {             q=(struct NODE *)malloc(sizeof(struct NODE));             if (NULL==q) exit(1);             q->data=v;             q->next=head;             head=q;             break;         } else {             if (k-1==n) {                 q=(struct NODE *)malloc(sizeof(struct NODE));                 if (NULL==q) exit(1);                 q->data=v;                 q->next=p->next;                 p->next=q;                 break;             }         }         p=p->next;     }      //输出整个单链表     s=head;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      k=5;     printf("删除第%d个节点:",k);//删除第k个节点     n=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         n++;         if (k==1) {             q=head;             head=head->next;             free(q);             break;         } else {             if (k-1==n) {                 q=p->next;                 if (q) {                     p->next=q->next;                     free(q);                 }                 break;             }         }         p=p->next;     }      //输出整个单链表     s=head;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      printf("从小到大排序:");//从小到大排序     for (p=head,p1=NULL;p!=NULL;p1=p,p=p->next) {         for (q=p->next,q1=p;q!=NULL;q1=q,q=q->next) {             if (p->data > q->data) {                  //交换data //              printf("swap %02d %02d\n",p->data,q->data); //              t=p->data;p->data=q->data;q->data=t;                  //或者                  //交换next //              printf("swap %02d %02d\n",p->data,q->data);                 if (p==head) {//p是头                     if (p->next==q) {//pq挨着                         head=q;                         p->next=q->next;                         q->next=p;                         q=p;                         p=head;                     } else {//pq不挨着                         head=q;                         p2=p->next;                         p->next=q->next;                         q->next=p2;                         q1->next=p;                         q=p;                         p=head;                     }                 } else {//p不是头                     if (p->next==q) {//pq挨着                         p1->next=q;                         p->next=q->next;                         q->next=p;                         q=p;                         p=p1->next;                     } else {//pq不挨着                         p1->next=q;                         p2=p->next;                         p->next=q->next;                         q->next=p2;                         q1->next=p;                         q=p;                         p=p1->next;                     }                 }                  //输出整个单链表 //              s=head; //              while (1) { //                  if (NULL==s) { //                      printf("\n"); //                      break; //                  } //                  printf("%02d->",s->data); //                  s=s->next; //              } //              getchar();             }         }     }      //输出整个单链表并计算链表长度n     n=0;     s=head;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         n++;         s=s->next;     }      printf("将整个链表逆序:");//将整个链表逆序     if (n>=2) {         p=head;         q=p->next;         p->next=NULL;         while (1) {             q1=q->next;             q->next=p;             p=q;             q=q1;             if (NULL==q) break;         }         head=p;     }      //输出整个单链表     s=head;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      m=4;     n=6;     printf("将单链表中前%d个结点和后%d个结点进行互换:",m,n);//将单链表中前m个结点和后n个结点进行互换,m+n为链表总长     k=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         k++;         if (m==k) {             q=p;         }         s=p;         p=p->next;     }     q1=head;     head=q->next;     s->next=q1;     q->next=NULL;      //输出整个单链表     s=head;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //释放所有节点     p=head;     while (1) {         if (NULL==p) {             break;         }         q=p->next;         free(p);         p=q;     }      return 0; } //创建10个节点的单链表:08->74->07->23->03->99->31->56->88->16-> //将值为5的结点插入到单链表的第3个结点前:08->74->05->07->23->03->99->31->56->88->16-> //删除第5个节点:08->74->05->07->03->99->31->56->88->16-> //从小到大排序:03->05->07->08->16->31->56->74->88->99-> //将整个链表逆序:99->88->74->56->31->16->08->07->05->03-> //将单链表中前4个结点和后6个结点进行互换:31->16->08->07->05->03->99->88->74->56-> //

user: user-4
content: #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct subjects {     int num;     char name[20];     char kind[10];     int stime;     int ttime;     int etime;     int score;     int term;     struct subjects *next; }SUB;  SUB *create_form() {     SUB *head,*tail,*p;     int num,stime,ttime;     int etime,score,term;     char name[20],kind[10];     int size=sizeof(SUB);     head=tail=NULL;     printf("输入选修课程信息:\n");     /* name and kind remove the char '&' */     scanf("%d %s %s %d %d %d %d %d", &num, name, kind,&stime,&ttime,&etime,&score,&term);     while(num!=0){         p=(SUB *)malloc(size);         p->num=num;         strcpy(p->name,name);         strcpy(p->kind,kind);         p->stime=stime;         p->ttime=ttime;         p->etime=etime;         p->score=score;         p->term=term;         if(head==NULL)             head=p;         else             tail->next=p;         tail=p;     /* name and kind remove the char '&' */         scanf("%d %s %s %d %d %d %d %d",&num, name, kind, &stime,&ttime,&etime,&score,&term);     }     tail->next=NULL;     return head; }  void savefile(SUB *head) {     SUB *p;     FILE *fp;     fp=fopen("subjects.txt","w");     fprintf(fp,"课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n");     for(p=head;p;p=p->next)         fprintf(fp,"%5d%12s%9s%9d%9d%11d%11d%7d\n",p->num,p->name,p->kind,p->stime,p->ttime,p->etime,p->score,p->term);     fclose(fp); }  void savefileadd(SUB *head) {     SUB *p;     FILE *fp;     fp=fopen("subjectsadd.txt","w");     fprintf(fp,"课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n");     for(p=head;p;p=p->next)         fprintf(fp,"%5d%12s%9s%9d%9d%11d%11d%7d\n",p->num,p->name,p->kind,p->stime,p->ttime,p->etime,p->score,p->term);     fclose(fp); }  void savefiledel(SUB *head) {     SUB *p;     FILE *fp;     fp=fopen("subjectsdel.txt","w");     fprintf(fp,"课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n");     for(p=head;p;p=p->next)         fprintf(fp,"%5d%12s%9s%9d%9d%11d%11d%7d\n",p->num,p->name,p->kind,p->stime,p->ttime,p->etime,p->score,p->term);     fclose(fp); }  void prin(SUB *head) {     SUB *ptr;     if(head==NULL){         printf("没有此门课程记录\n");         return;     }     printf("课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n");     for(ptr=head;ptr;ptr=ptr->next)         printf("%5d%12s%9s%9d%9d%11d%11d%7d\n",ptr->num,ptr->name,ptr->kind,ptr->stime,ptr->ttime,ptr->etime,ptr->score,ptr->term); } void search(SUB *head) {     int a,num;     int t=1;     char type[10];     char ch='a',ch1;     SUB *ptr;      while(ch!=' '){         printf("按课程性质查找输入1，按学分查找输入2:\n");         scanf("%d",&a);         switch(a){             case 1:printf("输入要查找的课程性质:\n");                    scanf("%s",type);                    printf("课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n");                    for(ptr=head;ptr;ptr=ptr->next)                        if(strcmp(type,ptr->kind)==0){                            printf("%5d%12s%9s%9d%9d%11d%11d%7d\n",ptr->num,ptr->name,ptr->kind,ptr->stime,ptr->ttime,ptr->etime,ptr->score,ptr->term);                            t=0;                        }                    if(t) printf("未找到\n");                    t=1;                    break;             case 2:printf("输入要查找的课程的学分\n");                    scanf("%d",&num);                    printf("课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n");                    for(ptr=head;ptr;ptr=ptr->next)                        if(ptr->score==num){                            printf("%5d%12s%9s%9d%9d%11d%11d%7d\n",ptr->num,ptr->name,ptr->kind,ptr->stime,ptr->ttime,ptr->etime,ptr->score,ptr->term);                            t=0;                        }                    if(t) printf("未找到\n");                    t=1;          }         printf("继续查找请按回车，结束请按空格:\n");         ch1=getchar();                              //将回车键赋给CH1，否则CASE里面最后输入的回车键会赋给CH，因此用CH1填补。         ch=getchar();     } }  SUB *insert(SUB *head) {     SUB *ptr,*ptr2,*subj;     int size=sizeof(SUB);     char ch='a',ch1;     while(ch!=' '){         subj=(SUB *)malloc(size);         ptr=subj;         printf("输入要插入的课程信息:\n");         scanf("%d%s%s%d%d%d%d%d", &subj->num, subj->name, subj->kind,&subj->stime,&subj->ttime,&subj->etime,&subj->score,&subj->term);         if(head==NULL){             head=ptr;             head->next=NULL;         }         else{             for(ptr2=head;ptr2;ptr2=ptr2->next)                 if(ptr2->next==NULL){                     ptr2->next=subj;                     subj->next=NULL;                     break;                 }         }         printf("继续插入请按回车，结束请按空格:\n");         ch1=getchar();                      //将回车键赋给CH1，否则subj->term输完后输入的回车键会赋给CH，因此用CH1填补。         ch=getchar();     }     return head; }     SUB *del(SUB *head) {     SUB *p1,*p2;     char ch='a',ch1;     int num;     while(ch!=' '){         printf("输入要删除的课程编号:\n");         scanf("%d",&num);         if(head->num==num){             p2=head;             head=head->next;             free(p2);         }         if(head==NULL)             return NULL;         p1=head;         p2=head->next;         while(p2){             if(p2->num==num){                 p1->next=p2->next;                 free(p2);             }             else p1=p2;             p2=p1->next;         }         printf("继续删除请按回车，结束请按空格:\n");         ch1=getchar();                       //将回车键赋给CH1，否则num输完后再输入的回车键会赋给CH，因此用CH1填补。         ch=getchar();     }     return head; }  void choose(SUB *head) {     SUB *p,*q;     int a[5];     int num,total=0,i=0,j;     printf("输入要选修的课程的编号，编号之间以空格分开，输完后以0结束\n");     scanf("%d",&num);     while(num!=0){         for(p=head;p;p=p->next)             if(p->num==num){                 total=total+p->score;                 a[i]=num;                 i++;             }         scanf("%d",&num);     }     if(total<60) printf("选修总学分未达到60,选修失败!\n");     else {         printf("选修成功!!\n");         printf("您选修的课程为:\n");         for(j=0;j<i;j++)             for(q=head;q;q=q->next)                 if(q->num==a[j])                     printf("%s  ",q->name);         printf("\n");     } }  int main() {     SUB *head=create_form();     savefile(head);     prin(head);     search(head);     head=insert(head);                        //函数insert的的返回值     savefileadd(head);     printf("修改后的信息为:\n");     prin(head);     head=del(head);                           //函数del的的返回值     savefiledel(head);     printf("修改后的课程信息为:\n");     prin(head);     choose(head); }   有两处错误～

user: user-0
content: 总要是链表那一块有点模糊

user: user-5
content: 请从main函数看起，哪里不懂就百度，必应，查参考书，要是还不懂就指出来是哪里。