C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边

这篇具有很好参考价值的文章主要介绍了C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言

👧个人主页:@小沈熬夜秃头中୧⍤⃝❅
😚小编介绍:欢迎来到我的乱七八糟小星球🌝
📋专栏:C语言学习
🔑本章内容:动态内存管理
送给各位💌:当你的能力还驾驭不了你的目标时那你就应该沉下心来历练
记得 评论📝 +点赞👍 +收藏😽 +关注💞哦~


提示:以下是本篇文章正文内容,下面案例可供参考

🌟一、为什么存在动态内存分配

我们已经掌握的内存开辟方式有:

int val = 20;在栈空间上开辟四个字节
char arr[10] = {0};在栈空间上开辟10个字节的连续空间

但是上述的开辟空间的方式有两个特点:
1.空间开辟大小是固定的。
⒉.数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。
但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道,那数组的编译时开辟空间的方式就不能满足了。这时候就只能试试动态存开辟了。

C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边

🌟二、动态内存函数的介绍

🌏2.1.malloc函数+free函数

C语言提供了一个动态内存开辟的函数:

void*malloc (size_t size);
这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。

  • 如果开辟成功,则返回一个指向开辟好空间的指针。
  • 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
  • 返回值的类型是void,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。*
  • 如果参数size为0,malloc的行为是标准是未定义的,取决于编译器。
    C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边
    C语言提供了另外一个函数free,专门 是用来做动态内存的释放和回收的,函数原型如下:

void free (void* ptr);
free函数用来释放动态开辟的内存。

  • 如果参数ptr指向的空间不是动态开辟的,那free函数的行为是未定义的。
  • 如果参数ptr是NULL指针,则函数什么事都不做。
    malloc和free都声明在stdlib.h头文件中。
    各位不要忘了我们之前学数组和指针的时候学过(p+i)==p[i],所以也可以写成p[i]
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>
int main()
{
	//申请
	//我们放整形时malloc是void*所以强制类型转换赋值给int* p
	int* p=(int*)malloc(20);//malloc这个函数一旦申请空间失败就会返回一个空指针
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//开辟成功 --- 使用
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		*(p + i) = i + 1;//为了防止p的地址被改变导致后面释放出错所以我们不用p++而是p+i
	}
	for (i = 0; i < 5; i++)
	{
		printf("%d", *(p + i));
	}
	//释放
	free(p);//free函数并不会让p置为空指针
	//free将所开辟的空间释放还给系统
	p = NULL;//避免了野指针
	return 0;
}

C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边

我们可以在调试内存中看到我们把所想要放入的值放进去了
C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边

注意:malloc申请空间时,里面放的都是随机值

🌏2.2.calloc函数+free函数

C语言还提供了一个函数叫ca1loc,cal1oc函数也用来动态内存分配。原型如下:

void* calloc (size_t num,size_t size);

  • 函数的功能是为num个大小为size的元素开辟一块空间,并且把空间的每个字节初始化为0。
  • ·与函数ma1loc的区别只在于calloc会在返回地址之前把申请的空间的每个字节初始化为全0。
    C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边
#include<stdio.h>
#include<errno.h>
#include<stdlib.h>
int main()
{
	//开辟
	int* p = (int*)calloc(10, sizeof(int));
	if (p == NULL)
	{
		printf("calloc()---%s\n", strerror(errno));
	}
	//使用
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}

根据运行结果我们可以看出calloc是由初始化的而malloc是随机值
C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边

注意:
calloc和malloc的对比:

1.参数不一样
⒉都是在堆区上申请内存空间,但是malloc不初始化,calloc会初始化为0如果要初始化,就使用calloc不需要初始化,就可以使用malloc

🌏2.3.realloc函数

realloc函数的出现让动态内存管理更加灵活。
有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时候内存,我们一定会对内存的大小做灵活的调整。那rea1loc函数就可以做到对动态开辟内存大小的调整。

函数原型如下:

void* rea1loc (void* ptr,size_t size);

  • ptr是要调整的内存地址
  • size调整之后新大小(这里是字节哦~)
  • 返回值为调整之后的内存起始位置。
  • 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。

C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边
C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边

#include<stdio.h>
#include<errno.h>
#include<stdlib.h>
int main()
{
	//开辟
	int* p = (int*)malloc(20);
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		p[i] = i + 1;
	}
	int* ptr = (int*)realloc(p, 40);//这里不能用p接受哦因为realloc返回空指针时,p就被赋值为空指针原来的20个字节的空间都找不到了
	if (ptr != NULL)
	{
		p = ptr;
	}
	else
	{
		printf("realloc:%s\n", strerror(errno));
		return 1;
	}
	for (i = 5; i < 10; i++)
	{
		p[i] = i+1;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}

🌟三、常见的动态内存错误

🌏3.1.对NULL指针的解引用操作

可能会出现对NULL指针的解引用操作
所以malloc函数的返回值要判断

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(20);
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		p[i] = i;
	}
	free(p);
	p = NULL;
	return 0;
}

🌏3.2.对动态开辟空间的越界访问

C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(20);
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	int i = 0;
	//malloc开辟了20个字节的空间但是这里要访问的却是40个字节的空间发生了越界访问
	for (i = 0; i < 10; i++)
	{
		p[i] = i;
	}
	free(p);
	p = NULL;
	return 0;
}

🌏3.3.对非动态开辟内存使用free释放

C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = arr;
	free(p);
	p = NULL;
	return 0;
}

🌏3.4.使用free释放一块动态开辟内存的一部分

C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(20);
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*p = i + 1;
		p++;
	}
	free(p);
	p = NULL;
	return 0;
}

🌏3.5.对同一块动态内存多次释放

这种问题可能会出现在一些事情上,假设A程序猿开辟一块空间后释放,但是B程序员并不知道,可能会导致二次释放。所以我们可以将p==NULL置为空指针这样就不会报错啦

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(20);
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//释放
	free(p);
	p = NULL;//我们释放掉把它置为空指针,p为空指针,这样就不会报错
	//释放
	free(p);
	p = NULL;
	return 0;
}

🌏3.6.动态开辟内存忘记释放(内存泄漏)

malloc calloc realloc所申请的空间,如果不想使用,需要free释放如果不使用free释放;程序结束之后,也会由操作系统回收;
如果不使用free释放,程序也不结束就会发生内存泄露

#include<stdio.h>
void test()
{
	int* p = (int*)malloc(20);
	//使用
}
int main()
{
	test();
	//这个函数一旦返回p就被销毁了,并没有把地址返回来
	//出了test函数来到主函数内部,主函数并不知道这个内存在哪里所以并没被释放
	return 0;
}

🌟四、优化通讯录

🌏4.1.优化前后通讯录的创建

首先创建一个通讯录我们想起之前写过的静态通讯录

typedef struct PeoInfo
{
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
}PeoInfo;
typedef struct Contact
{
	PeoInfo data[MAX];
	int sz;
}Contact;

那我们动态版本的怎么写呢?我们让它满足几点要求:
1.默认能够存放3个人的信息
2.不够的话,每次增加2个人信息
这样的话我们的动态版本不够的话每次需要增加两个人的信息所以就不能是数组形式了不然会出现问题malloc开辟的空间的起始地址交给一个指针维护;因为i要扩容我们要定义一个变量(capacity)来记录容量,还有定义一个变量(sz)来记录通讯录中的有效信息

typedef struct PeoInfo
{
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
}PeoInfo;
//静态版本
typedef struct Contact
{
	PeoInfo *data;//不够的话每次需要增加两个人的信息所以这里不能用数组会发生问题
	//malloc开辟的空间的起始地址交给一个指针维护
	//data指向了存向数据的空间
	int sz;//记录通讯录中的有效信息
	int capacity;//记录通讯录当前的容量
}Contact;

🌏4.2.优化前后通讯录的初始化

接下来就是初始化啦~对于数组我们初始化使用memset函数把里面的每个元素都设置为0

void InitContact(Contact* pc)
{
	pc->sz=0;
	//pc->date;//date是一个数组是一块连续的空间,数组名是地址不可以改成0
	//所以应该把pc所指向通讯录的date数组里的值改成0
	memset(pc->data, 0, sizeof(pc->data));
}

但对于动态内存的初始化,我们需要提前在之前静态的版本上再定义一个最开始默认值放在contact.h,这样方便我们日后更改默认值和扩容量

#define DEFAULT_SZ 3//初始默认值为3
#define INC_SZ 2//每次扩容2个

C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边

void InitContact(Contact* pc)
{
	pc->data = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo));
	//最开始默认大小,但希望我们日后可以随时改变所以我们定义一个DEFAULT_SZ和INC_SZ(扩容)
	if (pc == NULL)
	{
		printf("通讯录初始化失败:%s\n", strerror(errno));
		return;
	}
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;//默认初始值
}

🌏4.3.优化后通讯录的增加人数

不够就增容,所以我们发现主要和增加有关系,所以我们需要判断一下是否通讯录的人数超过三个是否需要扩容,所以我们分装一个函数来完成这个行为(用realloc来完成)
注意:
这里需要注意不然容易出现bug我们扩容后,一定要pc->data = ptr;不然实际上的data并没有扩容我们超过三个人的信息就会发生越界访问,INC_SZ就是我们最开始在contact.h中定义的扩容值,所以扩容后这个记录capacity当前容量的变量会+=2;我们还要注意一点扩容失败返回0,扩容成功,或者不需要扩容,返回1

int CheckCapacity(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		PeoInfo*ptr=realloc(pc->data, (pc->capacity + 2) * sizeof(PeoInfo));
		if (ptr == NULL)
		{
			printf("CheckCapacity:%s\n", strerror(errno));
			return 0;
		}
		else
		{
			pc->data = ptr;//返回值为调整之后的内存起始位置
			pc->capacity += INC_SZ;
			printf("增容成功,当前容量:%d\n", pc->capacity);
			return 1;
		}
	}
}
void AddContact(Contact* pc)
{
	if(CheckCapacity(pc)==0)
	{
		printf("空间不够,扩容失败\n");
		return 0;
	}
	else
	{
		printf("请输入名字>:");
		scanf("%s", pc->data[pc->sz].name);
		printf("请输入年龄>:");
		scanf("%d", &(pc->data[pc->sz].age));
		printf("请输入性别>:");
		scanf("%s", pc->data[pc->sz].sex);
		printf("请输入电话>:");
		scanf("%s", pc->data[pc->sz].tele);
		printf("请输入地址>:");
		scanf("%s", pc->data[pc->sz].addr);
		pc->sz++;
		printf("输入完成\n");
	}
}

🌏4.4.优化后通讯录的退出

前面的修改查找删除我们不需要做更改所以我们来到最后一项对于我们malloc开辟的内存空间最后我们要释放,所以我们要在静态版本的基础上进行修改。我们分装一个DestroyContact函数,然后在contact.h中声明再在contact.c中实现
C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边
C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边

释放完成后,我们将data置为NULL,capacity置为0,sz置为0

void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
	printf("释放内存\n");
}

🌏4.5.完整的通讯录

//contact.h
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30
//表示一个人信息
typedef struct PeoInfo
{
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
}PeoInfo;
typedef struct Contact
{
	PeoInfo data[MAX];
	int sz;
}Contact;
//初始化通讯录
void InitContact(Contact* pc);
//增加指定联系人
void AddContact(Contact* pc);
//显示联系人信息
void ShowContact(Contact* pc);
//删除联系人信息
//void DelContact(pContact pc);
void DelContact(Contact* pc);
//查找指定联系人
void SearchContact(Contact* pc);
//修改指定联系人信息
void ModifyContact(Contact* pc);
//排序联系人
void SortContact(Contact* pc);
//contact.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
#include<string.h>
void InitContact(Contact* pc)
{
	pc->sz=0;
	//pc->date;//date是一个数组是一块连续的空间,数组名是地址不可以改成0
	//所以应该把pc所指向通讯录的date数组里的值改成0
	memset(pc->data, 0, sizeof(pc->data));
}
void AddContact(Contact* pc)
{
	if (pc->sz == MAX)
	{
		printf("通讯录已满,无法增加\n");
		return;//在函数里面遇见return就返回了,因为是void所以不需要返回值
	}
	printf("请输入名字>:");
	//结构体对象用 . 
	//结构体指针用 ->
	scanf("%s", pc->data[pc->sz].name);//数组名本来就是一个地址所以不需要进行&操作
	printf("请输入年龄>:");
	scanf("%d", &(pc->data[pc->sz].age));//年龄是一个变量所以需要&操作
	printf("请输入性别>:");
	scanf("%s", pc->data[pc->sz].sex );
	printf("请输入电话>:");
	scanf("%s", pc->data[pc->sz].tele );
	printf("请输入地址>:");
	scanf("%s", pc->data[pc->sz].addr );
	pc->sz++;
	printf("输入完成\n");
}
void ShowContact(const Contact* pc)
{
	int i = 0;
	//printf("%10s %4s %5s %12s %30s\n", "姓名" "年龄" "性别" "电话" "地址");
	//打印标题
	printf("%-10s %-4s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	//打印数据
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-10s %-4d %-5s %-12s %-30s\n", 
			pc->data [i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
	}
}
static int FindByName(Contact*pc,char name[])//加上static这个函数只能在所在.c文件中使用
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			return i;//记录所删除联系人所在位置的下标
			break;
		}
	}
	if (i == pc->sz)//这里如果判断pos==0时可能是第一个元素因为i是从0开始了所以可以把pos开始赋值为-1
	{
		return -1;
	}
}
void DelContact(Contact* pc)
{
	char name[MAX_NAME] = { 0 };
	int i = 0;
	printf("请输入要删除指定联系人的名字\n");
	scanf("%s", &name);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
	}
	//删除
	//1.找到删除的指定联系人 - 位置 (下标)
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("要删除的人不存在\n");
	}
	//2.删除 - 删除pos位置上的数据
	for (i = pos;i<pc->sz -1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;//元素个数减少
	printf("删除成功\n");
}
void SearchContact(Contact* pc)
{
	//我们发现查找也需要遍历删除也需要所以为了简洁我们可以把这个遍历的数组分装成一个函数
	char name[MAX_NAME] = { 0 };
	printf("请输入要查找人的名字\n");
	scanf("%s", &name);
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("要查找的人不存在\n");
	}
	//找到就打印
	printf("%-10s %-4s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-10s %-4d %-5s %-12s %-30s\n",
		pc->data[pos].name, 
		pc->data[pos].age, 
		pc->data[pos].sex, 
		pc->data[pos].tele, 
		pc->data[pos].addr);
}
void ModifyContact(Contact* pc)
{
	char name[MAX_NAME] = { 0 };
	printf("请输入修改指定联系人的名字\n");
	scanf("%s", &name);
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("要修改的人不存在\n");
	}
	//存在就修改
	printf("请输入名字>:");
	scanf("%s", pc->data[pos].name);
	printf("请输入年龄>:");
	scanf("%d", &(pc->data[pos].age));
	printf("请输入性别>:");
	scanf("%s", pc->data[pos].sex);
	printf("请输入电话>:");
	scanf("%s", pc->data[pos].tele);
	printf("请输入地址>:");
	scanf("%s", pc->data[pos].addr);
	printf("修改成功\n");
}
//按照名字排序
int cmp_by_name(const void* e1, const void* e2)
{
	return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
void SortContact(Contact* pc)
{
	qsort(pc->data, pc->sz, sizeof(PeoInfo),cmp_by_name);
	printf("排序成功\n");
}
//test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"
void meau()
{
	printf("*****************************\n");
	printf("****1. add      2. del   ****\n");
	printf("****3. search   4. modify****\n");
	printf("****5. show     6. sort  ****\n");
	printf("****0. exit              ****\n");
	printf("*****************************\n");
}
enum Option
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT
};
int main()
{
	int input = 0;
	Contact con;
	InitContact(&con);
	do
	{
		meau();
		printf("请选择:>\n");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact(&con);
			break;
		case DEL:
			DelContact(&con);
			break;
		case SEARCH:
			SearchContact(&con);
			break;
		case MODIFY:
			ModifyContact(&con);
			break;
		case SHOW:
			ShowContact(&con);
			break;
		case SORT:
			SortContact(&con);
			break;
		case EXIT:
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误\n");
			break;
		}
	} while (input);
	return 0;
}

🌟五、一些笔试题

1.调用GetMemory函数的时候,str的传参为值传递,p是str的临时拷贝,所以在GetMemory函数内部讲动态开辟空间的地址存放在p中的时候,不会影响str.所以GetMemory函数返回之后,str中依然是NULL指针。strcpy函数就会调用失败,原因是对NULL的解引用操作,程序会崩溃。

2.GetMemory函数内容malloc申请的空间没有机会释放,造成了内存泄露。

#include<stdio.h>
#include<string.h>
void GetMemory(char* p)//传值
{
	p = (char*)malloc(100);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(str);
	strcpy(str,"hello world");
	printf(str);
}
int main()
{
	Test();
	return 0;
}

返回栈空间地址的问题
GetMemory函数内部创建的数组是临时的,虽然返回了数组的起始地址给了str,但是数组的内存出了
GetMemory函数就被回收了,而str依然保存了数组的起始地址,这时如果使用str,str就是野指针。

#include<stdio.h>
char* GetMemory(void)
{
	char p[] = "he1lo wor1d";
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}
int main()
{
	Test();
	return 0;
}

😽总结

C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边
😽Ending,今天的实现动态内存管理(上)+优化版通讯录+笔试题内容就到此结束啦~如果后续想了解更多,就请关注我吧,一键三连哦 ~文章来源地址https://www.toymoban.com/news/detail-481205.html

到了这里,关于C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C语言动态内存练习:【通讯录(动态内存版本)实现】

    前面我们写了一个静态数组版本的通讯录,再结合刚学习的动态内存管理的知识,我们现在来实现一个动态内存版本的通讯录。 动态内存版本的通讯录,主要还是为了解决静态数组版本的通讯录空间太大导致的内存浪费和空间太小不够存放的问题。 扩容策略: 为通讯录设置

    2023年04月13日
    浏览(55)
  • 动态通讯录实现(C语言)

    目录 前言: 一:单个节点的设计和主逻辑  结点设计 主逻辑 二:接口实现 (1)生成一个新的结点 (2)增加信息 (3)打印信息 (4)查找  (5)删除信息 (6)修改信息 (7)排序  插入排序 快速排序 (8)已有数据读取 (9)更新数据录入 三:全部代码 contact.h(声明) contact.c(接口) test.c(主逻辑) 本

    2024年02月05日
    浏览(32)
  • 【C语言】实现通讯录(动态+文件)

    在之前三子棋和扫雷的基础上,本篇文章博主将给大家逐步分析实现通讯录,介绍通讯录的每个功能( 动态增长和文件保存 )。 —————————————————————— test.c - 测试通讯录 Contact.c - 函数的实现 Contact.h - 函数和类型的声明 以多文件的形式分模块写的

    2024年02月13日
    浏览(36)
  • 【C语言】实现动态版通讯录

    💌内容专栏:【C语言】进阶部分 💌本文概括: 结合自定义类型、动态内存管理知识,对静态版本的通讯录进行优化。 💌本文作者:花 碟 💌发布时间:2023.4.2   目录 前言: 一、静态版本代码实现: 二、动态通讯录  三、代码整理  前面我们学过了结构体、枚举等自定义

    2024年02月02日
    浏览(22)
  • C语言实现通讯录--动态版

    实现一个通讯录,联系人的数量可多可少 1.在静态版本的基础上改用动态的方法: (1)默认能够存放三个人的信息 (2)不够的话,每次增加两个人的信息 2.其他功能不变 建立三个文件: test.c 用于测试通讯录的相关功能 contsct.c 通讯录的实现模块(用函数实现功能) conta

    2024年02月15日
    浏览(23)
  • C语言之通讯录的实现(静态版,动态版,文件版)

    个人主页(找往期文章包括但不限于本期文章中不懂的知识点): 我要学编程(ಥ_ಥ)-CSDN博客 目录 静态通讯录的实现逻辑  test.c:通讯录的逻辑实现 Contact.h:函数的声明与头文件的包含 Contact.c:函数的实现  通讯录源码:  test.c: Contact.c: Contect.h: 动态版通讯录  test.c: Co

    2024年04月13日
    浏览(27)
  • 【C语言】实现通讯录管理系统

    大家好,我是苏貝,本篇博客带大家实现通讯录,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️ 本文将使用C语言来实现通讯录管理系统,该通讯录包括若干联系人,和每个联系人的姓名、年龄、性别、电话、地址。此通讯录的功能包括:增加联系人信息,

    2024年02月08日
    浏览(29)
  • 【进阶C语言】动态版通讯录的实现(详细讲解+全部码源)

    前言 📕作者简介: 热爱跑步的恒川 ,致力于 C/C++、Java、Python 等多编程语言,热爱跑步,喜爱音乐的一位博主。 📗本文收录于 C语言进阶 系列,本专栏主要内容为数据的存储、指针的进阶、字符串和内存函数的介绍、自定义类型结构、动态内存管理、文件操作等,持续更

    2024年02月01日
    浏览(33)
  • C语言用链表实现通讯录管理系统

    目录 总体思路 具体代码 编译通过 总体代码 一、创建一个结构体保存通讯录信息。 二、构建链表,并存于文件中。 三、实现链表结点的增加、删除、查询、输出。 一、创建一个结构体,保存信息。 二、用尾插法创建一个链表,并让用户选择是否输入数据。 三、将链表数据

    2024年02月02日
    浏览(25)
  • 数据结构课设—C语言实现通讯录管理系统(顺序表实现)

    这个项目是我大一时期数据结构的课程设计,在我潜心研究下出来的,对于当时的我来说算是非常满意啦,哈哈哈哈哈哈哈哈哈哈☆*: .。. o(≧▽≦)o .。.:*☆ 目录 一、引言 1.目的: 2.意义: 3.主要任务: 4.程序功能: 5.编译工具: 二、正文 1.系统模块: 2.算法流程图: 3.各

    2024年02月02日
    浏览(62)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包