記事ディレクトリ
1. 基本的な仕組みと機能
準備作業:
1. サブモジュールの開発
1.test.c、モジュールのテストリンクの実装
2.contact.c、関数の機能の実装
3.contact.h、関数の名前と使用方法の実装以下では
関数の実装に焦点を当てますが、この記事を読みやすくするためにヘッダー ファイルが最初に提供されています。
2. ヘッダファイルの詳細
#include<stdio.h>//printf,scanf,perror
#include<stdlib.h>//system,malloc,realloc
#include<string.h>//strcmp
//对开辟的大小,方便之后的统一修改。
enum SIZE
{
NAME_SIZE=10,
SEX_SIZE=5,
TELE_SIZE=15,
ADDRE_SIZE=20,
DEFAULT_SIZE=2,
ADD_SIZE=2
};
//功能的选项数字赋予一定的意义
enum function
{
ADD=1,
DEL,
FIND,
MODIFY,
PRINT,
SORT,
EXIT
};
//联系人信息
typedef struct people
{
char name[NAME_SIZE];
int age;
char sex[SEX_SIZE];
char tele[TELE_SIZE];
char addre[ADD_SIZE];
}peo;
//通讯录信息
typedef struct Contact
{
int count;//联系人个数
int capacity;//当前最大容量
peo CON[];//柔性数组利用内存池的概念,使内存管理更加高效,并且free只要一次,更方便。
}contact;
//菜单
void menu();
//初始化通讯录
void Init_contact(contact** p);//要修改一级指针所以要传一级指针的地址用二级指针来接收
//添加联系人信息
void Add_Contact(contact** p);//同理
//打印通讯录
void Print_Contact(contact* p);
//删除联系人信息
void Del_Contact(contact* p);
//查找联系人信息
void Find_Contact(contact* p);
//修改联系人信息
void Modify_Contact(contact* p);
//释放已开辟的内存空间
void Distory_Contact(contact** p);//同理
//按照名字进行排序通讯录
void Sort_Contact(contact* p);
3. 機能の実装
1.印刷メニュー
void menu()
{
printf("******************************************\n");
printf("******** 1.增加联系人 2.删除联系人 *******\n");
printf("******** 3.查找联系人 4.修改联系人 *******\n");
printf("******** 5.打印联系人 6.排序联系人 *******\n");
printf("******** 7.退出通讯录 *******\n");
printf("******************************************\n");
}
パラメータなし、戻り値の型なし (return; と書くことができます)
2.アドレス帳の初期化
void Init_contact(contact** p)
{
*p = (contact*)malloc(4*2 + sizeof(peo) * DEFAULT_SIZE);
if (*p != NULL)
{
(*p)->count = 0;
(*p)->capacity = DEFAULT_SIZE;
}
else
{
perror("Init_contact");
return;
}
}
1. ここで割り当てられるスペースのデフォルトは、2 つの整数 + 最初に保存できる連絡先の数 (2) です。
2. 構造体ポインタは、第 1 レベルのポインタにのみアクセスできます。第 1 レベルのポインタを変更するには、第 2 レベルのポインタを渡す必要があります。 -level 関数へのポインタ ポインタ
3. ここでも calloc を使用できますが、malloc よりも面倒で、効率もわずかに劣ります。
4. スペースを開いて返されたアドレスの確認に注意してください。
3. 連絡先情報を追加する
void Add_Contact(contact** p)
{
int judge = 0;
//判断内存是否够
if ((*p)->count== (*p)->capacity)
{
printf("通讯录已满,请确定是否要增容(1是0否):");
scanf("%d", &judge);
if (judge)
{
contact* ptr = (contact*)realloc(*p, 4 * 2 + sizeof(peo) * ((*p)->capacity+ ADD_SIZE));
if (ptr != NULL)
{
(*p) = ptr;
(*p)->capacity += ADD_SIZE;
printf("增容成功\n");
}
else
{
perror("Add_Contact");
printf("增容失败\n");
return;
}
}
else
{
return;
}
}
//输入信息部分
printf("请输入姓名:");
scanf("%s", (*p)->CON[(*p)->count].name);
printf("请输入年龄:");
scanf("%d", &(*p)->CON[(*p)->count].age);
printf("请输入性别:");
scanf("%s", (*p)->CON[(*p)->count].sex);
printf("请输入电话:");
scanf("%s", (*p)->CON[(*p)->count].tele);
printf("请输入住址:");
scanf("%s", (*p)->CON[(*p)->count].addre);
printf("增加成功!\n");
(*p)->count++;
}
1. realloc の戻り値を確認し、空の場合は速やかにエラーを報告する
2. 情報を入力したら、連絡先の数に 1 を加算する 3.
情報を入力する際に、アクセスしているメンバーの種類を判断して決定するアドレスを追加するかどうか
: アドレス配列名と配列名を入力する場合、それらの値は同じであるため、効果は同じですが、それらの意味は異なります。
4.連絡先情報を印刷する
void Print_Contact(contact* p)
{
if (p->count == 0)
{
printf("通讯录为空!\n");
return;
}
printf("%-5s\t%3s\t%-3s\t%-12s\t%-20s\t\n", "姓名",
"年龄",
"性别",
"电话",
"住址");
int i = 0;
for (i = 0; i < p->count; i++)
{
printf("%-5s\t%3d\t%-3s\t%-12s\t%-20s\t\n", p->CON[i].name,
p->CON[i].age,
p->CON[i].sex,
p->CON[i].tele,
p->CON[i].addre);
}
}
1. アドレス帳に情報がない場合は、時間内に通知する必要があります。
2. 添え字と連絡先の数の関係に注意してください
3. 印刷内容が長すぎる場合は、コードを読みやすくするために行を折り返すことをお勧めします。
4. 印刷するときは、印刷内容をよりシンプルで美しくするために、印刷の形式を調整して設定する必要があります。
5. 名前を見つける
const int Find_By_name(contact* p,char*arr)
{
int i = 0;
for (i = 0; i < p->count; i++)
{
if (strcmp(p->CON[i].name, arr) == 0)
{
return i;
}
}
return -1;
}
1. この関数は関数を実装するモジュールのみを提供するため、const が追加されます
2. strcmp は 2 つの文字列を比較し、等しい場合は 0 を返します
3. 文字列が存在しない場合は -1 を返し、見つかった場合は返しますその添え字
4. この関数は、連絡先の検索、連絡先の変更、および連絡先の削除に使用されます。
6. 連絡先情報の削除
void Del_Contact(contact* p)
{
char name[20] = {
0 };
printf("请输入要删除的联系人:");
scanf("%s", name);
int ret = Find_By_name(p, name);
if (ret!=-1)
{
int i = 0;
for (i = ret; i < p->count-1; i++)
{
p->CON[ret] = p->CON[ret + 1];
}
p->count--;
printf("已删除\n");
}
else
{
printf("查无此人\n");
}
}
1. ここで削除するのは上書きするという考え方ですが、最後の要素に関しては連絡先の数が減った後に追加すると上書きされます。
2. ここで i の範囲に注意してください。次のコードを組み合わせると、配列の範囲外の問題が発生する可能性があることがわかります。そのため、1 を減算します。 3. 構造体配列のメンバーは前のメンバーを直接上書きできます
。これはアレイの特性と同じです。
7. 連絡先を探す
void Find_Contact(contact* p)
{
char name[20] = {
0 };
printf("请输入要查找的联系人:");
scanf("%s", name);
int ret = Find_By_name(p, name);
if (ret != -1)
{
printf("%-5s\t%3s\t%-3s\t%-12s\t%-20s\t\n", "姓名",
"年龄",
"性别",
"电话",
"住址");
printf("%-5s\t%3d\t%-3s\t%-12s\t%-20s\t\n", p->CON[ret].name,
p->CON[ret].age,
p->CON[ret].sex,
p->CON[ret].tele,
p->CON[ret].addre);
}
else
{
printf("查无此人\n");
}
}
8.連絡先情報の変更
void Modify_Contact(contact* p)
{
char name[20] = {
0 };
printf("请输入要修改的联系人:");
scanf("%s", name);
int ret = Find_By_name(p, name);
if (ret != -1)
{
printf("请输入姓名:");
scanf("%s", p->CON[ret].name);
printf("请输入年龄:");
scanf("%d", &p->CON[ret].age);
printf("请输入性别:");
scanf("%s", p->CON[ret].sex);
printf("请输入电话:");
scanf("%s", p->CON[ret].tele);
printf("请输入住址:");
scanf("%s", p->CON[ret].addre);
printf("修改成功!\n");
}
else
{
printf("查无此人\n");
}
}
9. 連絡先を (名前順に) 並べ替えます
int my_cmp(const void* e1, const void* e2)
{
return strcmp(((peo*)e1)->name, ((peo*)e2)->name);
}
void Sort_Contact(contact* p)
{
qsort(p->CON, p->count, sizeof(peo), my_cmp);
printf("排序成功!\n");
}
1. クイックソート用の比較関数を書く必要がある 文字列比較なので文字列比較関数を使う必要がある 2. クイックソート
のパラメータに注意する - ソートされた配列、ソート数、要素のサイズと比較関数。
4. まとめ
1.test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
int main()
{
contact *con =NULL;
Init_contact(&con);
int input = 0;
do
{
menu();
printf("请输入:");
scanf("%d", &input);
switch (input)
{
case ADD:
system("cls");
Add_Contact(&con);
break;
case DEL:
system("cls");
Del_Contact(con);
break;
case FIND:
system("cls");
Find_Contact(con);
break;
case MODIFY:
system("cls");
Modify_Contact(con);
break;
case PRINT:
system("cls");
Print_Contact(con);
break;
case SORT:
system("cls");
Sort_Contact(con);
break;
case EXIT:
system("cls");
Distory_Contact(&con);
printf("退出成功\n");
break;
default:
printf("输入错误\n");
break;
}
} while (input!=EXIT);
return 0;
}
2.連絡先c
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void menu()
{
printf("******************************************\n");
printf("******** 1.增加联系人 2.删除联系人 *******\n");
printf("******** 3.查找联系人 4.修改联系人 *******\n");
printf("******** 5.打印联系人 6.排序联系人 *******\n");
printf("******** 7.退出通讯录 *******\n");
printf("******************************************\n");
}
void Init_contact(contact** p)
{
*p = malloc(4*2 + sizeof(peo) * DEFAULT_SIZE);
if (*p != NULL)
{
(*p)->count = 0;
(*p)->capacity = DEFAULT_SIZE;
}
else
{
perror("Init_contact");
return;
}
}
//const void Think_Capacity(contact** p)
//{
//
// if ((*p)->count == (*p)->capacity)
// {
// contact* ptr = (contact*)realloc(*p, 8 + sizeof(peo) * ((*p)->capacity + ADD_SIZE));
// if (ptr != NULL)
// {
// (*p) = ptr;
// (*p)->capacity += ADD_SIZE;
// printf("增容成功\n");
// }
// else
// {
// perror("Add_Contact");
// printf("增容失败\n");
// return;
// }
// }
//
//}
//void Load_Contact(contact** p)
//{
// FILE* pf = fopen("contact.txt", "rb");
// if (NULL == pf)
// {
// perror("Load_Contact");
// }
// else
// {
// peo tmp = { 0 };
// while (fread(&tmp, sizeof(peo), 1, pf))
// {
// Think_Capacity(p);
// (*p)->CON[(*p)->count] = tmp;
// (*p)->count++;
// }
// }
// fclose(pf);
// pf = NULL;
//}
void Add_Contact(contact** p)
{
int judge = 0;
if ((*p)->count== (*p)->capacity)
{
printf("通讯录已满,请确定是否要增容(1是0否):");
scanf("%d", &judge);
if (judge)
{
contact* ptr = (contact*)realloc(*p, 4 * 2 + sizeof(peo) * ((*p)->capacity + ADD_SIZE));
if (ptr != NULL)
{
(*p) = ptr;
(*p)->capacity += ADD_SIZE;
printf("增容成功\n");
}
else
{
perror("Add_Contact");
printf("增容失败\n");
return;
}
}
else
{
return;
}
}
printf("请输入姓名:");
scanf("%s", (*p)->CON[(*p)->count].name);
printf("请输入年龄:");
scanf("%d", &(*p)->CON[(*p)->count].age);
printf("请输入性别:");
scanf("%s", (*p)->CON[(*p)->count].sex);
printf("请输入电话:");
scanf("%s", (*p)->CON[(*p)->count].tele);
printf("请输入住址:");
scanf("%s", (*p)->CON[(*p)->count].addre);
printf("增加成功!\n");
(*p)->count++;
}
void Print_Contact(contact* p)
{
if (p->count == 0)
{
printf("通讯录为空!\n");
return;
}
printf("%-5s\t%3s\t%-3s\t%-12s\t%-20s\t\n", "姓名", "年龄", "性别", "电话", "住址");
int i = 0;
for (i = 0; i < p->count; i++)
{
printf("%-5s\t%3d\t%-3s\t%-12s\t%-20s\t\n", p->CON[i].name,
p->CON[i].age,
p->CON[i].sex,
p->CON[i].tele,
p->CON[i].addre);
}
}
const int Find_By_name(contact* p,char*arr)
{
int i = 0;
for (i = 0; i < p->count; i++)
{
if (strcmp(p->CON[i].name, arr) == 0)
{
return i;
}
}
return -1;
}
void Del_Contact(contact* p)
{
char name[20] = {
0 };
printf("请输入要删除的联系人:");
scanf("%s", name);
int ret = Find_By_name(p, name);
if (ret!=-1)
{
int i = 0;
for (i = ret; i < p->count-1; i++)
{
p->CON[ret] = p->CON[ret + 1];
}
p->count--;
printf("已删除\n");
}
else
{
printf("查无此人\n");
}
}
void Find_Contact(contact* p)
{
char name[20] = {
0 };
printf("请输入要查找的联系人:");
scanf("%s", name);
int ret = Find_By_name(p, name);
if (ret != -1)
{
printf("%-5s\t%3s\t%-3s\t%-12s\t%-20s\t\n", "姓名", "年龄", "性别", "电话", "住址");
printf("%-5s\t%3d\t%-3s\t%-12s\t%-20s\t\n", p->CON[ret].name, p->CON[ret].age,
p->CON[ret].sex, p->CON[ret].tele,
p->CON[ret].addre);
}
else
{
printf("查无此人\n");
}
}
void Modify_Contact(contact* p)
{
char name[20] = {
0 };
printf("请输入要修改的联系人:");
scanf("%s", name);
int ret = Find_By_name(p, name);
if (ret != -1)
{
printf("请输入姓名:");
scanf("%s", p->CON[ret].name);
printf("请输入年龄:");
scanf("%d", &p->CON[ret].age);
printf("请输入性别:");
scanf("%s", p->CON[ret].sex);
printf("请输入电话:");
scanf("%s", p->CON[ret].tele);
printf("请输入住址:");
scanf("%s", p->CON[ret].addre);
printf("修改成功!\n");
}
else
{
printf("查无此人\n");
}
}
//void Save_Contact(contact* p)
//{
// FILE* pf = fopen("contact.txt", "wb");
// if (NULL == pf)
// {
// perror("Save_Contact:pf");
// }
// else
// {
// int i = 0;
// for (i = 0; i < p->count; i++)
// {
// fwrite(p->CON + i, sizeof(peo), 1, pf);
// }
// }
// printf("保存成功!\n");
// fclose(pf);
// pf = NULL;
//
//}
void Distory_Contact(contact** p)
{
free(*p);
*p = NULL;
}
int my_cmp(const void* e1, const void* e2)
{
return strcmp(((peo*)e1)->name, ((peo*)e2)->name);
}
void Sort_Contact(contact* p)
{
qsort(p->CON, p->count, sizeof(peo), my_cmp);
printf("排序成功!\n");
}
3.連絡先.h
#include<stdio.h>//printf,scanf,perror
#include<stdlib.h>//system,malloc,realloc
#include<string.h>//strcmp
//对开辟的大小,方便之后的统一修改。
enum SIZE
{
NAME_SIZE=10,
SEX_SIZE=5,
TELE_SIZE=15,
ADDRE_SIZE=20,
DEFAULT_SIZE=2,
ADD_SIZE=2
};
//功能的选项数字赋予一定的意义
enum function
{
ADD=1,
DEL,
FIND,
MODIFY,
PRINT,
SORT,
EXIT
};
//联系人信息
typedef struct people
{
char name[NAME_SIZE];
int age;
char sex[SEX_SIZE];
char tele[TELE_SIZE];
char addre[ADD_SIZE];
}peo;
//通讯录信息
typedef struct Contact
{
int count;//联系人个数
int capacity;//当前最大容量
peo CON[];//柔性数组利用内存池的概念,使内存管理更加高效,并且free只要一次,更方便。
}contact;
//菜单
void menu();
//初始化通讯录
void Init_contact(contact** p);//要修改一级指针所以要传一级指针的地址用二级指针来接收
//添加联系人信息
void Add_Contact(contact** p);//同理
//打印通讯录
void Print_Contact(contact* p);
//删除联系人信息
void Del_Contact(contact* p);
//查找联系人信息
void Find_Contact(contact* p);
//修改联系人信息
void Modify_Contact(contact* p);
//释放已开辟的内存空间
void Distory_Contact(contact** p);//同理
//按照名字进行排序通讯录
void Sort_Contact(contact* p);
//保存通讯录信息
//void Save_Contact(contact* p);
//加载通讯录信息
//void Load_Contact(contact* p);
5. ファイル操作に必要な機能
1. 容量の確認
const void Think_Capacity(contact** p)
{
if ((*p)->count == (*p)->capacity)
{
contact* ptr = (contact*)realloc(*p, 8 + sizeof(peo) * ((*p)->capacity + ADD_SIZE));
if (ptr != NULL)
{
(*p) = ptr;
(*p)->capacity += ADD_SIZE;
printf("增容成功\n");
}
else
{
perror("Add_Contact");
printf("增容失败\n");
return;
}
}
}
2.連絡先情報を追加する
void Load_Contact(contact** p)
{
FILE* pf = fopen("contact.txt", "rb");
if (NULL == pf)
{
perror("Load_Contact");
}
else
{
peo tmp = {
0 };
while (fread(&tmp, sizeof(peo), 1, pf))
{
Think_Capacity(p);
(*p)->CON[(*p)->count] = tmp;
(*p)->count++;
}
}
fclose(pf);
pf = NULL;
}
3. 連絡先情報を保存する
void Save_Contact(contact* p)
{
FILE* pf = fopen("contact.txt", "wb");
if (NULL == pf)
{
perror("Save_Contact:pf");
}
else
{
int i = 0;
for (i = 0; i < p->count; i++)
{
fwrite(p->CON + i, sizeof(peo), 1, pf);
}
}
printf("保存成功!\n");
fclose(pf);
pf = NULL;
}
現在のプロジェクトに作成するには (ソース ファイルと同じパス): contact.txt