学习C语言已有一段时间,我虽不敢说代码水平尚可,但学习一段时间总需要有些成果。下半年开学后,专业课程增多,我需要每天完成学校任务,所花的时间也不算少,但还是有些空闲的。想起自己之前学过用C语言写通讯录,其中功能较为全面,增删查改皆有,且可以直接展示所有已存储的联系人。不过这和我们生活中的用的通讯录还是有些不同的,像批量删除,指定删除等功能,实际上当我自己做起来后才发现其代码量并不少,可能也是因为这个,这些更适合自己摸索着做吧。
我从九月末旬开始创建文件,做完整的通讯录,自己想一些功能,并让朋友也想一些要实现的功能,这里面就有熟悉的长按删除,当然我是做不出来的,以及其他一些我能力达不到的功能,我觉得这毕竟涉及真正一个应用的完成,我也只是用自己平庸的C语言水平来展现功能实现的过程罢了。整体思路并不是很简洁,因为我看到为了一个功能而写的代码很多,另一个方面就是,我没见到过真正大量的代码是什么样子......
最近我才开始接触初阶数据结构,就在里面写了些注释,是自己对这个函数时、空间复杂度的分析,所以这肯定有错。另外,整个通讯录并没有完成,你可以看到我在初始化时就加载进了文件,但是这个程序还不能代码式地退出。对于里面的变量我已经注释了其用处,应该可以读明白。这个通讯录拖沓了很久,我必须承认我的懒惰在起作用。整个通讯录所呈现的我的编程思路我自认为只能作为一个基础水平的思路,还有很多可改变之处。今天是1024程序员节,且希望各位看官能看个爽吧。
头文件project.h
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100
#define NAME 20//姓名
#define SEX 7//性别
#define ADDRESS 20//地址
#define OCC 10//职业
#define NUMBER 15//电话
#define CP 20//动态开辟的空间
#define ADD_SZ 10//增容时所用
#define RS 30
#define LS 40//最多可选择删除的数量
struct PeoInfo
{
char name[NAME];
char sex[SEX];
char address[ADDRESS];
char occ[OCC];
char number[NUMBER];
int age;
};
struct Contact
{
struct PeoInfo* data;
int sz;
int capacity;
};
void InitContact(struct Contact* ps);
void LoadContact(struct Contact* ps);
void AddContact(struct Contact* ps);
void DelContact(struct Contact* ps);
void ChaContact(const struct Contact* ps);
void SortContact(const struct Contact* ps);
void ModifyContact(const struct Contact* ps);
void ShowContact(const struct Contact* ps);
int SearchContact(const struct Contact* ps);
project2.c
#include "project.h"
int r = 0;//回收站的sz
int rt = RS;//回收站的capacity
int pl[LS];//批量删除用来存储序号
int l = 0;//批量删除存储序号数
int z = 0;//泛用性··
static int FindByName(char name[], const struct Contact* pf)//时间O(N/2), 空间O(1)
{
assert(name && pf);
int i = 0;
for (i = 0; i < pf->sz; i++)
{
if (0 == strcmp(pf->data[i].name, name))
{
return i;
}
}
return -1;
}
static int check_capacity(struct Contact* ps)//时间O(1), 空间O(ADD_SZ)
{
assert(ps);
if (ps->sz == ps->capacity)
{
struct PeoInfo* ptr = (struct PeoInfo*)realloc(ps->data, (ps->capacity + ADD_SZ) * sizeof(struct PeoInfo));
if (ptr != NULL)
{
ps->data = ptr;
ps->capacity += ADD_SZ;
printf("增容成功\n");
return 1;
}
else
{
perror("AddContact()");
return 0;
}
}
else
return 1;
}
static int Hsz(struct PeoInfo* rs)//时间O(1), 空间O(ADD_SZ)
{
struct PeoInfo* ptr = (struct PeoInfo*)realloc(rs, (r + ADD_SZ) * sizeof(struct PeoInfo));
if (ptr != NULL)
{
rs = ptr;
rt += ADD_SZ;
printf("增容成功\n");
return 1;
}
else
{
perror("ZDDel()");
return 0;
}
}
void LoadContact(struct Contact* ps)//时间O(ps->sz), 空间O(ps->sz)
{
FILE* pfr = fopen("E://txl.txt", "r");
if (pfr == NULL)
{
perror("LoadContact::fopen");
return;
}
struct PeoInfo ptr = { 0 };
while (fread(&ptr, sizeof(struct PeoInfo), 1, pfr))
{
//检查是否要增容
check_capacity(ps);
ps->data[ps->sz] = ptr;
ps->sz++;
}
fclose(pfr);
pfr = NULL;
}
void InitContact(struct Contact* ps)//时间O(1), 空间O(CP)
{
assert(ps);
ps->data = (struct PeoInfo*)malloc(CP * sizeof(struct PeoInfo));
if (ps->data == NULL)
{
perror("InitContact()");
return;
}
ps->sz = 0;
ps->capacity = CP;
LoadContact(ps);
}
void AddContact(struct Contact* ps)//时间O(1), 空间O(1)
{
assert(ps);
if (0 == check_capacity(ps))
{
return;
}
else
{
printf("请输入要添加的名字:>");
scanf("%s", ps->data[ps->sz].name);
printf("请输入要添加的性别:>");
scanf("%s", ps->data[ps->sz].sex);
printf("请输入要添加的电话号码:>");
scanf("%s", ps->data[ps->sz].number);
printf("请输入要添加的地址:>");
scanf("%s", ps->data[ps->sz].address);
printf("请输入要添加的职业:>");
scanf("%s", ps->data[ps->sz].occ);
printf("请输入要添加的年龄:>");
scanf("%d", &ps->data[ps->sz].age);
ps->sz++;
printf("已成功添加第%d个联系人\n", ps->sz);
}
}
static int ZDDel(struct Contact* pz, struct PeoInfo* rs)//时间O(pz->sz - 1 - m), 空间O(3)
{
assert(pz);
assert(rs);
int j = 0;
int i = 0;
char name[NAME];//存储要操作的名字
if (r + 1 == rt)
{
i = Hsz(rs);
if (1 == i)
;
else
{
printf("虚拟回收站扩容失败,请重新进行删除\n");
return 1;
}
}
printf("请输入要删除人的名字: >");
scanf("%s", &name[z]);
int m = FindByName(name, pz);
if (m == -1)
{
printf("要删除的人不存在\n");
return 3;
}
else
{
FILE* hsz = fopen("E://hsz.txt", "w");
if (hsz == NULL)
{
perror("ZDDel::fopen");
printf("文件创建失败,请重新进行删除\n");
return 2;
}
fwrite(pz->data + m, sizeof(struct PeoInfo*), 1, hsz + z);
z++;//name数组的下标,如果为0,添入1个,则变为1
fclose(hsz);
hsz = NULL;
*(rs + r) = pz->data[m];
r++;
if (r + 1 == rt)
{
i = Hsz(rs);
if (1 == i)
;
else if (2 == i)
;
else
{
printf("虚拟回收站扩容失败,请重新进行删除\n");
return 1;
}
}
else
;
for (j = m; j < pz->sz - 1 - m; j++)
{
pz->data[j] = pz->data[j + 1];
}
pz->sz--;
printf("成功删除指定联系人\n");
}
return 0;
}
static int PLDel(struct Contact* pp, struct PeoInfo* rs)
{
assert(pp);
int i = 0;
int j = 0;
int n = 0;
int m = 0;
int o = 0;
struct PeoInfo* tmp = (struct PeoInfo*)calloc(10, sizeof(struct PeoInfo));
if (r + 1 == rt)
{
j = Hsz(rs);
if (1 == j)
;
else if (2 == j)
;
else
{
printf("虚拟回收站扩容失败,请重新进行删除\n");
return 1;
}
}
printf("选择结束后写入666来进行下一步\n");
printf("请选择要删除的序列号: >");
while (i <= LS)
{
scanf("%d", &pl[i]);
l++;
i++;
if (i == LS)
{
printf("最多选择%d个!\n", LS);
printf("是否确定删除? 1.确定 2.取消\n");
scanf("%d", &n);
if (1 == n)
{
FILE* hsz = fopen("E://hsz.txt", "w");
if (hsz == NULL)
{
perror("ZDDel::fopen");
printf("文件创建失败,请重新进行删除\n");
printf("已将选中的序列号保存\n");
return 2;
}
struct PeoInfo* pld = (struct PeoInfo*)calloc(LS , sizeof(struct PeoInfo));
for (o = 0; o < i; o++)
{
fwrite(pp->data + (pl[o]), sizeof(struct PeoInfo*), 1, hsz + z);
*(pp->data + (pl[o])) = *(pld + o);
z++;
}
fclose(hsz);
hsz = NULL;
SortContact(pp);
for (i; i >= 0; i--)
{
pl[i] = 0;
}
printf("删除成功\n");
}
else
{
printf("已将选中的序列号保存\n");
return 2;
}
}
else if (666 == pl[i - 1])
{
printf("是否确定删除? 1.确定 2.取消\n");
scanf("%d", &n);
if (1 == n)
{
FILE* hsz = fopen("E://hsz.txt", "w");
if (hsz == NULL)
{
perror("ZDDel::fopen");
printf("文件创建失败,请重新进行删除\n");
printf("已将选中的序列号保存\n");
return 2;
}
struct PeoInfo* pld = (struct PeoInfo*)calloc(LS, sizeof(struct PeoInfo));
for (o = 0; o < i; o++)
{
fwrite(pp->data + (pl[o]), sizeof(struct PeoInfo*), 1, hsz + z);
*(pp->data + (pl[o])) = *(pld + o);
z++;
}
fclose(hsz);
hsz = NULL;
//SortContact(pp);
for (o = 0; o < i; o++)
{
pl[o] = 0;
}
printf("删除成功\n");
}
else
{
printf("已将选中的序列号保存\n");
return 2;
}
}
//continue;
}
return 0;
}
void DelContact(struct Contact* ps)//时间O(1), 空间O(RS)
{
assert(ps);
int a = 0;
int c = 0;
int b = 0;
int d = 0;
int e = 1;
int i = 0;
char ret[20] = "0";
struct PeoInfo* rs = (struct PeoInfo*)malloc(RS * sizeof(struct PeoInfo));
if (rs == NULL)
{
perror("DelContact()");
}
printf("选择批量删除前请查询可用的序列号.是否查询?\n");
while (scanf("%s", ret) != EOF)
{
if (0 == strcmp("是", ret))
{
ShowContact(ps);
break;
}
else if (0 == strcmp("否", ret))
break;
else
{
printf("请重新输入!\n");
for (i = 0; i < 20; i++)
{
ret[i] = '0';
}
continue;
}
}
printf("请选择删除模式: 1、指定删除 2、批量删除\n");
while (scanf("%d", &a) != EOF)
{
if (a == 1)
{
while (e)
{
e = ZDDel(ps, rs);
}
break;
}
else if (a == 2)
{
c = PLDel(ps, rs);
if (1 == c)//返回1意味着删除成功
return;
else if (2 == c)//返回2意味着选中了但是取消删除了或者开辟空间啥的失败了
{
printf("是否查看已选中的序列号? 1、是 2、否\n");
scanf("%d", &b);
if (1 == b)
{
int i = 0;
for (i = 0; i < l; i++)
{
printf("%d ", pl[i]);
}
return;
}
else
{
printf("已退出删除界面\n");
return;
}
}
else
return;
}
else
{
printf("请重新输入\n");
continue;
}
}
}
void ChaContact(const struct Contact* ps)
{
assert(ps);
char name[NAME];
printf("请输入要查找的名字: >");
while (scanf("%s", name) != EOF)
{
int ret = FindByName(name, ps);
if (ret == -1)
printf("要查找的人不存在\n");
else
{
printf("%-9s\t%-7s\t%-10s\t%-10s\t%-15s\t%5s\n", "姓名", "性别", "地址", "职业", "号码", "年龄");
printf("%-9s\t%-7s\t%-10s\t%-10s\t%-15s\t%5d\n", ps->data[ret].name,
ps->data[ret].sex,
ps->data[ret].address,
ps->data[ret].occ,
ps->data[ret].number,
ps->data[ret].age);
}
break;
}
}
void ModifyContact(const struct Contact* ps)
{
printf("请输入要修改人的名字:>");
char name[NAME];
scanf("%s", name);
int ret = FindByName(name, ps);
if (ret == -1)
printf("要修改的人不存在\n");
else
{
printf("请输入要修改的名字:>");
scanf("%s", ps->data[ret].name);
printf("请输入要修改的性别:>");
scanf("%s", ps->data[ret].sex);
printf("请输入要修改的电话号码:>");
scanf("%s", ps->data[ret].number);
printf("请输入要修改的地址:>");
scanf("%s", ps->data[ret].address);
printf("请输入要修改的职业:>");
scanf("%s", ps->data[ret].occ);
printf("请输入要修改的年龄:>");
scanf("%d", &ps->data[ret].age);
printf("修改成功\n");
}
}
void ShowContact(const struct Contact* ps)
{
int i = 0;
printf("%-9s\t%-7s\t%-10s\t%-10s\t%-15s\t%5s\n", "姓名", "性别", "地址", "职业", "号码", "年龄");
for (i = 0; i < ps->sz; i++)
{
printf("%-9s\t%-7s\t%-10s\t%-10s\t%-15s\t%5d\n", ps->data[i].name,
ps->data[i].sex,
ps->data[i].address,
ps->data[i].occ,
ps->data[i].number,
ps->data[i].age);
}
}
int CmpByName(const void* q1, const void* q2)
{
return strcmp(((struct PeoInfo*)q1)->name, ((struct PeoInfo*)q2)->name);
}
void SortContact(const struct Contact* ps)
{
qsort(ps->data, ps->sz, sizeof(struct PeoInfo), CmpByName);
}
int SearchContact(const struct Contact* ps)
{
assert(ps);
char name[NAME];
printf("请输入要搜索的名字: >");
scanf("%s", name);
int ret = FindByName(name, ps);
if (ret == -1)
{
printf("要搜索的人不存在\n");
return ret;
}
else
{
printf("%-9s\t%-7s\t%-10s\t%-10s\t%-15s\t%5s\n", "姓名", "性别", "地址", "职业", "号码", "年龄");
printf("%-9s\t%-7s\t%-10s\t%-10s\t%-15s\t%5d\n", ps->data[ret].name,
ps->data[ret].sex,
ps->data[ret].address,
ps->data[ret].occ,
ps->data[ret].number,
ps->data[ret].age);
}
return 0;
}
主文件project1.c
#include "project.h"
void menu()
{
printf("\n");
printf("*************************************\n");
printf("******* 1. 增加 2. 删除 *******\n");
printf("******* 3. 查找 4. 修改 *******\n");
printf("******* 5. 展示 6. 排序 *******\n");
printf("******* 7. 搜索 0. 退出 *******\n");
printf("*************************************\n");
printf("\n");
}
enum Options
{
Exit,
Add,
Del,
Cha,
Mdf,
Show,
Sort,
Sea,
};
int main()
{
int a1 = 0;
int input = 0;
struct Contact txl;
InitContact(&txl);
do
{
menu();
printf("请选择: >");
scanf("%d", &input);
switch (input)
{
case Add:
AddContact(&txl);
break;
/*if (a1 == 0)
{
printf("添加失败, 请重试\n");
break;
}
else
{
printf("新添加的联系人是第%d个联系人\n", a1);
break;
}*/
case Del:
DelContact(&txl);
break;
case Cha:
ChaContact(&txl);
break;
case Mdf:
ModifyContact(&txl);
break;
case Show:
ShowContact(&txl);
break;
case Sort:
SortContact(&txl);
break;
case Sea:
SearchContact("&txl");
break;
}
} while (input);
return 0;
}
到现在为止,我还是没有把批量删除功能做完美。在选择确定删除后,图标会闪烁一会儿然后直接退出整个通讯录。
写一篇放在这里,也是记录一下10月24号我的通讯录记录,以防之后再拿出来写的时候忘记各个变量的作用。
结束。