通讯录工程的构建(一)
这个本是c语言课程设计的任务,完成这样一项工程还是花了不少时间,也学到了不少东西,应该说,c语言基本的东西全部能掌握了。
但是在编写的时候还是得到了许多教训。编写这样的大工程,首先要有清晰的思路,流程图什么的我是懒得画,但是得有个树状图,大体框架必须清楚。这一点HCM还是给了我不少启发。我习惯先写子函数,结果后来链表操作遇到文件保存的问题就傻了眼,幸好灵光一现想到转换成结构体数组。文件保存的时候我又一开始写进了子函数,最后写main函数的时候发现子函数里面的文件操作根本不需要,程序最后保存一下就好了。幸好文件的代码都差不多,才不至于做很多无用功。好了,废话不多说,进入正题吧。
这一篇是 main 函数的介绍,子函数下一篇再讲。
首先来解释一下结构体的组成:name,tel,email 为三个字符数组;sort用来存放联系人类型(办公,个人,商务);yn用来存放y 或者n,做判断依据;*next为链表尾指针。
定义了结构体之后,为方便起见,利用 typedef 将其简化为NODE标识。
struct stu { char name[20],tel[13],email[30]; char sort,yn; struct stu *next; }; typedef struct stu NODE;
下面利用main函数来看一看整个程序的结构(” //--------中文”为解释,“//English” 为编程时的注释)。
1 main() 2 3 { 4 5 //--------声明部分不看-------- 6 7 8 9 FILE *in,*f_name,*ll; 10 11 NODE *head; 12 13 int _new(NODE *head,char filename[]); 14 15 NODE *create(); 16 17 int add(NODE* head); 18 19 void check(NODE* head); 20 21 int del(NODE* head); 22 23 int func(); 24 25 int len,fun,lop=0,i; 26 27 NODE stu[15]; 28 29 char ctn='y',yon; 30 31 char fname[50]; 32 33 char ch; 34 35 void trans(NODE* head,int len,NODE lin[]); 36 37 void build(NODE* head,int len,NODE stu[]); 38 39 40 41 //--------声明部分不看-------- 42 43 44 45 // read stu[] 46 47 48 49 //--------利用file_name.dat 文件保存数据文件(如telbook.dat) 地址 50 51 52 53 // open file address 54 55 if((f_name=fopen("D:\\file_name.dat","rb"))==NULL) 56 57 { 58 59 puts("\t\t* cannot open the file1 *"); 60 61 exit(0); 62 63 } 64 65 66 67 rewind(f_name); 68 69 70 71 //--------将地址保存在变量fname中 72 73 74 75 fgets(fname,49,f_name); 76 77 // note filename 78 79 80 81 fclose(f_name); 82 83 // filename end 84 85 86 87 //--------输出文件路径,下行可以注释掉 88 89 printf(" filename: %s ",fname); 90 91 92 93 94 95 //--------从len.dat文件读入节点个数len,字符型,因为文件存取不能对整型,用字符型进行操作。文件指针小写的LL ( *ll ) 96 97 98 99 if((ll=fopen("D:\\len.dat","rb"))==NULL) 100 101 { 102 103 puts("* cannot open the file len *"); 104 105 exit(0); 106 107 } 108 109 110 111 rewind(ll); 112 113 114 115 ch=fgetc(ll); 116 117 118 119 len=ch; 120 121 122 123 fclose(ll); 124 125 126 127 //--------读取结构体数组,存入变量stu[]中 (因为链表不能存入文件,所以将其转化成结构体数组进行存储) 128 129 130 131 if((in=fopen(fname,"rb"))==NULL) 132 133 { 134 135 puts("\t\t* cannot open the file2 *"); 136 137 exit(0); 138 139 } 140 141 142 143 rewind(in); 144 145 146 147 for(i=0;i<len;i++) 148 149 fread(&stu[i],sizeof(NODE),1,in); 150 151 152 153 fclose(in); 154 155 156 157 //printf("\nlen=%d\n",len); 158 159 160 161 //--------将整个通讯录打印一遍 162 163 164 165 printf("\n\n **************************** Phone Book ****************************\n"); 166 167 168 169 170 171 172 173 for(i=0;i<len;i++) 174 175 { 176 177 printf("\n\t\t\tNO.%d\n\t\t\tName : %s\n",i+1,stu[i].name); 178 179 printf("\t\t\tTel : %s\n",stu[i].tel); 180 181 printf("\t\t\tSort : %c\n",stu[i].sort); 182 183 printf("\t\t\tEmail : %s\n",stu[i].email); 184 185 } 186 187 puts("\n\n"); 188 189 puts("\n\n* Tips: when you enter 'sort' information, 'a' means official, 'b' means personal, 'c' means commercial *\n"); 190 191 192 193 //--------创建表头 (create是建立头结点的函数) 194 195 head=create(); 196 197 198 199 //--------将已读入的结构体数组转化为链表,方便操作(build为结构体数组转化为链表的函数) 200 201 build(head,len,stu); 202 203 204 205 //--------下面是操作界面,ctn代表continue 206 207 208 209 while(ctn=='y') 210 211 { 212 213 //if(lop) fun=func(); 214 215 switch(func()) 216 217 { 218 219 case 1: check(head);break; 220 221 case 2: if(len>=15) {printf("\n\n\t\t* The total number should be less than 15 *");break;}if(add(head)) len++;else puts("\n\n\t\t* Add Fail *");break; 222 223 //--------case 2 首先判断节点是否已达到15,若是,则不进行add操作。进行add操作后,len要加一。 224 225 226 227 case 3: if(revise(head));else puts("\n\n\t\t* Revise Fail *");break; 228 229 //--------如果修改不成功,则输出修改失败 230 231 232 233 case 4: if(del(head)) len--;else puts("\n\n\t\t* Delete Fail *");break; 234 235 //--------进行delete操作后,len要减一。 236 237 238 239 case 5: printf("\n\n\n"); 240 241 printf("\t\t* Do you want to create a new phone book and destroy the previous phone book?(y/n) *"); 242 243 getchar(); 244 245 yon=getchar(); 246 247 getchar(); 248 249 //--------先让用户确定是否新建一个通讯录并且摧毁已有的通讯录 250 251 if(yon=='y') 252 253 { 254 255 //printf("entered"); 256 257 head=create(); 258 259 len=_new(head,fname); 260 261 //--------将新通讯录长度传回main函数 262 263 } 264 265 puts("\n\n\t\t* Create End *"); 266 267 268 269 break; 270 271 case 6: printf("\n\n **************************** Phone Book ****************************\n"); 272 273 274 275 for(i=0;i<len;i++) 276 277 { 278 279 printf("\n\t\t\tNO.%d\n\t\t\tName : %s\n",i+1,stu[i].name); 280 281 printf("\t\t\tTel : %s\n",stu[i].tel); 282 283 printf("\t\t\tSort : %c\n",stu[i].sort); 284 285 printf("\t\t\tEmail : %s\n",stu[i].email); 286 287 } 288 289 getchar(); 290 291 //--------这里的getchar接受换行符 292 293 break; 294 295 } 296 297 hah1:printf("\n\n\t\t* Continue?(y/n) *"); 298 299 ctn=getchar(); 300 301 getchar(); 302 303 //printf("\nctn=%c",ctn); 304 305 306 307 //--------如果既不输入y也不输入n,则返回询问句 308 309 if(ctn!='y'&&ctn!='n') goto hah1; 310 311 } 312 313 314 315 //--------将链表转化为结构体数组进行保存(trans为转化函数) 316 317 trans(head,len,stu); 318 319 320 321 //--------把最终的通讯录打印一遍 322 323 printf("\n\n **************************** Phone Book ****************************\n"); 324 325 326 327 for(i=0;i<len;i++) 328 329 { 330 331 printf("\n\t\t\tNO.%d\n\t\t\tName : %s\n",i+1,stu[i].name); 332 333 printf("\t\t\tTel : %s\n",stu[i].tel); 334 335 printf("\t\t\tSort : %c\n",stu[i].sort); 336 337 printf("\t\t\tEmail : %s\n",stu[i].email); 338 339 } 340 341 puts("\n\n"); 342 343 344 345 //--------将结构体数组保存进数据文件 346 347 if((in=fopen(fname,"wb"))==NULL) 348 349 { 350 351 puts("\t\t* Cannot open the file *"); 352 353 exit(0); 354 355 } 356 357 358 359 rewind(in); 360 361 362 363 for(i=0;i<len;i++) 364 365 fwrite(&stu[i],sizeof(NODE),1,in); 366 367 368 369 fclose(in); 370 371 372 373 //--------将len保存进len.dat文件 374 375 if((in=fopen("D:\\len.dat","wb"))==NULL) 376 377 { 378 379 puts("\t\t* Cannot open the file *"); 380 381 exit(0); 382 383 } 384 385 386 387 rewind(in); 388 389 390 391 fputc(len,in); 392 393 fclose(in); 394 395 396 397 //printf("\nlen=%d",len); 398 399 400 401 puts("\n\n\t\t* Program End *"); 402 403 }