1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #define N 3 5 #define LEN (Student*) malloc(sizeof(Student)) 6 /* 学生数据结构 */ 7 typedef struct node 8 { 9 char num[20]; 10 char name[15]; 11 int score[N]; 12 int sum; 13 double ave; 14 struct node *next; 15 } Student; 16 17 /* 头指针 */ 18 Student *head = NULL; 19 /* 临时指针 */ 20 Student *tmp = NULL; 21 /* 课程名称 */ 22 char CLASSNAME[N][30] = {"大物", "高数", "c语言"}; 23 /* 命令开关 */ 24 int SWITCH[16] = {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 25 /* 函数声明 */ 26 int Menu(); 27 Student* Init(); 28 int CheckNUM(char*); 29 int CheckName(char*); 30 int CheakScore(int score); 31 int Same_NUM(char*); 32 void InputNodeInfo(Student*); 33 void OutputNodeInfo(Student*); 34 Student* SearchFrontNode(Student*); 35 void DeleteNode(Student*); 36 void InsertBefore(); 37 void InputList(); 38 Student* SearchID(char*); 39 Student* SearchName(char*); 40 void SearchDeleteNode(); 41 void OutList(); 42 void SearchPrintNode(); 43 void Compute(); 44 int CmpID(Student*, Student*, int); 45 int CmpSum(Student*, Student*, int); 46 int CmpScore(Student*, Student*, int); 47 Student* SearchMaxNode(int (*cmp)(Student*, Student*, int), int); 48 Student* Sort(int (*cmp)(Student*, Student*, int), int); 49 void OutputToFile(FILE*, Student*, int); 50 void InsertAfter(Student*); 51 void SaveToFile(); 52 void LoadFile(); 53 void CopyFile(); 54 void InsertToFile(); 55 void FreeList(Student* p); 56 void Stat(); 57 void Quit(); 58 59 /* 主函数 */ 60 int main() 61 { 62 int n; 63 64 while (1) 65 { 66 n = Menu(); 67 { 68 if (n == 1 || n == 15 || SWITCH[1]) 69 { 70 switch (n) 71 { 72 /* 执行初始化 */ 73 case 1: 74 head = Init(); 75 printf("LOOK...初始化成功 "); 76 break; 77 /* 创建链表 ,输入学生信息*/ 78 case 2: 79 InputList(); 80 break; 81 /* 查找学号或姓名删除信息 */ 82 case 3: 83 SearchDeleteNode(); 84 break; 85 /* 输出全部学生信息 */ 86 case 4: 87 system("cls"); 88 OutList(); 89 break; 90 /* 按姓名查找学生信息*/ 91 case 5: 92 SearchPrintNode(); 93 break; 94 /* 保存到文件 */ 95 case 6: 96 SaveToFile(); 97 break; 98 /* 从文件中读取学生信息*/ 99 case 7: 100 if (SWITCH[6]) 101 { 102 head = Init(); 103 LoadFile(); 104 } 105 else 106 { 107 printf("当前文件未保存 "); 108 } 109 break; 110 /* 计算所有学生的总分和平均分 */ 111 case 8: 112 Compute(); 113 SWITCH[8] = 1; 114 printf("计算完毕 "); 115 break; 116 /* 插入一个学生信息到链表 */ 117 case 9: 118 InsertBefore(); 119 SWITCH[6] = 0; 120 SWITCH[8] = 0; 121 break; 122 /* 复制文件 */ 123 case 10: 124 CopyFile(); 125 break; 126 /* 排序,按总分排序并打印学生信息 */ 127 case 11: 128 if (SWITCH[8]) 129 { 130 head = Sort(CmpSum, 0); 131 system("cls"); 132 OutList(); 133 } 134 else 135 { 136 printf("请先计算总分! "); 137 } 138 break; 139 /* 尾部添加一个学生信息到文件中 */ 140 case 12: 141 InsertToFile(); 142 SWITCH[6] = 0; 143 printf("尾部添加完毕! "); 144 break; 145 /* 按学号搜索..学生信息*/ 146 case 13: 147 if (SWITCH[8]) 148 { 149 head = Sort(CmpID, 0); 150 system("cls"); 151 OutList(); 152 } 153 else 154 { 155 printf("请先计算总分! "); 156 } 157 break; 158 /* 分类汇总 */ 159 case 14: 160 system("cls"); 161 Stat(); 162 break; 163 /* 结束 */ 164 case 15: 165 Quit(); 166 break; 167 default: 168 printf("无效命令! "); 169 fflush(stdin); 170 } 171 system("pause"); 172 } 173 else 174 { 175 printf("你必须首先初始化! "); 176 system("pause"); 177 } 178 } 179 } 180 181 system("pause"); 182 return 0; 183 } 184 185 /* 菜单 */ 186 int Menu() 187 { 188 int n; 189 system("cls"); 190 fflush(stdin); 191 printf("********************************************************************* "); 192 printf("********************************************************************* "); 193 printf("【01】 初始化........ "); 194 printf("【02】 输入学生信息 "); 195 printf("【03】 查找学号或姓名删除信息 "); 196 printf("【04】 输出全部学生信息 "); 197 printf("【05】 按姓名查找学生信息 "); 198 printf("【06】 保存到文件 "); 199 printf("【07】 从文件中读取学生信息 "); 200 printf("【08】 计算所有学生的总分和平均分 "); 201 printf("【09】 插入一个学生信息到链表中 "); 202 printf("【10】 复制文件 "); 203 printf("【11】 按总分排序并打印学生信息 "); 204 printf("【12】 尾部添加一个学生信息到文件中 "); 205 printf("【13】 按学号搜索..学生信息 "); 206 printf("【14】 分类汇总 "); 207 printf("【15】 退出 "); 208 printf("******************************************************************** "); 209 printf("请输入命令编号: "); 210 scanf("%d", &n); 211 return n; 212 } 213 214 /* 初始化 */ 215 Student* Init() 216 { 217 int i; 218 Student *head; 219 head = LEN; 220 head->next = NULL; 221 222 /* 命令开关初始化 */ 223 for (i = 1; i < 16; i++) 224 { 225 SWITCH[i] = 0; 226 } 227 228 SWITCH[1] = 1; 229 SWITCH[6] = 1; 230 return head; 231 } 232 233 /* 检查学号 */ 234 int CheckNUM(char* s) 235 { 236 int i; 237 238 if (strlen(s) == 0 || strlen(s) > 10) return 0; 239 240 for (i = 0; i < strlen(s); i++) 241 { 242 if (s[i] < '0' || s[i] > '9') return 0; 243 } 244 245 return 1; 246 } 247 248 /* 检查姓名 */ 249 int CheckName(char* s) 250 { 251 int i; 252 253 if (strlen(s) == 0 || strlen(s) > 15) return 0; 254 255 for (i = 0; i < strlen(s); i++) 256 { 257 if (!(s[i] >= 'a' && s[i] <= 'z' || s[i] >= 'A' && s[i] <= 'Z')) return 0; 258 } 259 260 return 1; 261 } 262 263 /* 检查分数 */ 264 int CheakScore(int score) 265 { 266 if (score > 100 || score <= 0) return 0; 267 return 1; 268 } 269 270 /* 检查相同学号 */ 271 int Same_NUM(char* s) 272 { 273 Student *p = head->next; 274 while(p != NULL) 275 { 276 if (strcmp(s, p->num) == 0) return 1; 277 p = p->next; 278 } 279 return 0; 280 } 281 282 /* 给p指向的节点输入信息 */ 283 void InputNodeInfo(Student* p) 284 { 285 fflush(stdin); 286 287 /* 学号 */ 288 printf(" 请输入学号: "); 289 do 290 { 291 gets(p->num); 292 293 if (!CheckNUM(p->num)) 294 { 295 printf("数据不标准,请重新输入学号: "); 296 } 297 else if (Same_NUM(p->num)) 298 { 299 printf("检测到此学号存在,请重新输入: "); 300 } 301 }while (!(CheckNUM(p->num) && !Same_NUM(p->num))); 302 303 /* 姓名 */ 304 printf("请输入姓名: "); 305 do 306 { 307 gets(p->name); 308 if (!CheckName(p->name)) 309 { 310 printf("数据不标准,请重新输入姓名: "); 311 } 312 } 313 while (!CheckName(p->name)); 314 315 /* 成绩 */ 316 int i; 317 for (i = 0; i < N; i++) 318 { 319 printf("请输入 %s 成绩: ", CLASSNAME[i]); 320 do 321 { 322 fflush(stdin); 323 scanf("%d", &p->score[i]); 324 325 if (!CheakScore(p->score[i])) 326 { 327 printf("数据不标准,请重新输入 %s 成绩: ", CLASSNAME[i]); 328 } 329 } 330 while (!CheakScore(p->score[i])); 331 } 332 333 /* 总分及平均分 */ 334 p->sum = -1; 335 p->ave = -1; 336 } 337 338 /* 输出p指向节点的信息 */ 339 void OutputNodeInfo(Student* p) 340 { 341 int i; 342 printf(" "); 343 printf("姓名: %s ", p->name); 344 printf("学号: %s ", p->num); 345 346 for (i = 0; i < N; i++) 347 { 348 printf("%s 成绩: %d ", CLASSNAME[i], p->score[i]); 349 } 350 351 /* 计算过才输出 */ 352 if (SWITCH[8]) printf("总分: %d ", p->sum); 353 if (SWITCH[8]) printf("平均分: %.2lf ", p->ave); 354 } 355 356 /* 返回r的前一个节点 */ 357 Student* SearchFrontNode(Student* r) 358 { 359 Student *p = head; 360 while (p->next != r) p = p->next; 361 return p; 362 } 363 364 /* 删除r指向的节点 */ 365 void DeleteNode(Student* r) 366 { 367 Student *p = SearchFrontNode(r); 368 p->next = r->next; 369 } 370 371 /* 头插法插入节点 */ 372 void InsertBefore() 373 { 374 Student *s = LEN; 375 InputNodeInfo(s); 376 s->next = head->next; 377 head->next = s; 378 } 379 380 /* 输入链表 */ 381 void InputList() 382 { 383 int n; 384 printf("有多少个学生信息要输入? "); 385 scanf("%d", &n); 386 387 while (n--) 388 { 389 InsertBefore(); 390 } 391 } 392 393 /* 按学号查找 */ 394 Student* SearchID(char* num) 395 { 396 Student *p = head->next; 397 398 while (p != NULL) 399 { 400 if (strcmp(p->num, num) == 0) break; 401 p = p->next; 402 } 403 404 return p; 405 } 406 407 /* 按姓名查找 */ 408 Student* SearchName(char* name) 409 { 410 Student *p = head->next; 411 412 while (p != NULL) 413 { 414 if (strcmp(p->name, name) == 0) break; 415 p = p->next; 416 } 417 418 return p; 419 } 420 421 /* 按学号或姓名查找删除节点 */ 422 void SearchDeleteNode() 423 { 424 Student *p; 425 fflush(stdin); 426 char str[20]; 427 char sure[20]; 428 429 /* 输入合法性判断 */ 430 printf("请输入你要删除的学生的 姓名 或 学号: "); 431 do 432 { 433 gets(str); 434 435 if (!(CheckNUM(str) || CheckName(str))) 436 { 437 printf("数据不标准,请重新输入姓名或学号: "); 438 } 439 } 440 while (!(CheckNUM(str) || CheckName(str))); 441 442 /* 判断是姓名还是学号 */ 443 if (str[0] >= '0' && str[0] <= '9') 444 { 445 p = SearchID(str); 446 447 if (p == NULL) 448 { 449 printf("对不起,找不到这个学号 "); 450 } 451 else 452 { 453 OutputNodeInfo(p); 454 printf("确认删除? (输入"y"确认,任意键取消): "); 455 if (strcmp(gets(sure), "y") == 0) 456 { 457 DeleteNode(p); 458 printf("删除成功 "); 459 SWITCH[6] = 0; 460 } 461 fflush(stdin); 462 } 463 } 464 else 465 { 466 p = SearchName(str); 467 468 if (p == NULL) 469 { 470 printf("对不起,找不到这个姓名 "); 471 } 472 else 473 { 474 OutputNodeInfo(p); 475 printf("确认删除? (输入"y"确认,任意键取消): "); 476 if (strcmp(gets(sure), "y") == 0) 477 { 478 DeleteNode(p); 479 printf("删除成功! "); 480 SWITCH[6] = 0; 481 } 482 fflush(stdin); 483 } 484 } 485 } 486 487 /* 输出链表 */ 488 void OutList() 489 { 490 Student *p = head->next; 491 492 /* 空表处理 */ 493 if (p == NULL) 494 { 495 printf("暂无学生信息! "); 496 } 497 498 while (p != NULL) 499 { 500 OutputNodeInfo(p); 501 p = p->next; 502 } 503 } 504 505 /* 按姓名查找记录并打印 */ 506 void SearchPrintNode() 507 { 508 Student *p = head->next; 509 int ok = 1; 510 char name[20]; 511 fflush(stdin); 512 513 /* 姓名合法性判断 */ 514 printf("请输入你要查找的学生姓名: "); 515 do 516 { 517 gets(name); 518 519 if (!CheckName(name)) 520 { 521 printf("数据不标准,请重新输入姓名: "); 522 } 523 } 524 while (!CheckName(name)); 525 526 /* 按姓名查找节点 */ 527 while (p != NULL) 528 { 529 if (strcmp(p->name, name) == 0) 530 { 531 ok = 0; 532 OutputNodeInfo(p); 533 } 534 p = p->next; 535 } 536 537 if (ok) 538 { 539 printf("对不起,找不到这个姓名 "); 540 } 541 } 542 543 /* 计算总分和均分 */ 544 void Compute() 545 { 546 int i; 547 Student *p = head->next; 548 549 while (p != NULL) 550 { 551 int sum = 0; 552 553 for (i = 0; i < N; i++) 554 { 555 sum += p->score[i]; 556 } 557 558 p->sum = sum; 559 p->ave = sum * 1.0 /N; 560 p = p->next; 561 } 562 } 563 564 /* 比较学号 */ 565 int CmpID(Student* a, Student* b, int k) 566 { 567 return strcmp(a->num, b->num); 568 } 569 570 /* 比较总分 */ 571 int CmpSum(Student* a, Student* b, int k) 572 { 573 return b->sum - a->sum; 574 } 575 576 /* 比较各科分数 */ 577 int CmpScore(Student* a, Student* b, int k) 578 { 579 return b->score[k] - a->score[k]; 580 } 581 582 /* 选择最大元素 */ 583 Student* SearchMaxNode(int (*cmp)(Student* a, Student* b, int k), int k) 584 { 585 Student *p = head->next; 586 Student *max = p; 587 588 while (p != NULL) 589 { 590 if (cmp(p, max, k) < 0) 591 { 592 max = p; 593 } 594 p = p->next; 595 } 596 597 return max; 598 } 599 600 /* 排序 */ 601 Student* Sort(int (*cmp)(Student* a, Student* b, int k), int k) 602 { 603 Student *newhead = LEN; 604 Student *p = newhead; 605 Student *max; 606 607 while (head->next != NULL) 608 { 609 max = SearchMaxNode(cmp, k); 610 p->next = max; 611 DeleteNode(max); 612 p = p->next; 613 } 614 615 /* 表尾处理 */ 616 p->next = NULL; 617 return newhead; 618 } 619 620 621 /* 将s插入链表尾部 */ 622 void InsertAfter(Student* s) 623 624 { 625 Student *p = head; 626 627 while (p->next != NULL) p = p->next; 628 629 s->next = NULL; 630 p->next = s; 631 } 632 633 /* 保存到文件 */ 634 void SaveToFile() 635 { 636 /* 处理尾部添加表尾情况 */ 637 if (SWITCH[12]) 638 { 639 InsertAfter(tmp); 640 } 641 642 FILE *fp; 643 int i; 644 Student *p; 645 char file[20]; 646 fflush(stdin); 647 printf("请输入要保存的文件名: "); 648 gets(file); 649 650 if ((fp = fopen(file, "wt")) == NULL) 651 { 652 printf("写文件错误.......! "); 653 return; 654 } 655 for(p = head->next;p!=NULL;p=p->next) 656 fprintf(fp,"%s %s ",p->name,p->num); 657 for(i=0;i<2;i++) 658 { 659 fprintf(fp,"%d ",p->score[i]); 660 } 661 printf("文件保存成功! "); 662 fclose(fp); 663 SWITCH[6] = 1; 664 665 /* 处理尾部添加情况 */ 666 if (SWITCH[12]) 667 { 668 DeleteNode(tmp); 669 SWITCH[12] = 0; 670 } 671 } 672 673 /* 从文件中读入记录 */ 674 void LoadFile() 675 { 676 int i; 677 FILE *fp; 678 char file[20]; 679 fflush(stdin); 680 printf("请输入文件名: "); 681 gets(file); 682 683 if ((fp = fopen(file, "rt")) == NULL) 684 { 685 printf("对不起,无法打开文件! "); 686 return; 687 } 688 689 /* 文件未结束时读入数据 */ 690 while (!feof(fp)) 691 { 692 Student *s = LEN; 693 fscanf(fp, "%s", s->name); 694 fscanf(fp, "%s", s->num); 695 696 for (i = 0; i < N; i++) 697 { 698 fscanf(fp, "%d", &s->score[i]); 699 } 700 701 s->next = head->next; 702 head->next = s; 703 } 704 705 printf("文件读取成功! "); 706 fclose(fp); 707 } 708 709 /* 复制文件 */ 710 void CopyFile() 711 { 712 FILE *fp1, *fp2; 713 char ch, file1[20], file2[20]; 714 fflush(stdin); 715 /* 读入源文件 */ 716 printf("请输入源文件名: "); 717 gets(file1); 718 719 if ((fp1 = fopen(file1, "rb")) == NULL) 720 { 721 printf("对不起,无法打开文件! "); 722 return; 723 } 724 725 /* 读入目标文件 */ 726 printf("请输入目标文件名: "); 727 gets(file2); 728 729 if ((strcmp(file1, file2) == 0) || ((fp2 = fopen(file2, "wb")) == NULL)) 730 { 731 printf("对不起,无法创建文件! "); 732 return; 733 } 734 735 /* 逐个字符拷贝 */ 736 while (!feof(fp1)) 737 { 738 ch = fgetc(fp1); 739 740 if (ch != EOF) 741 fputc(ch, fp2); 742 } 743 744 fclose(fp1); 745 fclose(fp2); 746 printf("文件拷贝成功! "); 747 } 748 749 /* 尾部添加记录到文件中 */ 750 void InsertToFile() 751 { 752 tmp = LEN; 753 InputNodeInfo(tmp); 754 SWITCH[12] = 1; 755 } 756 757 /* 分类统计 */ 758 void Stat() 759 { 760 int i, j, n = 0; 761 int sum[N] = {0}; 762 Student *p = head->next; 763 764 if (p == NULL) 765 { 766 printf("暂无学生信息,无法统计 "); 767 return; 768 } 769 770 /* 统计各科总分 */ 771 while (p != NULL) 772 { 773 /* 记录学生总数 */ 774 n++; 775 776 for (i = 0; i < N; i++) 777 { 778 sum[i] += p->score[i]; 779 } 780 781 p = p->next; 782 } 783 784 /* 各科分别输出 */ 785 for (i = 0; i < N; i++) 786 { 787 printf("%s 总均分: %.2lf ", CLASSNAME[i], sum[i] * 1.0 / n); 788 head = Sort(CmpScore, i); 789 j = 0; 790 p = head->next; 791 792 while (p != NULL) 793 { 794 j++; 795 printf("第%d名 %s %d ", j, p->name, p->score[i]); 796 p = p->next; 797 } 798 799 printf(" "); 800 } 801 } 802 803 /* 释放链表 */ 804 void FreeList(Student* p) 805 { 806 if (p->next != NULL) 807 { 808 FreeList(p->next); 809 } 810 free(p); 811 } 812 813 /* 退出 */ 814 void Quit() 815 { 816 if (!SWITCH[6]) 817 { 818 printf("请先保存文件! "); 819 return; 820 } 821 if (head != NULL) 822 { 823 FreeList(head); 824 } 825 exit(0); 826 }