c语言之动态内存管理篇(二)

目录

经典笔试题

题目1.

错误代码:

错误解析:

修改方法:

题目2. 

错误代码:

错误解析: 

修改方法

题目3.

错误代码:

错误解析:

修改方法:

c/c++的内存开辟  

动态内存管理版本的通讯录代码

main.c

contact.h 

contact.c 


本篇为动态内存管理篇第二弹,本文将对几个经典笔试题进行讲解,文章最后会附上动态管理的通讯录管理系统代码供大家交流指正。

经典笔试题

题目1.

错误代码:

void GetMemory(char* p)
{
	p = (char*)malloc(100);//申请动态空间
}
void Test(void)
{
	char* str = NULL;
	GetMemory(str);//传入str
	strcpy(str, "hello world");//给str拷贝字符串
	printf(str);//打印str
}
int main()
{
	Test();
	return 0;
}

错误解析:

综上:上述代码存在两个问题,一是对空指针的解引用操作,二是动态空间由程序结束后自动释放,会造成内存泄漏的问题。

修改方法:

对于这个程序的修改 有两种方法,第一:将值传递改为址传递,free(str);

void GetMemory(char** p)
{
	*p = (char*)malloc(100);//申请动态空间
}
void Test(void)
{
	char* str = NULL;
	GetMemory(&str);//传入str
	strcpy(str, "hello world");//给str拷贝字符串
	printf(str);//打印str
	free(str);
	str = NULL;
}
int main()
{
	Test();
	return 0;
}

第二:返回p变量,并用str接收,最后free(str)。

char* GetMemory()
{
	char* p = (char*)malloc(100);//申请动态空间
	return p;
}
void Test(void)
{
	char* str = NULL;
	str=GetMemory();//传入str
	strcpy(str, "hello world");//给str拷贝字符串
	printf(str);//打印str
    free(str);
    str=NULL;
}
int main()
{
	Test();
	return 0;
}

题目2. 

错误代码:

char* GetMemory(void)
{
	char p[] = "hello world";
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}
int main()
{
	Test();
	return 0;
}

错误解析: 

修改方法

1.将char p[] = "hello world";改为static char p[] = "hello world"; 

2.使用mallloc开辟空间。

char* GetMemory(void)
{
	char *p = (char*)malloc(20);
	strcpy(p, "hello world");
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
    free(str);
    str=NULL;
}
int main()
{
	Test();
	return 0;
}

 注意:可以返回栈空间的变量值,但不能返回地址。

题目3.

错误代码:

void Test(void)
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
	if (str != NULL)
	{
		strcpy(str, "world");
		printf(str);
	}
}
int main()
{
	Test();
	return 0;
}

错误解析:

修改方法:

在free(str)后加上str=NULL;


c/c++的内存开辟  

下图是内存开辟的结构。 

栈区:存放函数运行的局部变量,函数参数等数据,函数运行即被操作系统回收。

堆区:由程序员手动开辟与释放,如果程序员未释放,当程序结束,操作系统会自动回收其空间。

数据段:存放全局变量,静态数据等,程序结束后由系统释放。题目2中的修改方法,加static,即将数组p存放在这一空间,函数结束后并未被释放。

动态内存管理版本的通讯录代码

以下附上动态内存的通讯录代码供大家交流指正:

main.c

#include"contact.h"
void menu()
{
	printf("***************************************\n");
	printf("*******  1.add        2.del     *******\n");
	printf("*******  3.search     4.modify  *******\n");
	printf("*******  5.show       6.sort    *******\n");
	printf("*******  7.empty      0.exit    *******\n");
	printf("***************************************\n");
	printf("请输入您的操作选项:\n");

}
enum Option
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT,
	EMPTY
};
int main()
{
	int input = 0;
	Contact con;
	InitContact(&con);
	do
	{
		menu();
		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;
		case EMPTY:
			EmptyContact(&con);
			break;
		default:
			printf("输入有误,请重新输入!\n");
			break;	
		}
		system("pause");
		system("cls");
	} while (input);
}

contact.h 

#define _CRT_SECURE_NO_WARNINGS 1
#define MAX 1000
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
//联系人信息
typedef struct PeoInfo
{
	char name[20];//姓名
	int age;//年龄
	char sex[5];//性别
	char phone[15];//联系号码
	char addr[30];//通讯地址
}PeoInfo;

//静态通讯录
/*typedef struct Contact
{
	PeoInfo data[MAX];
	int sz;
}Contact;*/

//动态通讯录
typedef struct Contact
{
	PeoInfo* data;
	int capacity;//容量
	int sz;//当前联系人数量
}Contact;

//初始化通讯录
void InitContact(Contact *pc);

//添加联系人
void AddContact(Contact* pc);

//扩容通讯录
void Add_Capacity(Contact* pc);

//展示当前通讯录所有联系人
void ShowContact(const Contact* pc);

//删除联系人
void DelContact(Contact* pc);

//根据姓名查找联系人并返回下标
int  Find_Byname(const Contact* pc,char name[]);

//查找联系人
void SearchContact(const Contact* pc);

//修改联系人
void ModifyContact(Contact* pc);

//通讯录排序
void SortContact(Contact* pc);

//清空通讯录
void EmptyContact(Contact* pc);

contact.c 

#include"contact.h"
//静态初始化
//void InitContact(Contact* pc)
//{
//	assert(pc);
//	pc->sz = 0;
//	memset(pc->data, 0, sizeof(pc->data));
//}

//动态初始化
void InitContact(Contact* pc)
{
	assert(pc);
	
	pc->sz = 0;
	pc->capacity = 3;
	pc->data = calloc(pc->capacity, sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		perror("InitContact.calloc");
	}
}
//静态添加联系人
//void AddContact(Contact* pc)
//{
//	assert(pc);
//	if (pc->sz == MAX)
//	{
//		printf("通讯录已满!\n");
//		return;
//	}
//	printf("请输入联系人姓名:\n");
//	scanf("%s", pc->data[pc->sz].name);
//	printf("请输入联系人性别:\n");
//	scanf("%s", pc->data[pc->sz].sex);
//	printf("请输入联系人年龄:\n");
//	scanf("%d", &pc->data[pc->sz].age);
//	printf("请输入联系人号码:\n");
//	scanf("%s", pc->data[pc->sz].phone);
//	printf("请输入联系人地址:\n");
//	scanf("%s", pc->data[pc->sz].addr);
//	pc->sz++;
//	printf("添加成功!\n");
//}

void Add_Capacity(Contact* pc)
{
	PeoInfo* ptr = realloc(pc->data, (pc->capacity + 2) * sizeof(PeoInfo));
	if (ptr != NULL)
	{
		pc->data = ptr;
		pc->capacity += 2;
		printf("增容成功\n");
	}
	else
	{
		perror("Add_Capacity.realloc");
	}
	
}
//动态添加联系人
void AddContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == pc->capacity)
	{
		printf("当前通讯录已满,请稍后!\n");
		Add_Capacity(pc);
		return;
	}
	printf("请输入联系人姓名:\n");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入联系人性别:\n");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入联系人年龄:\n");
	scanf("%d", &pc->data[pc->sz].age);
	printf("请输入联系人号码:\n");
	scanf("%s", pc->data[pc->sz].phone);
	printf("请输入联系人地址:\n");
	scanf("%s", pc->data[pc->sz].addr);
	pc->sz++;
	printf("添加成功!\n");
}
void ShowContact(const Contact* pc)
{
	assert(pc);
	printf("%-20s%-10s%-10s%-20s%-30s\n", "姓名", "性别", "年龄", "联系方式", "联系地址");
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-20s%-10s%-10d%-20s%-30s\n", pc->data[i].name,
			pc->data[i].sex, pc->data[i].age,
			pc->data[i].phone, pc->data[i].addr);
	}
}
void DelContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空!\n");
		return;
	}
	char name[20];
	printf("请输入您要删除的联系人姓名:\n");
	scanf("%s", name);
	int ret= Find_Byname(pc,name);
	if (ret == -1)
	{
		printf("您要删除的联系人不存在!\n");
		return;
	}
	for (int i = ret; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("删除成功!\n");
}
int Find_Byname(const Contact* pc,char name[])
{
	for (int i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
			return i;
	}
	return -1;
}
void SearchContact(const Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空!\n");
		return;
	}
	char name[20];
	printf("请输入您要查找的联系人姓名:\n");
	scanf("%s", name);
	int ret = Find_Byname(pc, name);
	if (ret == -1)
	{
		printf("您要查找的联系人不存在!\n");
		return;
	}
	printf("%-20s%-10s%-10s%-20s%-30s\n", "姓名", "性别", "年龄", "联系方式", "联系地址");
	printf("%-20s%-10s%-10d%-20s%-30s\n", pc->data[ret].name,
		pc->data[ret].sex, pc->data[ret].age,
		pc->data[ret].phone, pc->data[ret].addr);
}
void ModifyContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空!\n");
		return;
	}
	char name[20];
	printf("请输入您要修改的联系人姓名:\n");
	scanf("%s", name);
	int ret = Find_Byname(pc, name);
	if (ret == -1)
	{
		printf("您要修改的联系人不存在!\n");
		return;
	}
	printf("请输入联系人姓名:\n");
	scanf("%s", pc->data[ret].name);
	printf("请输入联系人性别:\n");
	scanf("%s", pc->data[ret].sex);
	printf("请输入联系人年龄:\n");
	scanf("%d", &pc->data[ret].age);
	printf("请输入联系人号码:\n");
	scanf("%s", pc->data[ret].phone);
	printf("请输入联系人地址:\n");
	scanf("%s", pc->data[ret].addr);
}

int cmp_char(const void* e1, const void* e2)
{
	return *(char*)e1 - *(char*)e2;
}
void SortContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	qsort(pc->data->name,pc->sz, sizeof(pc->data[0]), cmp_char);
	printf("排序成功\n");
}
void EmptyContact(Contact* pc)
{
	assert(pc);
	free(pc->data);
	pc->data = NULL;
	pc->sz = 0;
	pc->capacity = 0;
	printf("通讯录清空成功!\n");
}

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值