コンテンツ
皆さん、こんにちは
今日は、ポインタ、構造、動的メモリ割り当て、ファイルの読み取りと書き込みなど、アドレスブックの実装について説明します。記事は少し長いです。完全なアドレスブックコードは記事の最後にあります。I辛抱強く読んで何かを得られることを願っています。
1.テスト結果
これは、このアドレス帳を最初に使用した結果であり、ファイルにはまだ連絡先リストがありません。
このプログラムを終了すると、プロジェクトパスの下に以前の連絡先情報を記録したテキストファイルがあることがわかります。プログラムを再度使用すると、ファイルに保存されている連絡先情報が再度読み込まれます。下の写真をご覧ください。
ここでは、連絡先の削除、検索、並べ替え、および変更については説明しません。そうしないと、スクリーンショットが長すぎます 。興味のある友人は、それを自分のコンパイラでテストして、効果を確認できます。それでは、今すぐトピックに行きましょう〜
2.全体的なアイデア
コードの全体的なスタイルは、以前に作成された3つのチェスとマインスイーパーと同じであるか、3つのファイルが作成されるか、各関数の実装が最初にcontact.cファイルに配置され、次にヘッダーファイルcontact.hが配置されます。これらの関数はStatementにあるため、contact.hをtest.cファイルで直接参照でき、contact.cの関数を使用できます。これにより、メインの関数ロジックが明確で簡潔で理解しやすくなります。
3.構造の定義
名簿なので、一人一人の名前、性別、年齢、住所、電話番号などを記録する必要があるので、個人に関するさまざまな情報を含む連絡先構造を定義します。
typedef struct PeoInfo
{
char name[NAME_MAX];
int age;
char number[NUMBER_MAX];
char adress[ADDR_MAX];
char sex[SEX_MAX];
}PeoInfo;
次に、名簿の情報の管理を容易にするために、名簿に関する構造を作成しました。
typedef struct Contact
{
PeoInfo* data;//存放数据
int capacity;//当前通讯录容量
int sz;//实际有效信息数量
}Contact;
4.コア機能の構築
enum Option
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SORT,
SHOW
};
void menu()
{
printf("***************菜单****************\n");
printf("****** 1.add 2.del ******\n");
printf("****** 3.search 4.modify ******\n");
printf("****** 5.sort 6.show ******\n");
printf("****** 0.exit ******\n");
printf("***********************************\n");
}
void test()
{
Contact con;
InitContact(&con);//初始化通讯录
int input = 0;
do
{
menu();
printf("请选择->");
scanf("%d", &input);
switch (input)
{
case ADD:
//增加联系人
AddContact(&con);
break;
case DEL:
//删除联系人
DeleteContact(&con);
break;
case SEARCH:
//查找联系人
FindContact(&con);
break;
case MODIFY:
//修改联系人
ModifyContact(&con);
break;
case SORT:
//对通讯录进行排序(按名字)
SortContact(&con);
break;
case SHOW:
//显示联系人
ShowContact(&con);
break;
case EXIT:
SaveContact(&con);
DestroyContact(&con);
printf("退出通讯录\n");
break;
default:
printf("选择错误,请重新选择!\n");
break;
}
}while (input);
}
ここでは、do-whileステートメントとswitchステートメントを主に使用して、さまざまな関数を直列に接続し、比較的完全なプロジェクトを形成します。操作の対象は名簿の情報であるため、名簿タイプの変数conが定義されます。このコードを見ると、基本的にすべての関数のパラメーターがconであることがわかります。これに関連する各機能について、以下で1つずつ説明します。
5.モジュールコードの解釈
(1)、表示メニュー
これは単純すぎます。コードに直接移動してください〜
void menu()
{
printf("***************菜单****************\n");
printf("****** 1.add 2.del ******\n");
printf("****** 3.search 4.modify ******\n");
printf("****** 5.sort 6.show ******\n");
printf("****** 0.exit ******\n");
printf("***********************************\n");
}
メニューのさまざまな機能については、後で1つずつ説明しますのでご安心ください。
(2)、アドレス帳を初期化します
名簿には最初は連絡先の情報がないので、有効な情報の実際の数を0に設定してから、PeoInfoのサイズのスペースを申請して情報を保存する必要があります。最初は、データもさまざまな情報です。連絡先の数。空に設定します。次のステップは、この名簿の容量を設定することです。スペースアプリケーションが失敗した場合、後の検査とメンテナンスを容易にするためにエラーメッセージが出力されます。
ただし、このプログラムを初めて使用する場合は、プログラムの起動時に以前に記録した連絡先情報が自動的に読み込まれるため、表示や変更に便利です。そこで、ファイルの知識を使用して、情報をロードする関数LoadContact()を作成しました(心配しないでください)。
その特定の実装については後で説明します)。これは初期化中にロードされます。
void InitContact(Contact* pc)
{
assert(pc);
pc->sz = 0;
PeoInfo *tmp = (PeoInfo*)malloc(DEFAULT_SZ *sizeof(PeoInfo));
if (tmp != NULL)
{
pc->data = tmp;
}
else
{
printf("InitContact()::%s\n", strerror(errno));
return;
}
pc->capacity = DEFAULT_SZ;
LoadContact(pc);
}
(3)、名簿の容量を増やす
この機能は、動的メモリ管理の知識を使用して実装されます。名簿PCの容量が実際に保存されている有効な情報の数(アドレス帳に保存されている人数)と等しくなるたびに、後続の連絡先を追加できるように、名簿の容量を増やす必要があります。 。つまり、realloc()関数を使用して、アドレス帳の容量(メモリ)を変更します。
int addcapacity(Contact* pc)
{
assert(pc);
if (pc->sz == pc->capacity)
{
PeoInfo* tmp = (PeoInfo*)realloc(pc->data, sizeof(PeoInfo)*(pc->capacity+ 2));
if (tmp != NULL)
{
pc->data = tmp;
pc->capacity += 2;
//printf("增容成功\n");
return 1;
}
else
{
printf("addcapacity()::%s\n", strerror(errno));
return 0;
}
}
return 1;
}
(4)、連絡先を追加します
AddContact()関数は、連絡先を追加するために使用されます。この関数を呼び出すと、連絡先情報がアドレス帳に追加されます。ただし、連絡先情報を追加するときは、アドレス帳の容量を判断する必要があります。レコードがいっぱいになったとき、容量を増やします。したがって、AddContact()関数の最初に、作成した関数を呼び出します。その関数は、アドレス帳がいっぱいかどうかを判断することです。容量が当面増加しない場合、容量の増加が成功した場合、または増加しないと判断された場合は1が返され、容量の増加が失敗した場合は0が返されます。名簿の容量が十分であるか、容量が正常に増加したと判断された場合にのみ、連絡先をアドレス帳に追加できます。
実際、連絡先の追加は非常に簡単です。つまり、アドレス帳構造の連絡先タイプデータに値を割り当てることです。連絡先が追加されるたびに、アドレス帳pcの有効な情報szの実際の数が1つ増えます。 。
void AddContact(Contact* pc)
{
assert(pc);
int i=addcapacity(pc);
if (i)
{
printf("请输入姓名->");
scanf("%s", pc->data[pc->sz].name);
printf("请输入性别->");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入年龄->");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入住址->");
scanf("%s", pc->data[pc->sz].adress);
printf("请输入电话->");
scanf("%s", pc->data[pc->sz].number);
pc->sz++;
printf("添加联系人成功!\n");
}
else
{
printf("AddContact::%s\n", strerror(errno));
}
}
(5)、連絡先を探す
連絡先情報は、連絡先タイプの配列に格納されます。連絡先の検索は、実際には配列をトラバースすることと同じです。検索する連絡先の名前を入力すると、配列がトラバースされます。配列が見つかった場合はそのインデックスを返し、見つからなかった場合は-1を返します。
int FindPeoInfo(char* name, Contact* pc)//查找联系人,返回其下标
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (*name == *(pc->data[i].name))
{
return i;
}
}
return -1;
}
(6)、連絡先を削除します
連絡先を削除すると、実際には削除された連絡先が上書きされ、連絡先情報が連絡先の後ろに移動して順番に削除されます。連絡先を削除する前に、連絡先に対応する配列インデックスを見つけてから、FindPeoInfoを呼び出す必要があります。 ()関数を実行し、この要素の次の要素と次の要素を順番に進めてカバーします。取材が完了すると、名簿に有効な情報szを持っている実際の人数が1人減ります。
void DeleteContact(Contact* pc)//删除联系人
{
char name[NAME_MAX] = "0";
int i = 0;
printf("请输入要删除的联系人姓名->");
scanf("%s", name);
//查找联系人
int flag=FindPeoInfo(name,pc);
if (flag != -1)
{
for (i = flag; i < pc->sz-1; i++)
{
pc->data[i] = pc->data[i + 1];
}
pc->sz--;
printf("删除成功!\n");
}
else
{
printf("没有找到您需要删除的人!\n");
}
}
(7)、連絡先を変更します
連絡先を変更すると、最初に割り当てられた連絡先タイプのデータ配列の要素が再割り当てされ、変更の効果が得られます。同様に、変更する前に、FindPeoInfo()を呼び出して、変更する連絡先を見つける必要があります。
void ModifyContact(Contact* pc)//修改联系人
{
char name[NAME_MAX] = "0";
printf("请输入要修改的联系人姓名->");
scanf("%s", name);
int flag = FindPeoInfo(name, pc);
if (flag == -1)
{
printf("查无此人\n");
return;
}
else
{
int input = 0;
do
{
/*char rename[NAME_MAX] = "0";
int reage = 0;
char resex[] = "0";
char readdress[] = "0";
char*/
printf("1.姓名 2.年龄 3.性别 4.住址 5.电话 0.退出\n");
printf("请输入要修改的选项(按0退出修改)->");
scanf("%d", &input);
switch (input)
{
case 1:
printf("请输入改正后的姓名->");
scanf("%s", pc->data[flag].name);
break;
case 2:
printf("请输入改正后的年龄->");
scanf("%d", &(pc->data[flag].age));
break;
case 3:
printf("请输入改正后的性别->");
scanf("%s", pc->data[flag].sex);
break;
case 4:
printf("请输入改正后的住址->");
scanf("%s", pc->data[flag].adress);
break;
case 5:
printf("请输入改正后的电话->");
scanf("%s", pc->data[flag].number);
break;
case 0:
break;
default:
printf("输入错误,请重新输入!\n");
break;
}
} while(input);
printf("修改成功!\n");
}
}
(8)、アドレス帳の連絡先を名前で並べ替えます
これも非常に簡単です。qsort()関数を呼び出して、構造体タイプの文字列名を並べ替えるだけです。あまり詳しくは説明しませんが、コードを見てください〜
//对联系人进行排序(按名字)
int compare_Peo(const void* e1, const void* e2)
{
return strcmp(((PeoInfo*)e1)->name,((PeoInfo*)e2)->name);
}
void SortContact(Contact* pc)
{
qsort(pc->data, pc->sz, sizeof(pc->data[0]), compare_Peo);
printf("排序成功\n");
ShowContact(pc);
}
(9)、名簿を表示する
この関数の実装は、最初に、名簿内の有効な情報の実際の数が0であるかどうかを判別することです。0の場合は、名簿に誰もいないことを意味します。0でない場合は、データをトラバースします。連絡先タイプの配列とそれらを1つずつ印刷します。
void ShowContact(Contact* pc)//显示通讯录
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录里无联系人!\n");
}
else
{
int i = 0;
printf("%-7s\t%-7s\t%-6s\t%-20s\t%-15s\n", "姓名", "性别", "年龄", "住址", "电话");
for (i = 0; i < pc->sz; i++)
{
printf("%-7s\t%-7s\t%-6d\t%-20s\t%-15s\n",
pc->data[i].name, pc->data[i].sex, pc->data[i].age,
pc->data[i].adress, pc->data[i].number);
}
}
}
(10)、ファイルを保存します
この機能の機能は、名簿の情報の変更をバイナリ形式のファイルに書き込んで、このプロジェクトのパスに保存することです。これは、次回プログラムを起動するときに表示するのに便利です。
//保存文件
void SaveContact(Contact* pc)
{
FILE* fp = fopen("contact1.txt", "wb");
if (fp == NULL)
{
printf("SaveContact::open for writting:%s", strerror(errno));
return;
}
//写入文件
int i = 0;
for (i = 0; i < pc->sz; i++)
{
fwrite(pc->data + i, sizeof(PeoInfo), 1, fp);
}
//关闭文件
fclose(fp);
fp = NULL;
}
(11)、ファイル情報をロードします
このプログラムを開始するときは、最初にアドレス帳を初期化し(この手順は上記で説明しました)、次に以前に保存した連絡先情報をロードする必要があります。これにより、このプログラムを以前の連絡先情報に使用できるようになります。ビューを変更しました。ファイル情報を読み取ることは、連絡先を追加することにも相当するため、読み取る前に、アドレス帳の容量を判断して、アドレス帳を増やす必要があるかどうかを確認する必要があります。
void LoadContact(Contact* pc)
{
//打开文件
FILE* pf = fopen("contact1.txt", "rb");
if (pf == NULL)
{
printf("LoadContact::open for reading:%s\n", strerror(errno));
return;
}
//读文件
PeoInfo tmp = { 0 };
while (fread(&tmp, sizeof(PeoInfo), 1, pf))
{
addcapacity(pc);
pc->data[pc->sz] = tmp;
pc->sz++;
}
//关闭文件
fclose(pf);
pf = NULL;
}
(12)、リリーススペース
アドレスブックの連絡先タイプ配列のスペースは動的に適用されるため、このプログラムを終了するときは、最初にSaveContact()関数を使用して連絡先情報を保存し、次にこのスペースを解放して、これへのポインターをポイントします。スペース。不正アクセスを回避するには、NULLに設定します。
void DestroyContact(Contact* pc)//销毁
{
free(pc->data);
pc->data = NULL;
pc->capacity = 0;
pc->sz = 0;
}
6、コードの全体的な実装
contact.h
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
//#define MAX_SIZE 10
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 30
#define NUMBER_MAX 12
#define DEFAULT_SZ 3
typedef struct PeoInfo
{
char name[NAME_MAX];
int age;
char number[NUMBER_MAX];
char adress[ADDR_MAX];
char sex[SEX_MAX];
}PeoInfo;
typedef struct Contact
{
PeoInfo* data;//存放数据
int capacity;//当前通讯录容量
int sz;//实际有效信息数量
}Contact;
void InitContact(Contact* pc);//初始化通讯录
void AddContact(Contact* pc);//增加联系人
void ShowContact(Contact* pc);//显示通讯录
void DeleteContact(Contact* pc);//删除联系人
int FindPeoInfo(char* name, Contact* pc);//查找联系人,返回其下标
void FindContact(Contact* pc);//查找联系人
void ModifyContact(Contact* pc);//修改联系人
void SortContact(Contact* pc);//对联系人进行排序(按名字)
int addcapacity(Contact* pc);//增容
void DestroyContact(Contact* pc);//销毁通讯录
void LoadContact(Contact* pc);//加载通讯录
void SaveContact(Contact* pc);//保存通讯录
contact.c
#include"contact.h"
//初始化通讯录
void InitContact(Contact* pc)
{
assert(pc);
pc->sz = 0;
PeoInfo *tmp = (PeoInfo*)malloc(DEFAULT_SZ *sizeof(PeoInfo));
if (tmp != NULL)
{
pc->data = tmp;
}
else
{
printf("InitContact()::%s\n", strerror(errno));
return;
}
pc->capacity = DEFAULT_SZ;
LoadContact(pc);
}
//判断是否增容
int addcapacity(Contact* pc)
{
assert(pc);
if (pc->sz == pc->capacity)
{
PeoInfo* tmp = (PeoInfo*)realloc(pc->data, sizeof(PeoInfo)*(pc->capacity+ 2));
if (tmp != NULL)
{
pc->data = tmp;
pc->capacity += 2;
//printf("增容成功\n");
return 1;
}
else
{
printf("addcapacity()::%s\n", strerror(errno));
return 0;
}
}
return 1;
}
//加载文件
void LoadContact(Contact* pc)
{
//打开文件
FILE* pf = fopen("contact1.txt", "rb");
if (pf == NULL)
{
printf("LoadContact::open for reading:%s\n", strerror(errno));
return;
}
//读文件
PeoInfo tmp = { 0 };
while (fread(&tmp, sizeof(PeoInfo), 1, pf))
{
addcapacity(pc);
pc->data[pc->sz] = tmp;
pc->sz++;
}
//关闭文件
fclose(pf);
pf = NULL;
}
//增加联系人
void AddContact(Contact* pc)
{
assert(pc);
int i=addcapacity(pc);
if (i)
{
printf("请输入姓名->");
scanf("%s", pc->data[pc->sz].name);
printf("请输入性别->");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入年龄->");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入住址->");
scanf("%s", pc->data[pc->sz].adress);
printf("请输入电话->");
scanf("%s", pc->data[pc->sz].number);
pc->sz++;
printf("添加联系人成功!\n");
}
else
{
printf("AddContact::%s\n", strerror(errno));
}
}
void ShowContact(Contact* pc)//显示通讯录
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录里无联系人!\n");
}
else
{
int i = 0;
printf("%-7s\t%-7s\t%-6s\t%-20s\t%-15s\n", "姓名", "性别", "年龄", "住址", "电话");
for (i = 0; i < pc->sz; i++)
{
printf("%-7s\t%-7s\t%-6d\t%-20s\t%-15s\n",
pc->data[i].name, pc->data[i].sex, pc->data[i].age,
pc->data[i].adress, pc->data[i].number);
}
}
}
int FindPeoInfo(char* name, Contact* pc)//查找联系人,返回其下标
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (*name == *(pc->data[i].name))
{
return i;
}
}
return -1;
}
void DeleteContact(Contact* pc)//删除联系人
{
char name[NAME_MAX] = "0";
int i = 0;
printf("请输入要删除的联系人姓名->");
scanf("%s", name);
//查找联系人
int flag=FindPeoInfo(name,pc);
if (flag != -1)
{
for (i = flag; i < pc->sz-1; i++)
{
pc->data[i] = pc->data[i + 1];
}
pc->sz--;
printf("删除成功!\n");
}
else
{
printf("没有找到您需要删除的人!\n");
}
}
void FindContact(Contact* pc)//查找联系人
{
char name[NAME_MAX] = "0";
printf("请输入要查找的联系人姓名->");
scanf("%s", name);
int flag = FindPeoInfo(name, pc);
if (flag != -1)
{
printf("%-7s\t%-7s\t%-6s\t%-20s\t%-15s\n", "姓名", "性别", "年龄", "住址", "电话");
printf("%-7s\t%-7s\t%-6d\t%-20s\t%-15s\n",
pc->data[flag].name, pc->data[flag].sex, pc->data[flag].age,
pc->data[flag].adress, pc->data[flag].number);
}
else
{
printf("查无此人!\n");
}
}
void ModifyContact(Contact* pc)//修改联系人
{
char name[NAME_MAX] = "0";
printf("请输入要修改的联系人姓名->");
scanf("%s", name);
int flag = FindPeoInfo(name, pc);
if (flag == -1)
{
printf("查无此人\n");
return;
}
else
{
int input = 0;
do
{
/*char rename[NAME_MAX] = "0";
int reage = 0;
char resex[] = "0";
char readdress[] = "0";
char*/
printf("1.姓名 2.年龄 3.性别 4.住址 5.电话 0.退出\n");
printf("请输入要修改的选项(按0退出修改)->");
scanf("%d", &input);
switch (input)
{
case 1:
printf("请输入改正后的姓名->");
scanf("%s", pc->data[flag].name);
break;
case 2:
printf("请输入改正后的年龄->");
scanf("%d", &(pc->data[flag].age));
break;
case 3:
printf("请输入改正后的性别->");
scanf("%s", pc->data[flag].sex);
break;
case 4:
printf("请输入改正后的住址->");
scanf("%s", pc->data[flag].adress);
break;
case 5:
printf("请输入改正后的电话->");
scanf("%s", pc->data[flag].number);
break;
case 0:
break;
default:
printf("输入错误,请重新输入!\n");
break;
}
} while(input);
printf("修改成功!\n");
}
}
//对联系人进行排序(按名字)
int compare_Peo(const void* e1, const void* e2)
{
return strcmp(((PeoInfo*)e1)->name,((PeoInfo*)e2)->name);
}
void SortContact(Contact* pc)
{
qsort(pc->data, pc->sz, sizeof(pc->data[0]), compare_Peo);
printf("排序成功\n");
ShowContact(pc);
}
void DestroyContact(Contact* pc)//空间销毁
{
free(pc->data);
pc->data = NULL;
pc->capacity = 0;
pc->sz = 0;
}
//保存文件
void SaveContact(Contact* pc)
{
FILE* fp = fopen("contact1.txt", "wb");
if (fp == NULL)
{
printf("SaveContact::open for writting:%s", strerror(errno));
return;
}
//写入文件
int i = 0;
for (i = 0; i < pc->sz; i++)
{
fwrite(pc->data + i, sizeof(PeoInfo), 1, fp);
}
//关闭文件
fclose(fp);
fp = NULL;
}
test.c
#include"contact.h"
enum Option
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SORT,
SHOW
};
void menu()
{
printf("***************菜单****************\n");
printf("****** 1.add 2.del ******\n");
printf("****** 3.search 4.modify ******\n");
printf("****** 5.sort 6.show ******\n");
printf("****** 0.exit ******\n");
printf("***********************************\n");
}
void test()
{
Contact con;
InitContact(&con);//初始化通讯录
int input = 0;
do
{
menu();
printf("请选择->");
scanf("%d", &input);
switch (input)
{
case ADD:
//增加联系人
AddContact(&con);
break;
case DEL:
//删除联系人
DeleteContact(&con);
break;
case SEARCH:
//查找联系人
FindContact(&con);
break;
case MODIFY:
//修改联系人
ModifyContact(&con);
break;
case SORT:
//对通讯录进行排序(按名字)
SortContact(&con);
break;
case SHOW:
//显示联系人
ShowContact(&con);
break;
case EXIT:
SaveContact(&con);
DestroyContact(&con);
printf("退出通讯录\n");
break;
default:
printf("选择错误,请重新选择!\n");
break;
}
}while (input);
}
int main()
{
test();
return 0;
}
共有するのはこれで終わりです。どうですか?とても簡単ですか?質問がある、または理解できない友達は、何か見つけたら私に尋ねることができます。
何か問題があったり、改善できる場合は、コメント欄やプライベートチャットで投稿することもできます。ぜひご提案をお待ちしております。