?? 通訊錄.c
字號:
/*
*File: 通訊錄.c
*--------------------------
*本程序采用結(jié)構(gòu)數(shù)組方式編寫,目前可以存儲1000條信息,每條信息中包含6項子信息。
*程序在運行時會要求用戶輸入文件名,然后把文件中的信息讀取到數(shù)組(內(nèi)存)中。
*因此用戶在程序運行時對記錄所做的任何修改均是對數(shù)組元素內(nèi)容的的修改,這些修改
*只有在用戶執(zhí)行保存指令或者退出程序的時候才會保存到文件中。
*文件中的記錄采用從0開始的編碼方式,即每條記錄均與相同下標的數(shù)組元素對應。
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MaxElement 1000
#define Namelength 25
/*類型定義*/
typedef enum{false, true}bool;
typedef struct{
int n;
char *name;
char *number;
char *flatnum;
char *cellphone;
char *qqnum;
char *address;
}*oneRecord;
typedef struct{
oneRecord classmates[MaxElement];
int matesnum;
}*records;
/*函數(shù)聲明*/
void AddRecord(records db);
oneRecord AddToRecord(int n);
void PrintRecord(FILE *infile, records db);
void GiveInstruction(int num, char *filename);
void DeleteRecord(records db);
void ChangeRecord(records db);
void SearchRecord(records db);
void *GetBlock(size_t nbytes);
void UpdateRecord(char *filename, FILE *infile, records db);
void Guide(void);
FILE *OPENFile(char *filename);
void ScanRecord(FILE *infile, records db);
void RangeRecord(records db);
/*主程序*/
int main()
{
Guide();
system ("pause");
return 0;
}
/*
*Function: Guide
*Usage: Guide();
*----------------------------------
*這個函數(shù)是本程序的主要框架,在用戶輸入文件名后,
*函數(shù)會給出程序的指令代碼,并根據(jù)用戶的選擇來作出反應
*目前本程序共有8項功能。
*/
void Guide(void)
{
FILE *infile, *outfile; //聲明兩個變量以區(qū)分讀寫
records db;
char *line, *string, *newname;
int code;
string = (char *)GetBlock(100 * sizeof(char));
printf("請輸入要創(chuàng)建或打開的文件名:");
gets(string);
infile = outfile = OPENFile(string);
db = (records)GetBlock(sizeof *db);
db->matesnum = 0;
line = GetBlock(100 * sizeof(char));
if(fgets(line, 100, infile) == NULL){ //判斷文件是否為新文件
fprintf(outfile, "%s\n", "姓名: 學號: 宿舍: 手機: QQ: 住址: ");
}else{
ScanRecord(infile, db);
}
while(true){
rewind(infile); //因用戶要使用的功能未知,故使用文件指針復位返回初始狀態(tài)
rewind(outfile);
GiveInstruction(db->matesnum, string);
printf("請輸入命令代號:");
scanf("%d", &code);
if(code == 9) { //當用戶要退出程序時,自動保存記錄,然后退出
UpdateRecord(string, outfile, db);
break;
}
switch(code){ //功能選擇
case 1:
AddRecord(db);
break;
case 2:
DeleteRecord(db);
break;
case 3:
SearchRecord(db);
break;
case 4:
PrintRecord(infile, db);
break;
case 5:
ChangeRecord(db);
break;
case 6:
RangeRecord(db);
break;
case 7:
UpdateRecord(string, outfile, db);
printf("保存完畢。\n");
infile = outfile = OPENFile(string);
fgets(line, 100, infile);
ScanRecord(infile, db);
break;
case 8:
printf("請輸入新文件名(帶擴展名):");
newname = (char *)GetBlock(Namelength * sizeof(char));
scanf("%24s", newname);
getchar();
fclose(infile);
fclose(outfile);
if(rename(string, newname) != 0){
printf("文件重命名失敗。\n");
infile = outfile = OPENFile(string);
break;
}
string = newname;
infile = outfile = OPENFile(string);
printf("文件重命名成功。\n");
break;
default:
printf("錯誤指令,請重新輸入.\n");
break;
}
}
fclose(infile); //關(guān)閉文件
fclose(outfile);
}
/*
*Function: 0PENFile
*Usage: infile = OPENFile(filename);
*--------------------------------------
*這個函數(shù)從用戶處獲得文件名后將其打開
*若文件不存在則會創(chuàng)建一個新文件
*如果無法打開或創(chuàng)建文件,函數(shù)會報錯,并退出程序
*/
FILE *OPENFile(char *filename)
{
FILE *file;
file = fopen(filename, "a+");
if(file == NULL){
printf("無法打開文件!\n");
system ("pause");
exit (0);
}
return (file);
}
/*
*Function: AddRecord
*Usage: AddRecord(db, db->matesnum);
*--------------------------------------
*這個函數(shù)可以往記錄表中添加記錄
*用戶可以選擇添加的位置,并可重復調(diào)用該函數(shù)
*以達到添加多條記錄的目的
*/
void AddRecord(records db)
{
int answer, i;
oneRecord result;
printf("目前菜單:增加記錄。確定增加請輸入1,返回上一級菜單請輸入0:");
while(true){
scanf("%d", &answer);
getchar();
if(answer == 0 || answer == 1) break;
printf("輸入錯誤!請重新輸入:");
}
if(!answer) return; //當用戶輸入0時
printf("是否添加到最后(是 1/否 0)?");
while(true){
scanf("%d", &answer);
getchar();
if(answer == 0 || answer == 1) break;
printf("輸入錯誤!請重新輸入:");
}
if(answer){
result = AddToRecord(db->matesnum);
printf("輸入成功!\n");
db->classmates[db->matesnum] = result;
db->matesnum++;
}else{
printf("是否添加到開始(是 1/否 0)?");
while(true){
scanf("%d", &answer);
getchar();
if(answer == 0 || answer == 1) break;
printf("輸入錯誤!請重新輸入:");
}
if(answer){ //如果用戶輸入1
result = AddToRecord(0);
printf("輸入成功!\n");
for(i = 0; i < db->matesnum; i++){
db->classmates[i]->n++;
}
for(i = db->matesnum; i > 0; i--){
db->classmates[i] = db->classmates[i - 1];
}
db->classmates[0] = result;
db->matesnum++;
}else{
printf("添加為第幾條?");
scanf("%d", &answer);
getchar();
result = AddToRecord(answer);
for(i = answer; i < db->matesnum; i++){ //將從answer開始的記錄的編號后移1個單位
db->classmates[i]->n++;
}
for(i = db->matesnum; i > answer; i--){ //記錄指針后移
db->classmates[i] = db->classmates[i - 1];
}
db->classmates[answer] = result;
db->matesnum++;
}
}
printf("是否繼續(xù)添加(是 1/否 0)?");
while(true){
scanf("%d", &answer);
getchar();
if(answer == 0 || answer == 1) break;
printf("輸入錯誤!請重新輸入:");
}
if(answer) AddRecord(db);
}
/*
*Function: AddToRecord
*Usage: result = AddToRecord(n);
*------------------------------------
*這個函數(shù)在用戶要增加記錄時調(diào)用,添加一條記錄
*用戶輸入完畢后,函數(shù)返回該記錄的指針
*/
oneRecord AddToRecord(int n)
{
oneRecord emp;
printf("請在一行中依次輸入\"姓名\"\"學號\"\"宿舍\"\"手機\"\"QQ號\"\"住址\"\n");
printf("如該項信息空缺,請輸入“無”而不是以空格代替。每項信息中不能有空格,兩項信息之間以空格分隔。\n");
emp = (oneRecord)GetBlock(sizeof *emp);
emp->name = (char *)GetBlock(Namelength * sizeof(char));
emp->number = (char *)GetBlock(Namelength * sizeof(char));
emp->flatnum = (char *)GetBlock(Namelength * sizeof(char));
emp->cellphone = (char *)GetBlock(Namelength * sizeof(char));
emp->qqnum = (char *)GetBlock(Namelength * sizeof(char));
emp->address = (char *)GetBlock(Namelength * sizeof(char));
emp->n = n;
scanf("%6s %7s %8s %11s %11s %20s", emp->name, emp->number, emp->flatnum, emp->cellphone, emp->qqnum, emp->address);
getchar();
return (emp);
}
/*
*Function: PrintRecord
*Usage: PrintRecord(db);
*------------------------------------
*這個函數(shù)用于將記錄顯示在屏幕上
*用戶可以根據(jù)需要選擇顯示部分或全部記錄
*當用戶選擇顯示部分記錄時,若輸入的起始終止編號相同,則只顯示一條記錄
*/
void PrintRecord(FILE *infile, records db)
{
int i = 0, start, end, answer;
char *title;
printf("目前菜單:顯示記錄。顯示部分請輸入0,顯示全部請輸入1,返回上一級菜單請輸入2:");
while(true){
scanf("%d", &answer);
getchar();
if(answer == 0 || answer == 1 || answer == 2) break;
printf("輸入錯誤!請重新輸入:");
}
if(answer == 2) return;
if(db->matesnum == 0){
printf("文件中沒有記錄。\n");
return;
}
if(!answer){ //用戶輸入0時,選擇顯示部分功能
printf("請輸入顯示范圍:\n");
while(true){
printf("請輸入起始標號:");
scanf("%d", &start);
getchar();
printf("請輸入終止標號:");
scanf("%d", &end);
getchar();
if(start <= end && end < db->matesnum) break;
printf("指令錯誤!請重新輸入\n");
}
rewind(infile); //文件指針復位
title = (char *)malloc(100 * sizeof(char));
fgets(title, 100, infile);
printf("%s", title); //顯示文件頭,如“姓名”等
for(i = start; i <= end; i++){
printf("%-4d.%-6s %-7s %-8s %-11s %-11s %-20s\n", db->classmates[i]->n,db->classmates[i]->name,db->classmates[i]->number,db->classmates[i]->flatnum, db->classmates[i]->cellphone, db->classmates[i]->qqnum,db->classmates[i]->address);
}
printf("%d條記錄顯示完成。\n",end - start + 1);
}else{
rewind(infile);
title = (char *)malloc(100 * sizeof(char));
fgets(title, 100, infile);
printf("%s", title);
for(i = 0; i < db->matesnum; i++){
printf("%-4d.%-6s %-7s %-8s %-11s %-11s %-20s\n", db->classmates[i]->n,db->classmates[i]->name,db->classmates[i]->number,db->classmates[i]->flatnum, db->classmates[i]->cellphone, db->classmates[i]->qqnum,db->classmates[i]->address);
}
printf("%d條記錄顯示完成。\n", db->matesnum);
}
}
/*
*Function: GetBlock
*Usage: temp = (char *)GetBlock(n * sizeof(char));
*------------------------------------------------------
*這個函數(shù)用于從堆中動態(tài)分配內(nèi)存
*/
void *GetBlock(size_t nbytes)
{
void *result;
result = malloc(nbytes);
if(result == NULL){
printf("申請內(nèi)存失敗!\n");
system ("pause");
exit (0);
}
return (result);
}
/*
*Function: ScanRecord
*Usage: ScanRecord(infile, db);
*---------------------------------
*這個函數(shù)將文件中的記錄信息掃描到程序
*運行時聲明的數(shù)組中,便于快速更改
*如果文件的格式有誤,函數(shù)會報錯并退出程序
*/
void ScanRecord(FILE *infile, records db)
{
oneRecord temp;
int i = 0, nscan;
char termch;
while(true){
temp = (oneRecord)GetBlock(sizeof *temp);
temp->name = (char *)GetBlock(Namelength * sizeof(char));
temp->number = (char *)GetBlock(Namelength * sizeof(char));
temp->flatnum = (char *)GetBlock(Namelength * sizeof(char));
temp->cellphone = (char *)GetBlock(Namelength * sizeof(char));
temp->qqnum = (char *)GetBlock(Namelength * sizeof(char));
temp->address = (char *)GetBlock(Namelength * sizeof(char));
nscan = fscanf(infile, "%d .%6s %7s %8s %11s %11s %20s%c", &(temp->n), temp->name, temp->number, temp->flatnum, temp->cellphone, temp->qqnum, temp->address, &termch);
if(nscan == EOF) break;
if(temp->n < 0 || temp->n >= MaxElement){ //當記錄的編號超出范圍時
printf("文件中記錄格式有誤,讀取失敗!\n");
system ("pause");
exit(1);
}
db->classmates[temp->n] = temp;
i++;
}
db->matesnum = i;
}
/*
*Function: UpdateRecord
*Usage: UpdateRecord(string, infile, db);
*-----------------------------------------
*這個函數(shù)用于更新文件,即將修改后的記錄信息寫入到文件中
*當這個函數(shù)在用戶選擇了保存記錄功能后被調(diào)用時,它會新建
*一個臨時文件,然后把記錄寫入臨時文件中,最后以原文件名
*將臨時文件重命名,并以之替換原文件
*/
void UpdateRecord(char *filename, FILE *infile, records db)
{
int i;
char *temname;
FILE *outfile;
temname = tmpnam(NULL);
outfile = OPENFile(temname);
fprintf(outfile, "%s\n", " 姓名: 學號: 宿舍: 手機: QQ: 住址: ");
for(i = 0; i < db->matesnum; i++){
fprintf(outfile, "%-4d.%-6s %-7s %-8s %-11s %-11s %-20s\n", db->classmates[i]->n,db->classmates[i]->name,db->classmates[i]->number,db->classmates[i]->flatnum, db->classmates[i]->cellphone, db->classmates[i]->qqnum,db->classmates[i]->address);
fflush(NULL);
}
fclose(infile);
fclose(outfile);
if(remove(filename) != 0 || rename(temname, filename) != 0){
printf("無法重命名臨時文件!\n");
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -