从 0->1 的用C语言手搓基于顺序表的通讯录项目(优化版)

C语言——通讯录管理系统2.0版 C语言通讯录项目,单链表实现,C语言实现通讯录,干货满满,注释满满,一看就会,内含代码源文件可下载 阅读详情

整体的大框架

我们先用 C 语言将顺序表这个数据结构的各种接口如增删查改都写全,再基于这个顺序表的内置框架去做一个通讯录,有了顺序表,我们的通讯录就要好完成的多。

注:函数的具体逻辑实现会在代码注释里提到,如果有格外重要的我会再次说明。

一.准备工作

首先,要配置好项目环境,因为 vscode 的多文件编译配置较为麻烦,而且也不方便,在这里推荐用 VS2022 或者 Clion 这两个 IDE。强大的调试功能和编译功能让我们的 Debug 和 Coding 事半功倍。

我们先做顺序表的实现,需要三个文件,分别是顺序表功能实现文件Seqlist.c,顺序表功能声明的头文件Seqlist.h,以及我们的测试文件test.c,测试文件是很重要的,我们在写每个顺序表的每个功能时,都应该写完立即的去调试测试,重点测试边界和空指针这种特殊情况。

有了以上的三个文件,我们就可以开始写顺序表的各种功能的实现了!

二.顺序表的实现

顺序表,是数据结构里线性表的一种,它逻辑不仅是顺序的,而且结构也是顺序的,所以它的底层就是数组。而顺序表也分动态和静态,所谓动态和静态就是顺序表的长度大小是定长还是可变的。我们在项目中,都选择用动态来做,不浪费空间,而且具有更强的兼容性,来多少存多少。

1.定义顺序表

既然是数组,那我们当然要用数组来模拟,不过,我们希望它的功能要比数组强大,所以用结构体来封装,便于实现更多的功能

//讲顺序表结构体类型重命名为SL
typedef struct SeqList
{
    SLDataType *arr;//因为是动态,所以用一个指针,方便后续使用 malloc,realloc
    int size;//用来记录使用的个数
    int capacity;//用来记录目前的空间
}SL;

以上就是我们对于顺序表其中结构体的定义,其中很详细的解释了每一个元素的功能和用途,不过我在补充一点就是 size,这个 size 是元素的个数,而数组中下标都是从0 开始的,所以 size 也是数组中下一个元素的待放入位置。其在Seqlist.h 文件中。

我们既然 要实现增删差改,下面我给出顺序表的功能函数,都放在声明的头文件.h 中

//顺序表打印函数
void SLPrint(SL s);

//顺序表的初始化
void SLInit(SL *ps);

//顺序表的销毁;
void SLDestroy(SL *ps);

//顺序表的尾插/头插
void SLPushBack(SL * ps ,SLDataType n);//尾插 当前的数据类型
void SLPushFront(SL * ps ,SLDataType n);//头插

//顺序表的删除
void SLPopBack(SL *ps);
void SLPopFront(SL *ps);

//顺序表的指定位置插入删除
void SLInsert(SL *ps,int pos,SLDataType n);
void SLErase(SL *ps,int pos);
//寻找顺序表中的元素
int SLFind(SL *ps,SLDataType n);

以上的所有函数,我们都在 Seqlist.h 文件中用来声明函数,而实现其具体的功能我们在 Seqlist.c 中。

2.实现顺序表

接下来,我们在.c 文件中来实现这些增删查改的功能。

我们先实现一些较为基础的功能。

//初始化顺序表函数
void SLInit(SL* ps)
{
    ps->arr = NULL;
    ps->capacity = ps->size = 0;
}

//销毁顺序表
void SLDestroy(SL * ps)
{
  //如果顺序表不为空
    if (ps->arr)
    {
        free(ps->arr);//在 arr 进行动态内存开辟之后
    }
    ps->arr = NULL;
    ps->capacity = ps->size = 0;
}

// 顺序表打印函数
 void SLPrint(SL s)
 {
   for (int i = 0;i<s.size;i++)
   {
     printf("%d ",s.arr[i]);
   }
   printf("\n");
 }

以上分别是初始化,销毁,打印的功能。

有了以上的功能,我们的顺序表已经有了开始和结束,不过我们还需要考虑一点的就是,我们在使用增删查改的功能时,我们的结构体其中的指针还为空,如果是空的顺序表,那我们应该要申请内存用来存放顺序表中的元素,那我们在头插和尾插时,难道每次都要手动的申请内存吗?该用什么函数呢?malloc,calloc,realloc,答案是 realloc,因为顺序表的空间是要连续的,而且要时刻的插入,所以应该 realloc 扩容,当初始化时,指针为空指针,此时调用的 realloc 也就相当于 malloc,而且每次都判断空间是否足够太过麻烦,我们可以将其封装为一个函数,每当有新元素插入时,我们就检查。

//检查存储容量
void SLCheckcapacity(SL *ps)
{

    // 在插入前,应该先判断空间是否足够插入
    // 而判断空间是否足够,就要看 size 和 capacity 是否相等,如果相等,那就不够用
    // 举例,当size是 6 时,待插的元素下标就是 6,而空间必须是 7
    // 如果空间也是 6 的话,,空间不足就会越界访问
    if (ps->size == ps->capacity)
    {
        //增加空间前还要判断 capacity 是否为 0
        //增容增多大的空间呢?最好增目前两倍的空间
        int Newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
        SLDataType * tmp  = (SLDataType *)realloc(ps->arr,Newcapacity*sizeof(SLDataType));
        //要检查是否申请成功
        if (tmp == NULL)
        {
            perror("realloc fail");
            exit(0);
        }
        ps->arr = tmp;//交给 arr 来维护
        tmp = NULL;
        ps->capacity = Newcapacity;//空间内容也要更新
    }

}

还有一个小 tips,我们扩容时,最好是两倍或者四倍的扩容,时间效率略优,实现简单(背后是严谨的数学推导,有兴趣可以 AI)

接下来我们可以实现尾插,头插的功能了,在头插或者尾插时,我们都需要以上步骤的检查容量和扩容

// 顺序表的的尾插
 void SLPushBack(SL * ps ,SLDataType n)
{
    //如果传的是空指针的话,就会出问题,报错,用断言、
    assert(ps);

    //检查内存容量
    SLCheckcapacity(ps);

    //尾插
    ps->arr[ps->size++] = n;//后置++,先使用 size 再让 size 更新记录
}
//顺序表的头插
void SLPushFront(SL *ps,SLDataType n)
{
    assert(ps);
    //判断空间
    SLCheckcapacity(ps);
    //因为是头插,所以要讲数据往后移
    for (int i = ps->size;i>0;i--)
    {
        ps->arr[i] = ps->arr[i-1];
    }
    ps->arr[0] = n;
    //在插入完成后,size 要更新
    ps->size++;//更新 size
}

注意在头插时,数据后移应该从后往前移动,这样才能保证顺序表中的元素不被覆盖,顺利的向后移动。

注:在实现功能时应该实现完一个功能就立即的测试,以免最后发现 Bug 半天飞费劲的去 debug

我们要在 test.c 文件测试一下这两个功能

void SLTest01()
{
    SL sl;

    SLInit(&sl);//初始化
  //测试尾插
    SLPushBack(&sl,1);
    SLPushBack(&sl,2);
    SLPushBack(&sl,3);
    SLPushBack(&sl,4);
    SLPushBack(&sl,5);
    SLPrint(sl);//打印

  //测试头插
    SLPushFront(&sl,6);
    SLPushFront(&sl,7);
    SLPrint(sl);//打印
    SLDestroy(&sl);//销毁
}
int main()
{
    SLTest01();
    return 0;
}

经过测试,功能是正常的,我们可以继续实现删改查的操作功能

//末尾删除
void SLPopBack(SL *ps)
{
  assert(ps);
  assert(ps->size);//数据个数不能为空
  ps->size--;//直接覆盖,当进行增删查改时,不影响,而且效率更高,惰性删除
}
//头部删除
void SLPopFront(SL *ps)
{
  assert(ps);
  assert(ps->size);
  //头删也就是将后面的数据覆盖到第一个,并且 size--
  for (int i = 0;i<ps->size-1;i++)
  {
    ps->arr[i] = ps->arr[i+1];
  }
  ps->size--;
}

// 顺序表指定位置的插入
 void SLInsert(SL *ps,int pos,SLDataType n)
 {
   assert(ps);
   //临界情况就是头插和尾插
   assert(pos >= 0 && pos <= ps->size);
   //插入前要将待插入位置及以后的数据向后挪动
   for (int i = ps->size;i>pos;i--)
   {
     ps->arr[i] = ps->arr[i-1];
   }
   ps->arr[pos] = n;
   ps->size++;
 }

// 顺序表的指定位置删除
 void SLErase(SL * ps ,int pos)
 {
   assert(ps);
   assert(pos >= 0 && pos < ps->size);
   //将要删除位置的数据以后的数据往前移动,覆盖数组
   for (int i =pos;i<ps->size-1;i++)
   {
     ps->arr[i] = ps->arr[i+1];
   }
   ps->size--;
 }

// 顺序表的查找
 int SLFind(SL *ps,SLDataType n)
 {
   assert(ps);
   for (int i = 0;i<ps->size;i++)
   {
     if (ps->arr[i] == n)
     {
       //找到了
       return i;
     }
   }
   return -1;
 }

其中的每一个功能的代码逻辑在注释里已经写的非常清楚,这样,我们就完成了一个顺序表的基本的功能实现。

三.通讯录的实现

接下来,我们要实现基于顺序表的一个通讯录的项目,因为我们有了顺序表,那么完成通讯录也是只要略微的修改就可以了。

我们试想,如果通讯录是一个顺序表的话,通讯录的联系人就是顺序表其中的元素,那么联系人无法用内置类型来准确的记录,所以我们需要将联系人包装成结构体在放进顺序表中。

此时我们又需要两个文件,一个 Contact.h 放入通讯录的结构功能声明,一个 Contact.c 具体实现通讯录的功能,所以我们加上之前的顺序表三个文件,我们现在一共有五个文件

1.定义通讯录

现在我们需要在通讯录的头文件里定义通讯录的结构和各种功能函数,通讯录其实就是顺序表,而联系人就是通讯录的元素,联系人自然有姓名,性别,年龄,手机号,住址        

#define NAME_MAX 20
#define GENDER_MAX 10
#define TEL 20
#define ADDR_MAX 100
//定义通讯录成员的数据
typedef struct personInfo
{
  char name[NAME_MAX];//20
  char gender[GENDER_MAX];//10
  int age;
  char tel[TEL];//20
  char addr[ADDR_MAX];//地址100
}peoInfo;//将顺序表的结构体元素的命名为peoInfo

这样我们就将一个联系人的结构体成员定义好了

上文说了,通讯录就是顺序表,而我们如果一直用 Seqlist 会感觉很乱,所以我们将Seqlist 重命名一下,但 Seqlist 没有在 Contact.h 文件里出现过,所以我们需要前置声明(重要),不然我们就找不到我们的顺序表结构体

struct SeqList;
typedef struct SeqList Contact;//将顺序表重命名为通讯录名字

此时,我们当前的通讯录的成员指针类型是peoInfo,所以需要将前面的类型改变


typedef peoInfo SLDataType;

这样以来,我们的通讯录结构就定义好了,再给出通讯录我们可以实现的功能

//通讯录的初始化
void Contact_Init(Contact * con);

//通讯录的销毁
void Contact_Destroy(Contact * con);

//通讯录的添加数据
void Contact_Add(Contact * con);

//通讯录的删除数据
void Contact_Del(Contact *con);

//通讯录的修改
void Contact_Modify(Contact * con);

//通讯录的查找
void Contact_Find(Contact * con);

//通讯录的显示数据
void Contact_Show(Contact * con);

2.实现通讯录

其中的通讯录的功能中,初始化,销毁,以及添加数据中的尾插都是我们在顺序表里已经 实现好了的

//初始化
void Contact_Init(Contact *con)
{
  //调用顺序表的初始化
  SLInit(con);//指向顺序表
}
//销毁
void Contact_Destroy(Contact *con)
{
  SLDestroy(con);
}
//添加
void Contact_Add(Contact *con)
{
  //将信息输入到结构体中
  peoInfo info;

  printf("请输入联系人姓名\n");
  scanf("%s",info.name);

  printf("请输入联系人性别\n");
  scanf("%s",info.gender);

  printf("请输入联系人年龄\n");
  scanf("%d",&info.age);

  printf("请输入联系人电话\n");
  scanf("%s",info.tel);

  printf("请输入联系人住址\n");
  scanf("%s",info.addr);

  //使用顺序表的功能,尾插,时间复杂度 O(1)
  SLPushBack(con,info);
}

以上的代码很容易实现,我们现在进一步实现删除修改和查找,首先,删除通讯录的联系人,首先需要这个人在通讯录内,且我们需要知道他的一项信息,例如名字,所以,写一个查找人名并且返回位置的函数尤为重要

//查找姓名
int FindByname(Contact *con,char name[])
{
  for (int i = 0;i<con->size;i++)
  {
    if (strcmp(con->arr[i].name,name) == 0)
    {
      //找到了,返回这个名字的下标
      return i;
    }
  }
  //  出循环,没找到
  return -1;
}

有了这个函数,我们就可以更加方便的实现删除修改的功能

我特想想给大家讲解我实现的通讯录项目中删除和修改的功能,相信大家在一些应用里都做过遇到过不小心输入错了,结果返回又要执行很多步骤才到删除和修改的功能,这里,我用 goto 语句和查找人名函数实现了一个优化,当用户不小心输错了时,将选择权交给用户来选择,如果输错了,就继续选择删除和修改的人名,如果发现没有这个人,可以直接退出。里面的逻辑也非常的清楚

//删除
void Contact_Del(Contact *con)
{
  again:
  //删除一个信息需要先看是否存在
  //并获取这个人在哪
  //通过peoinfo里的姓名来判断是否存在
  char arr[20] = {0};
  printf("请输入要删除的人的名字:");
  scanf("%s",arr);
  //检查是否存在这个人
  int r = FindByname(con,arr);

  if (r != -1)
  {
    //存在
    SLErase(con,r);
  }
  else
  {
    printf("此人不存在\n");
    printf("要重新输入吗?如果要,请输入 1,不要输入 0\n");
    int x = 0;
    scanf("%d",&x);
    if (x == 1)
    {
      goto again;
    }
    else if (x == 0)
      return;
  }
}

//修改
void Contact_Modify(Contact * con)
{
  again:
  char name[NAME_MAX];
  printf("请输入要修改的用户姓名:");
  scanf("%s",name);
  int r  = FindByname(con,name);
  if (r < 0)
  {
    printf("要修改的用户不存在\n");
    printf("要重新输入吗?如果要,请输入 1,不要输入 0\n");
    int x = 0;
    scanf("%d",&x);
    if (x == 1)
    {
      goto again;
    }
    else
    return;
  }
  else
  {
    printf("请输入修改后的姓名:");
    scanf("%s",con->arr[r].name);
    printf("\n");

    printf("请输入修改后的性别:");
    scanf("%s",con->arr[r].gender);
    printf("\n");

    printf("请输入修改后的年龄:");
    scanf("%d",&(con->arr[r].age));
    printf("\n");

    printf("请输入修改后的电话:");
    scanf("%s",con->arr[r].tel);
    printf("\n");

    printf("请输入修改后的地址:");
    scanf("%s",con->arr[r].addr);
    printf("\n");
  }
  printf("修改成功\n");
}

给大家看一下效果图

接下来,我们最终实现展示联系人的功能

void Contact_Show( Contact *con)
{
  //打印数据,姓名,性别,年龄,电话,住址
  printf("%s %s %s %s %s\n","姓名","性别","年龄","电话","住址");
  for (int i = 0;i<con->size;i++)
  {
    printf("%3s %3s %3d %3s %3s\n",
          con->arr[i].name,
          con->arr[i].gender,
          con->arr[i].age,
          con->arr[i].tel,
          con->arr[i].addr
    );
  }
}

至此,我们的通讯录的全部功能和定义就已经完成了。

四.项目的实现

有了所有的功能,我们就可以在 test.c 文件里实现这些功能。

在这里我也想向大家介绍我对于实现这些功能时的外部优化,我运用了枚举体,利用枚举体成员下表从 0 开始,将退出的功能放在第一个,这样在我的 dowhile()循环里,我就可以将 EXIT 放进 while里,然后在 switch 选择语句里,就可以更加方便的调用函数,易懂,让别人也一眼可以观察清楚。

void menu()
{
  printf("********************通讯录***************************\n");
  printf("********1.添加联系人******* 2.删除联系人****************\n");
  printf("********3.查找联系人********4.修改联系人*********************\n");
  printf("********5.展示联系人********0.退出通讯录********************\n");
  printf("*****************************************************\n");
  printf("*****************************************************\n");
}

enum Option
{
  EXIT,
  ADD,
  DEL,
  FIND,
  MODIFY,
  SHOW
};

int main()
{
  Contact con;
  Contact_Init(&con);
  int input = 0;
  do
  {
    menu();
    printf("请输入你所要进行的操作\n");
    scanf("%d",&input);
    switch(input)
    {
    case ADD:
      Contact_Add(&con);
      break;
    case DEL:
      Contact_Del(&con);
      break;
    case MODIFY:
      Contact_Modify(&con);
      break;
    case FIND:
      Contact_Find(&con);
      break;
    case SHOW:
      Contact_Show(&con);
      break;
    case EXIT:
      break;
    default:
      printf("请输入正确的选项\n");
      break;
    }
  } while (input);

    return 0;
}

最后,我也想说,这个项目并不完美,例如在打印时不够美观,展示时不够美观,只能在控制台进行,不过我会在以后的学习中,更加的完善。大家也可以集思广益,让这个项目更加的人性化和完美!!谢谢大家

从建模到调参:基于Simulink的两轮差速机器人轨迹跟踪PID控制全流程解析 本文详细解析了基于Simulink的两轮差速机器人轨迹跟踪PID控制全流程。从运动学建模入手,对比了基于距离与基于位置偏差的两种控制策略,并重点阐述了高精度轨迹跟踪的控制器设计、Simulink仿真搭建及PID参数整定方法,为移动机器人运动控制提供了完整的仿真实践指南。 阅读详情

相关推荐

AutoDock Vina实战:从零开始完成分子对接(附7VU6案例详解)

本文提供了一份详细的AutoDock Vina分子对接实战指南,以SARS-CoV-2 3CL蛋白酶(PDB ID: 7VU6)为例,从零开始手把手教学。内容涵盖软件安装、环境配置、受体与配体文件准备、对接参数设置,以及结果分析与可视化解读,旨在帮助计算生物学与药物发现领域的新手快速掌握这一核心技能。

ooo22的博客 536

学完顺序表后,用 C 语言写了一个通讯录

本文介绍如何用顺序表实现通讯录管理系统。顺序表是数组+长度+容量的封装,适合存储联系人数据。系统功能包括添加、删除、查找、修改和显示联系人,并支持文件持久化。实现步骤包括定义联系人结构体、顺序表结构、核心操作函数和业务逻辑。文章还分析了顺序表的优缺点,并建议后续可优化为链表或哈希表。通过这个项目,读者可以深入理解顺序表的实际应用。

dongaoran的博客 2614

Jetson AGX ORIN硬件初始化和环境部署

orin预安装了ubuntu20.04,只需开机,像重装系统一样设置用户信息即可,可以参考官网的教程[https://developer.nvidia.com/embedded/learn/get-started-jetson-agx-orin-devkit],官网提供了两种方式:一种是orin + 显示器,orin有提供DP接口,你需要准备一台显示器,最好也是有DP口的,因为我用DP转HDMI的连的,分辨率会受影响。确认安装的路径,一般直接回车安装在默认的 /home/你的名字/anaconda3。

TracyGC的博客 3835

【数据结构】基于顺序表实现通讯录

学习了顺序表,我们就可以用顺序表做一些事情了,例如我们可以做一个简易的通讯录项目,加深自己对顺序表的理解

Become Mad的博客 1459

LangChain4j-针对性操作Function-call+系统预设角色

如果我们想要对一些敏感信息进行针对化的操作,不仅仅是接口大模型去进行回复。比如我们现在数据库里面有一些菜品,那么用户提问,店里有多少套餐,那么云端大模型肯定是不知道的,我们希望捕获这些关键字然后进行自己的业务查询或者处理,这个时候就可以使用function-call。

DDDDDouble的博客 454

无感无刷电机三段式启动避坑指南:从预定位到闭环切换的STM32代码实现

本文深入解析无感无刷电机的三段式启动流程,涵盖预定位、启动加速与闭环切换三大阶段。重点对比了恒频升压、恒压升频与升频升压三种核心启动策略的优劣,并提供了基于STM32的详细状态机代码实现与关键参数调试指南,帮助工程师有效规避启动失步、线圈过热等常见问题,实现稳定可靠的无感驱动。

herb5的博客 535

重生之我在异世界学编程之C语言小项目:通讯录

在现代社会中,通讯录作为一种重要的个人信息管理工具,广泛应用于手机、电脑等电子设备中。通讯录的基本功能包括添加联系人、删除联系人、查找联系人和更新联系人信息等。为了实现这些功能,我们可以采用多种数据结构,其中顺序表(即数组)是一种常见且高效的选择。本文将深入探讨使用顺序表实现通讯录的实现思路和原因。一起来看看吧!!!

z15879084549的博客 3122

HybridCLR热更新打包报错全解析:从原理到实战解决方案

热更新技术是现代游戏和应用开发中实现动态内容交付与Bug修复的核心机制,它允许开发者在无需重新发布完整应用的情况下更新代码逻辑。其原理通常涉及在运行时加载并执行新的代码模块,这要求框架在底层实现安全的代码隔离、内存管理与元数据桥接。在Unity生态中,HybridCLR作为基于IL2CPP的高性能热更新解决方案,通过补充元数据和AOT泛型引用技术,实现了对C#代码的原生级热更支持,显著提升了开发迭代效率与线上问题修复能力。然而,在实际的工程实践中,尤其是在面向Android、iOS等多平台打包构建时,开发者

weixin_29017445的博客 309

C语言数据结构——顺序表,及通讯录项目的模拟实现

摘要:本文介绍了C语言中顺序表的基本概念和实现方法。顺序表是一种物理地址连续的线性结构,分为静态和动态两种类型。重点讲解了动态顺序表的实现过程,包括初始化、增删查改等操作,并通过检查空间、内存管理等关键技术确保程序稳定性。最后以通讯录项目为例,展示了顺序表的实际应用,涉及结构体存储、头文件引用、数据持久化等进阶内容。文章提供了完整的代码实现思路,适合C语言初学者学习基础数据结构。

lunar_coder的博客 787

金仓数据库KCM认证考试介绍【2025年4月更新】

金仓数据库认证资深专家KCM认证考试介绍

qq709869231的博客 3227

Python爬虫实战:全自动采集银行理财产品收益率数据

本文通过Playwright动态爬虫技术,成功实现了对银行理财产品收益率数据的实时采集,并通过 Pandas 数据清洗、SQLite 存储、调度自动化等模块,构建了一个可扩展的银行理财数据抓取系统。理财非儿戏,数据做决策。掌握银行收益信息是我们迈向理性投资的第一步。希望这套工具对你有所帮助!

2201_76125261的博客 1155

C语言实现个人通讯录(功能优化)

本文用C语言模拟实现通讯录,代码行数大约1000行(算注释),主要实现通讯录基本功能,外加隐蔽空间等,以及Hoare最初版本快速排序

认真分享博客,认真分享学习 2984

如何借助Gemini 3 Pro完成一篇文献精读?(劝收藏)

金句必须是原文的完整句子,并附上该句子在文中的大致位置。你是一名资深科研文献评估专家,请根据我提供的文献信息(标题、作者、期刊、时间、引用、摘要、结论、图表)依次输出:①影响力评估:按期刊、作者、时间、引用、问题重要性给出1–10分及简述;用上述方法再结合Gemini 3 Pro的辅助,原本需要3小时才能读完一篇文献,现在只需50分钟,不管是顶刊论文还是领域内冷门论文,都可以用这套方法,另外七哥设计的高阶精读提示词,需根据自己的文献内容做调整,希望这篇文章的方法能帮你高效精读文献,掌握文献的精华内容。

智能AI让学术科研更容易 1302

通讯录项目——顺序表的应用

基于上节讲解的顺序表,这里我们将其应用实现通讯录项目

2301_80288511的博客 652

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

基于顺序表的通讯录项目 (1)

摘要:本文介绍了如何用结构体存储联系人信息,解决内置数据类型的局限性。通过自定义结构体PersonInfo整合姓名、电话、地址等多种数据,将其作为顺序表的元素类型。相比普通变量,结构体可以同时存储多项信息,如同快递包裹能容纳多种物品。文中还讲解了电话号码采用char类型存储的原因,以及多文件处理和宏定义的使用技巧。通讯录底层基于顺序表实现,复用其操作方法,包括初始化、新增、删除、修改、展示和查找联系人等功能。关键点在于理解结构体类型与内置类型的区别,以及如何通过类型重命名实现代码复用。

2501_94467353的博客 541

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

C语言程序设计 | 通讯录管理系统

通讯录可以用来存储个人的信息,每个人的信息包括:姓名、性别、年龄、电话、住址。而一个通讯录的管理系统,应该至少具备增、删、查、改等几项功能,并要对其进行拓展。 所以我们要实现的功能如下: 添加联系人信息 删除指定联系人信息 查找指定联系人信息 修改指定联系人信息 显示所有联系人信息 清空所有联系人 对联系人进行排序 通讯录应该是可扩容而非定长的 通讯录的数据应该存储在文件当中,以便多次使用 明...

凌桓丶的博客 1万+

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

顺序表实战:从通讯录到算法题解析

仓库获取。

xxxiugou123的博客 547

【数据结构】实现通讯录:基于C语言动态顺序表

本文介绍了一个基于顺序表实现的通讯录系统。该系统通过复用动态顺序表底层接口,将存储类型替换为自定义联系人结构体peoInfo,实现了联系人信息的增删改查功能。关键实现包括:1) 使用定长字符数组存储联系人字段;2) 通过顺序表适配器模式实现数据存储;3) 提供完整的CRUD操作接口,包括按姓名查找、删除、修改等功能。系统采用菜单驱动方式运行,并采用格式化输出保证显示整洁。文中还分析了常见面试问题,如字符串比较、内存管理等要点。该实现展示了顺序表的泛化应用和结构体的实际使用场景。

2501_93577780的博客 519

C语言顺序表实现通讯录:原理与优化实战

顺序表作为线性表的基础实现,通过连续内存空间存储数据元素,具有O(1)随机访问的显著优势。其核心原理是通过数组实现物理地址相邻的数据存储,这种结构天然适合CPU缓存预取,在嵌入式开发等资源受限场景中表现优异。技术价值体现在高效的内存局部性和稳定的时间复杂度,特别适用于通讯录、配置表等需要频繁按索引查询的场景。动态扩容策略和批量操作优化能进一步提升性能,例如通过realloc实现内存按需增长,或采用标记-整理算法优化批量删除。在嵌入式联系人管理系统等实战项目中,合理设计Contact结构体字段和二分查找算法,

weixin_28704565的博客 255

C语言基于顺序表实现通讯录:从原理到实战运用

本文通过顺序表实现了通讯录的核心功能,从结构体设计到函数实现,再到主菜单交互,完整覆盖了小型项目的开发流程。顺序表的“数组存储”特性让通讯录的随机访问更高效,但也存在容量固定的缺陷,适合入门学习数据结构的实际应用。如果需要进一步优化,可以尝试实现动态顺序表、数据持久化或更高效的查找算法,欢迎大家在评论区交流讨论!#C语言 #数据结构 #顺序表 #通讯录实现 #C语言实战项目。

zzy200762的博客 327

从顺序表到通讯录实战:用 C 语言打造高效数据管理系统(附完整实现)

本文介绍了动态顺序表的实现原理及其在通讯录中的应用。数据结构是程序中组织数据的"排队系统",顺序表是线性表的一种,基于动态数组实现,支持高效随机访问。文章详细解析了动态顺序表的C语言实现,包括初始化与销毁、扩容策略(2倍扩容)、插入/删除操作的时间复杂度分析,以及边界检查等关键点。通过动态顺序表可实现灵活的数据存储管理,为后续构建通讯录系统奠定基础。

2403_87581574的博客 871

数据结构之通讯录项目的实现

咱也就是说,有了思维,就不要让它仅仅浮现在头脑之中,不妨share一下

X_do_myself的博客 1553

基于顺序表的通讯录系统设计与实现

在实际编程学习中,将数据结构理论应用于具体项目是提升编程能力的重要途径。本文将通过一个完整的通讯录系统实现,展示如何利用顺序表这一基础数据结构来解决实际问题。通讯录作为日常生活中常用的工具,其背后蕴含的数据管理思想值得我们深入探讨。目录前言系统架构设计整体架构概述核心数据结构分析联系人信息结构顺序表与通讯录的关联核心功能模块详解1. 系统初始化与销毁2. 联系人添加功能3. 联系人查询与展示4. 联系人删除功能5. 联系人修改功能6. 用户界面设计测试代码分析自动化测试函数交互式主程序顺序表底层实现分析。

qq_67169366的博客 828

【c语言进阶】常见的静态通讯录

不知道结构体的运用?快来学学静态通讯录吧!

睿的博客 1326

C语言手写顺序表

本人的技术笔记会优先发布在个人站点数据结构是计算机存储、组织数据的方式。是指相互之间存在一种或多种特定关系的数据元素合集。数据结构反映数据的内部构成,即数据由哪部分构成,什么方式构成,以及数据元素之间的呈现的结构。使用数据结构是为了将杂乱无章的数据按特定逻辑关系高效地组织起来,从而在时间(运算速度)与空间(内存占用)上最大化程序的执行与存储效率。

2501_93598028的博客 771

C语言顺序表实现通讯录管理系统实战

顺序表作为线性表的基础实现方式,在内存连续存储的场景下展现出优异的缓存命中率。其核心原理是通过数组实现元素的顺序存储,支持O(1)时间复杂度的随机访问,特别适合通讯录这类查询频繁的应用。在嵌入式开发中,顺序表的内存管理策略直接影响系统性能,常见优化手段包括动态扩容和懒删除机制。通过实现联系人信息的增删改查功能,开发者能深入理解数据结构底层原理,同时掌握文件持久化和防御性编程等工程实践技巧。本案例结合华为嵌入式开发经验,演示如何用C语言构建工业级通讯录系统,涉及内存优化、二进制存储和跨平台兼容等关键技术点。

weixin_32183107的博客 282
上一篇: C 语言中函数的高效学习方法实操在内存函数中
下一篇: 快慢指针判环步长差的探讨与解析
DDXYcoder
博客等级 码龄1年 140粉丝 29原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值