本程序用C写成,鼓励批评指正!
Name:Contact++
Version:0.2
Powered By GenialX
From 沈阳化工大学2011级
URL:胡旭-煦生活 - 胡旭个人博客 - 一个自由大学生的琐碎
QQ:2252065614
QQ交流群:235173087(欢迎加入,增增人气儿...)
---2013.02.07
基本功能实现:
通讯录信息插入、删除、编辑、查找、修改以及信息存盘(contact.ctt)。
实现原理:
利用指针操作链表实现通讯录功能。
记录:
添加给存盘文档加密的功能(存档文件即根目录下的contact.ctt文件)
详细:利用异或加密,由于异或操作的特性,所以加密和解密调用,同一个实现即可。
步骤:
1、定义密钥常量KEY(默认值为'x')。
2、修改getInfo()函数。首先创建一个临时文件tmp.ctt(属性设置成系统隐藏文件),然后把源文件(加密文件)读取,并将解密后的内容放入tmp.ctt中。然后将tmp.ctt中的内容逐步读入链表,之后删除临时文件tmp.ctt。
3、修改saveRecords()函数。原理基本同上,创建系统隐藏文件作为临时缓冲文件(tmp.ctt),之后删除。
---2013.02.07 21:01
定义常量
详细:将一些信息定一场全局常量,便于管理。比如:作者信息。
---2013.02.08 08:26
源码:
1 /** 2 * @Name:Contact++ 3 * @Desc:这是一个实现通讯录的C源代码 4 * @Version:0.2 5 * @Author:GenialX 6 * @From:沈阳化工大学2011级 7 * @URL:http://www.ihuxu.com 8 * @QQ:287156904 9 * @QQ Group:235173087 10 */ 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include <windows.h> 16 17 //这里定义的是联合体中字符数组的长度。 18 #define C_NAME_SIZE 10 19 #define C_SEX_SIZE 3 20 #define C_AGE_SIZE 5 21 #define C_PHONE_SIZE 12 22 #define C_QQ_SIZE 12 23 #define C_PROVINCE_SIZE 20 24 #define C_CITY_SIZE 20 25 #define C_COMMENT_SIZE 100 26 27 //亲,很明显,这是函数说明! 28 void insRecord();//插入一条记录的实现 29 void inputs(char *prompt,char *info,int count);//插入一条记录时,逐行输入信息的实现 30 struct addr *linkNode(struct addr *i,struct addr *top);//输入完一条记录后,将当前的缓冲节点连接到链表中的实现 31 struct addr *find(char *name);//查找出指定的节点的实现 32 void seaRecord();//查找记录的实现 33 void delRecord();//删除记录的实现 34 int selectMenu();//主菜单的实现 35 void disRecord(addr *info);//显示一条记录的实现 36 void disRecords();//显示全部记录的实现 37 void getInfo(); //根据ctt文本中的记录,逐条返回数据项,并实现将信息插入链表,即程序启动的初始化状态的实现 38 void initInputs(char *initInfo[]);//输入完一条记录后,将当前的缓冲节点连接到链表中的实现 39 void saveRecords();//将链表中的信息全部写到磁盘文件中的实现 40 void saveToFile(addr *info);//将每条信息记录放到新建的文件中的实现 41 void editRecord();//修改记录的实现 42 void about();//显示作者信息的实现 43 44 45 //全局的东东 46 47 //联合体 48 struct addr 49 { 50 char c_name[C_NAME_SIZE]; 51 char c_sex[C_SEX_SIZE]; 52 char c_age[C_AGE_SIZE]; 53 char c_phone[20]; 54 char c_qq[C_QQ_SIZE]; 55 char c_province[C_PROVINCE_SIZE]; 56 char c_city[C_CITY_SIZE]; 57 char c_comment[C_COMMENT_SIZE]; 58 59 struct addr *next;//pointer to next entry ^^ 60 }; 61 62 //全局指针变量,info存储当前缓冲的节点、start和last存储最后一个节点、head存储头节点 63 struct addr *info,*start,*last,*head; 64 //初始化用,与head有关的变量 65 static int n = 0; 66 //加密常量 67 const char KEY='x'; 68 //作者信息 69 const char AUTHOR[] = "乌鸟"; 70 const char VERSION[] = "0.2"; 71 const char DESC[] = "本程序用C写成,鼓励批评指正!"; 72 const char QQ[] = "235173087(欢迎加入,增增人气儿...)"; 73 const char URL[] = "http://www.ihuxu.com"; 74 const char FROM[] = "沈阳化工大学2011级"; 75 const char TIME[] = "2013.02.08"; 76 const char APPNAME[] = "Contact++"; 77 78 /** 79 * @desc 显示系统菜单的实现 80 */ 81 int selectMenu() 82 { 83 char s[80]; 84 int c; 85 printf(" ------------------------------- \n");Sleep(50); 86 printf("|1.Insert a New Record |\n");Sleep(50); 87 printf("|2.Delete a Specific Record |\n");Sleep(50); 88 printf("|3.Search the Record |\n");Sleep(50); 89 printf("|4.Edit the Record |\n");Sleep(50); 90 printf("|5.Display All Records |\n");Sleep(50); 91 printf("|6.About |\n");Sleep(50); 92 printf("|7.Quit |\n");Sleep(50); 93 do 94 { 95 printf(" ------------------------------- \nEnter your choice:"); 96 gets(s); 97 c = atoi(s);//atoi(),把字符串转换为整形。 98 }while(c<1||c>7); 99 return(c); 100 } 101 102 /** 103 * @desc 插入一条记录的实现 104 */ 105 void insRecord() 106 { 107 struct addr *info;//声明缓冲节点,用来指向新记录的节点地址 108 109 for(;;n++) 110 { 111 //分配地址给info 112 info = (struct addr *)malloc(sizeof(struct addr)); 113 //内存不足的情况 114 if(info == NULL) 115 { 116 printf("Out of memory!\n"); 117 return;//计算机脑容量不够了,结束了插入操作 118 } 119 printf("\nSet 0 to name to exit insert!"); 120 inputs("Enter name",info->c_name,C_NAME_SIZE); 121 if(info->c_name[0] == '0') 122 { 123 printf("\n"); 124 break; 125 }else{ 126 inputs("Enter sex",info->c_sex,C_SEX_SIZE); 127 inputs("Enter age",info->c_age,C_AGE_SIZE); 128 inputs("Enter phone",info->c_phone,C_PHONE_SIZE); 129 inputs("Enter qq",info->c_qq,C_QQ_SIZE); 130 inputs("Enter province",info->c_province,C_PROVINCE_SIZE); 131 inputs("Enter city",info->c_city,C_CITY_SIZE); 132 inputs("Enter comment",info->c_comment,C_COMMENT_SIZE); 133 start = linkNode(info,start);//感觉start和last存的是一个节点 134 if(n == 0) 135 { 136 // printf("\nhead has been initialized\nn:%d",n); 137 head = start;//head就是头结点 138 } 139 } 140 } 141 } 142 143 /** 144 * @desc 插入一条记录时,逐行输入信息的实现 145 * @parame char *promot,提示信息 146 * @parame char *info,存储用户输入数据的节点 147 * @parame int count,数据项最大字节数 148 */ 149 void inputs(char *prompt,char *info,int count) 150 { 151 char p[50]; 152 do 153 { 154 printf("\n%s:",prompt); 155 gets(p); 156 // puts(p); 157 if(strlen(p)/2>count) 158 { 159 printf("Too long!\n"); 160 } 161 }while(strlen(p)/2>count); 162 strcpy(info,p);//将本函数的p地址复制给缓冲info地址 163 // puts(info); 164 } 165 166 /** 167 * @desc 在输入好新的消息记录后,需要将新的节点连接在链表中 168 */ 169 struct addr *linkNode(struct addr *current,struct addr *top) 170 { 171 if(!last) 172 { 173 last = current; 174 current->next = NULL; 175 return(current); 176 } 177 else 178 { 179 top->next=current; 180 current->next=NULL; 181 last = current; 182 return(current); 183 } 184 } 185 186 /** 187 * @desc 查找出指定的节点的实现 188 * @return addr *,指定姓名的指针 189 */ 190 struct addr *find() 191 { 192 struct addr *info; 193 info = head; 194 int flag; 195 char str[20]; 196 197 printf("按类别查找 1:名字;2:电话;3:QQ;4:省份;5:城市\n");Sleep(50); 198 printf("请输入相应数字:"); 199 scanf("%d",&flag); 200 // printf("%d",flag); 201 getchar(); 202 printf("请输入数据:"); 203 gets(str); 204 // puts(str); 205 206 //我实在是找不着办法如何动态改变info->后面的东西,正好,让我知道知道什么叫面向过程编程!嘻嘻... 207 switch(flag) 208 { 209 case 1:{ 210 while(info) 211 { 212 if(!strcmp(str,info->c_name)) 213 { 214 return(info); 215 } 216 else 217 { 218 info = info->next; 219 } 220 } 221 return(info = NULL); 222 };break; 223 case 2:{ 224 while(info) 225 { 226 if(!strcmp(str,info->c_phone)) 227 { 228 return(info); 229 } 230 else 231 { 232 info = info->next; 233 } 234 } 235 return(info = NULL); 236 };break; 237 case 3:{ 238 while(info) 239 { 240 if(!strcmp(str,info->c_qq)) 241 { 242 return(info); 243 } 244 else 245 { 246 info = info->next; 247 } 248 } 249 return(info = NULL); 250 };break; 251 case 4:{ 252 while(info) 253 { 254 if(!strcmp(str,info->c_province)) 255 { 256 return(info); 257 } 258 else 259 { 260 info = info->next; 261 } 262 } 263 return(info = NULL); 264 };break; 265 case 5:{ 266 while(info) 267 { 268 if(!strcmp(str,info->c_city)) 269 { 270 return(info); 271 } 272 else 273 { 274 info = info->next; 275 } 276 } 277 return(info = NULL); 278 };break; 279 default:return(info = NULL);break; 280 } 281 282 } 283 284 /** 285 * @desc 查找记录的实现 286 */ 287 void seaRecord() 288 { 289 struct addr *info; 290 info = find(); 291 printf("请稍后,正在检索信息...\n");Sleep(800); 292 if(info == NULL)//如果是空节点,证明没有找到 293 { 294 printf("Not founded,im so sorry!\n\n"); 295 Sleep(300); 296 } 297 else 298 { 299 disRecord(info); 300 } 301 } 302 303 /** 304 * @desc 显示一条记录的实现 305 * @param addr *info,记录的节点 306 */ 307 void disRecord(addr *info) 308 { 309 printf("\nInfo from %s:\n",info->c_name);Sleep(50); 310 printf("Sex:%s\n",info->c_sex);Sleep(50); 311 printf("Age:%s\n",info->c_age);Sleep(50); 312 printf("Phone:%s\n",info->c_phone);Sleep(50); 313 printf("QQ:%s\n",info->c_qq);Sleep(50); 314 printf("Province:%s\n",info->c_province);Sleep(50); 315 printf("City:%s\n",info->c_city);Sleep(50); 316 printf("Comment:%s\n\n",info->c_comment); 317 Sleep(300); 318 } 319 320 /** 321 * @desc 显示全部信息记录的实现 322 */ 323 void disRecords() 324 { 325 struct addr *info = head; 326 327 if(info == NULL) 328 { 329 printf("\nSoryy,there is no record!\n\n"); 330 } 331 else 332 { 333 while(info) 334 { 335 disRecord(info); 336 info = info->next; 337 } 338 return; 339 } 340 } 341 342 /** 343 * @desc 删除记录的实现 344 */ 345 void delRecord() 346 { 347 struct addr *p1,*p2,*info; 348 info = find(); 349 printf("正在检索并删除信息...\n"); 350 Sleep(800); 351 //这个循环是关键,要好好理解哟!反正我明白喽~~~ 352 if(info != NULL) 353 { 354 if(head == info) 355 { 356 head = info->next; 357 printf("%s Deleted Successfully!\n\n",info->c_name); 358 free(info); 359 Sleep(300); 360 } 361 else 362 { 363 p1 = head->next; 364 p2 = head; 365 while(info != p1) 366 { 367 p2 = p1; 368 p1 = p1->next; 369 } 370 p2->next = p1->next; 371 printf("%s Deleted Successfully!\n\n",info->c_name); 372 Sleep(300); 373 free(info); 374 } 375 } 376 else 377 { 378 printf("Im trying,but...but,i coundt find it~~~\n\n"); 379 Sleep(300); 380 } 381 } 382 383 384 /** 385 * @desc 根据ctt文本中的记录,逐条返回数据项,并实现将信息插入链表,即程序启动的初始化状态的实现 386 */ 387 void getInfo() 388 { 389 FILE *fp,*sfp; 390 char ch; 391 char *info[8]; 392 char str[100]; 393 int m = 0;//给info做标记用的,没当m到7就意味着info数组已满。 394 395 //初始化提示信息 396 printf("请稍后,系统正在初始化,先上趟厕所吧...\n"); 397 398 //不知道怎么给指针数组赋值,所以,只能这样喽!!! 399 for(int i = 0; i<8;i++) 400 { 401 info[i] = (char *)malloc( sizeof(char)*50 ); 402 } 403 404 if((sfp = fopen("Contact.ctt","r")) == NULL) 405 { 406 printf("Initial file cannot be opened!\n"); 407 // info = NULL; 408 return; 409 } 410 else 411 { 412 413 if((fp = fopen("tmp.ctt","w+")) != NULL){ 414 system("attrib +s +h tmp.ctt"); 415 416 ch = fgetc(sfp);//先从源文件中读取一个字符 417 418 /** 循环解密读取、并写入临时文件 */ 419 while(!feof(sfp)){//feof()函数检测指针未到文件尾部,返回0 420 fputc(ch^KEY,fp); 421 //printf("%c",ch^'x'); 422 //printf("||"); 423 ch = fgetc(sfp); 424 } 425 rewind(fp);//把文件指针放到文件头部,以便重新读取并存入链表。 426 fclose(sfp); 427 }else{ 428 429 printf("tmp file cannot be opened!\n"); 430 } 431 432 Sleep(1000); 433 printf("正在载入通讯录信息...\n"); 434 while( (ch = fgetc(fp)) != EOF ) 435 { 436 if(ch == ':')//开始标志 437 { 438 int i = 0; 439 while( (ch = fgetc(fp)) != EOF && ch != '\n' ) 440 { 441 str[i] = ch; 442 // printf("%c",str[i]); 443 i++; 444 str[i] = '\0'; 445 } 446 // printf("这是第%d次判断",m); 447 if(m == 7)//数组即将满,打包数组送给insRecord() 448 { 449 450 strcpy(info[m++],str); 451 // puts(info[0]); 452 // printf("这里是m7\n"); 453 m = 0;//归0 454 // printf("传参"); 455 initInputs(info); 456 } 457 else 458 { 459 strcpy(info[m++],str); 460 str[0] = '\0'; 461 // printf("%d",m); 462 } 463 // strcpy(info[0],str); 464 // puts(info[0]); 465 // 此处应该是实现将info的信息逐条加入链表当中的实现 466 // return info; 467 } 468 else 469 { 470 471 } 472 } 473 Sleep(300); 474 printf("初始化完毕!\n"); 475 Sleep(300); 476 fclose(fp); 477 system("del tmp.ctt /q /a"); 478 } 479 } 480 481 /** 482 * @desc 输入完一条记录后,将当前的缓冲节点连接到链表中的实现 483 * @param char *,inifInfo[],缓冲节点 484 */ 485 void initInputs(char *initInfo[]) 486 { 487 struct addr *info;//声明缓冲节点,用来指向新记录的节点地址 488 489 for(;;n++) 490 { 491 //分配地址给info 492 info = (struct addr *)malloc(sizeof(struct addr)); 493 //内存不足的情况 494 if(info == NULL) 495 { 496 printf("Out of memory!\n"); 497 return;//计算机脑容量不够了,结束了插入操作 498 } 499 //插入链表 500 strcpy(info->c_name,initInfo[0]); 501 strcpy(info->c_sex,initInfo[1]); 502 strcpy(info->c_age,initInfo[2]); 503 strcpy(info->c_phone,initInfo[3]); 504 strcpy(info->c_qq,initInfo[4]); 505 strcpy(info->c_province,initInfo[5]); 506 strcpy(info->c_city,initInfo[6]); 507 strcpy(info->c_comment,initInfo[7]); 508 start = linkNode(info,start);//感觉start和last存的是一个节点 509 // puts(start->name); 510 if(n == 0) 511 { 512 // printf("\nhead has been initialized\nn:%d",n); 513 head = start;//head就是头结点 514 } 515 n++; 516 return; 517 } 518 } 519 520 /** 521 * @desc 将链表中的信息全部写到磁盘文件中的实现 522 */ 523 void saveRecords() 524 { 525 char flag='\0'; 526 struct addr *p1,*p2; 527 FILE *fp,*tmpFp; 528 529 printf("\nPress 'Y' or 'y' to Save,'N' or 'n' to Exit:"); 530 flag = getchar(); 531 getchar(); 532 533 if(flag == 'Y' || flag == 'y') //存盘操作 534 { 535 // printf("我已存盘!\n"); 536 if(head != NULL) 537 { 538 p1 = head; 539 Sleep(300); 540 printf("\n存盘中,请稍后,要么再上趟厕所吧......\n"); 541 Sleep(300); 542 do 543 { 544 saveToFile(p1); 545 p2 = p1; 546 p1 = p1->next; 547 free(p2);//释放吧!! 548 // printf("释放中\n"); 549 }while(p1 != NULL); 550 /** 将临时文件tmp.ctt加密,并写到Contact.ctt文件中 */ 551 //这段的目的是删除原来文件中的内容。 552 fp = fopen("contact.ctt","w+"); 553 if( (tmpFp = fopen("tmp.ctt","r")) != NULL){ 554 char ch; 555 ch = fgetc(tmpFp); 556 //加密存盘 557 while(!feof(tmpFp)){ 558 fputc(ch^KEY,fp); 559 ch = fgetc(tmpFp); 560 } 561 }else{ 562 printf("打开tmp.ctt的文件失败~!"); 563 } 564 fclose(fp); 565 fclose(tmpFp); 566 //删除临时文件 567 system("del tmp.ctt /a"); 568 //将结点设置为空 569 head = start = last = NULL; 570 printf("存盘成功!\n"); 571 Sleep(1000); 572 return; 573 574 } 575 else 576 { 577 printf("\nNo Records!\n"); 578 Sleep(1000); 579 return; 580 } 581 } 582 else 583 { Sleep(300); 584 printf("请稍后,正在退出程序...\n"); 585 Sleep(300); 586 printf("退出成功!\n"); 587 Sleep(1000); 588 589 } 590 return; 591 } 592 593 /** 594 * @desc 将每条信息记录放到新建的文件中的实现 595 */ 596 void saveToFile(addr *info) 597 { 598 599 FILE *fp; 600 if ( ( fp = fopen("tmp.ctt","a") ) != NULL ) 601 { 602 system("attrib +s +h tmp.ctt"); 603 fprintf(fp,"Name:%s\n",info->c_name); 604 fprintf(fp,"Sex:%s\n",info->c_sex); 605 fprintf(fp,"Age:%s\n",info->c_age); 606 fprintf(fp,"Phone:%s\n",info->c_phone); 607 fprintf(fp,"QQ:%s\n",info->c_qq); 608 fprintf(fp,"Province:%s\n",info->c_province); 609 fprintf(fp,"City:%s\n",info->c_city); 610 fprintf(fp,"Comment:%s\n",info->c_comment); 611 fclose(fp);//关闭文件,以免数据流失 612 } 613 else 614 { 615 printf("文件不存在,存盘失败"); 616 Sleep(1000); 617 } 618 return; 619 } 620 621 /** 622 * @desc 显示作者信息的实现 623 */ 624 void about() 625 { 626 Sleep(300); 627 printf("\n%s\n",DESC);Sleep(200); 628 printf("Name:%s\n",APPNAME);Sleep(200); 629 printf("Version:%s\n",VERSION);Sleep(200); 630 printf("Powered By %s\n",AUTHOR);Sleep(200); 631 printf("From %s\n",FROM);Sleep(200); 632 printf("URL:%s\n",URL);Sleep(200); 633 printf("QQ交流群:%s\n",QQ);Sleep(200); 634 printf(" ----%s\n\n",TIME); 635 Sleep(800); 636 return; 637 } 638 639 /** 640 * @desc 修改记录的实现 641 */ 642 void editRecord() 643 { 644 struct addr *info; 645 info = find(); 646 printf("请稍后,正在检索信息...\n");Sleep(800); 647 if(info != NULL) 648 { 649 printf("\n修改前的姓名:"); 650 puts(info->c_name); 651 printf("\n请输入修改后的姓名:"); 652 gets(info->c_name); 653 printf("\n修改前的性别:"); 654 puts(info->c_sex); 655 printf("\n请输入修改后的性别:"); 656 gets(info->c_sex); 657 printf("\n修改前的年龄:"); 658 puts(info->c_age); 659 printf("\n请输入修改后的年龄:"); 660 gets(info->c_age); 661 printf("\n修改前的电话:"); 662 puts(info->c_phone); 663 printf("\n请输入修改后的电话:"); 664 gets(info->c_phone); 665 printf("\n修改前的QQ:"); 666 puts(info->c_qq); 667 printf("\n请输入修改后的QQ:"); 668 gets(info->c_qq); 669 printf("\n修改前的省份:"); 670 puts(info->c_province); 671 printf("\n请输入修改后的省份:"); 672 gets(info->c_province); 673 printf("\n修改前的城市:"); 674 puts(info->c_city); 675 printf("\n请输入修改后的城市:"); 676 gets(info->c_city); 677 printf("\n修改前的备注:"); 678 puts(info->c_comment); 679 printf("\n请输入修改后的备注:"); 680 gets(info->c_comment); 681 return; 682 } 683 else 684 { 685 printf("查找的东东不纯在呀~~~\n"); 686 return; 687 } 688 689 } 690 691 /** 692 * @desc 程序入口 693 */ 694 int main(){ 695 696 //这是个初始化函数,将存盘文件Contact.ctt读入缓冲区...^^ 697 getInfo(); 698 699 //菜单的循环 700 for(;;) 701 { 702 switch(selectMenu()) 703 { 704 case 1:insRecord();break; 705 case 2:delRecord();break; 706 case 3:seaRecord();break; 707 case 4:editRecord();break; 708 case 5:printf("正在载入信息...\n");Sleep(800);disRecords();break; 709 case 6:about();break; 710 case 7:saveRecords();exit(0); 711 } 712 }return 0; 713 }
Its Done~