目录
本篇为动态内存管理篇第二弹,本文将对几个经典笔试题进行讲解,文章最后会附上动态管理的通讯录管理系统代码供大家交流指正。
经典笔试题
题目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");
}