当前位置: 首页 > news >正文

S1E48:内存池 课后作业

测试题:
0. 内存碎片和内存泄漏的区别是什么呢?

答:内存碎片(释放了的空间,但是系统不会再利用这片内存了);内存泄漏(内存超限,数据超出了定义的内存范围)(错误

答案:内存碎片和内存泄露是两个不同的概念,它们都会对程序的性能和稳定性产生负面影响。
内存泄露是指程序在分配了内存后,忘记或无法释放,导致这部分内存无法再次使用;
而内存碎片是由于频繁地分配和释放不同大小的内存块,导致内存中留下许多小的、不连续的内存块,降低了内存的利用效率。


1. 请使用简单的代码,举一个可能导致内存碎片的例子?

答:

struct Node *node = (struct Node *)malloc(sizeof(struct Node));free(node);

答案:在以下的代码中,我们频繁地进行小块内存的分配和释放,这可能会导致内存碎片。

解析:内存碎片问题在一段简单的代码中可能不容易看出,因为它依赖于内存分配器的具体行为以及程序的运行时间。l
在实际的大型程序中,频繁的小块内存分配和释放可能会导致明显的性能问题。

#include <stdio.h>
#include <stdlib.h>void memory_fragment() 
{for (int i = 0; i < 1000000; ++i){// 分配10字节的内存char *buffer = malloc(10);if (buffer == NULL) {printf("内存分配失败。\n");return;}// 使用这个缓冲区做一些操作...// 释放内存free(buffer);}
}int main() 
{memory_fragment();return 0;
}


2. 请使用简单的代码,举一个可能导致内存泄漏的例子?

答:错误?

int p[10] = {0,1,2,3,4,5,6,7,8,9,10,11};

答案:在以下的代码中,我们创建了一个动态数组,但在函数结束时忘记释放内存,这就导致了内存泄漏。

#include <stdio.h>
#include <stdlib.h>void memory_leak() 
{// 使用malloc动态分配100个整数的内存int *array = malloc(100 * sizeof(int));if (array == NULL) {printf("内存分配失败。\n");return;}// 使用这个数组做一些操作...// 忘记释放内存,导致内存泄漏// free(array);
}int main() 
{memory_leak();return 0;
}


{&eDjn`9Mk;Z)H'a52RQr
3. 链表和数组,哪一个结构更容易造成内存碎片?

答:链表,因为链表需要手动申请内存,再通过free释放

答案:链表。
解析:链表和数组都是常用的数据结构,但它们对内存的使用方式和可能造成的内存碎片情况不同。
链表中的每个节点都需要单独分配内存,并且这些节点在内存中的位置可能是分散的。
因此,链表在频繁插入和删除节点时可能会产生许多小的内存碎片。
数组相比之下,数组通常在连续的内存地址空间中分配,因此不太可能


4. 内存池为什么可以解决内存碎片的问题,它的设计思路是什么?

答:内存池就是链表

答案:内存池的设计思路是预先申请一大块连续的内存空间,然后按需从这个内存池中分配内存给程序。
当程序不再需要这些内存时,不立即释放这些内存,而是将这些内存块返回到内存池中,以供以后使用。
这样,就避免了频繁地申请和释放内存,从而减少了内存碎片的产生。


5. 内存池的缺点是什么?

答:使用麻烦

答:虽然内存池可以解决内存碎片问题,但它也有一些缺点。
例如,内存池需要预先申请一大块内存,这可能会占用大量的内存资源;
此外,如果程序的内存需求超过了内存池的大小,就需要重新分配内存池,这也会产生一定的开销。

动动手:
0. 模仿小甲鱼在课堂中实现的通信录程序(内存池版),现在让我们开发一个使用内存池的待办事项程序。
主要功能包括:
        添加待办事项 - 用户可以添加一个新的待办事项到应用中。每个待办事项都有一个名称和描述。如果内存池中有空闲的待办事项,则复用它;如果没有,则为新的待办事项分配内存。
        修改待办事项描述 - 用户可以修改现有的待办事项的描述。他们需要输入待办事项名称,然后输入新的描述。如果找不到待办事项,程序会显示错误信息。
        删除待办事项 - 用户可以删除一个待办事项。他们输入待办事项的名称,然后应用会在列表中查找并删除它。如果找不到待办事项,程序会显示错误信息。删除的待办事项会被放入内存池以便以后复用。
        查看所有待办事项 - 用户可以查看所有的待办事项。程序会遍历待办事项列表,显示每个待办事项的名称和描述。
        退出程序 - 用户可以选择退出程序。退出前,程序会释放待办事项列表和内存池中所有待办事项的内存。

答:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>struct Node
{char name[32];char number[32];struct Node *next;
};#define MAX 1024  //定义内存池最大大小 struct Node *pool = NULL;  //内存池指针 
int count;void addPerson(struct Node **head)
{struct Node *cur = NULL;struct Node *temp = NULL;if(pool != NULL){cur = pool;pool = pool->next;count--;} else{cur = (struct Node *)malloc(sizeof(struct Node));if(cur == NULL){printf("内存分配失败!\r\n");exit(1); 	}	}printf("请输入联系人:");scanf("%s",cur->name);printf("请输入电话:");scanf("%s",cur->number);	if(*head != NULL){temp = *head;*head = cur;cur->next= temp; }else{*head = cur;cur->next=NULL;		}
}struct Node *findPerson(struct Node *head)
{char nameinput[32] = {0}; struct Node *temp = head;printf("请输入联系人:");scanf("%s",nameinput);while(temp != NULL){if(!strcmp(temp->name,nameinput)){printf("电话:%s\n",temp->number); break;}	temp = temp->next; }return temp;
} void changePerson(struct Node *head)
{struct Node *temp = NULL; char nameinput[32]={0};temp = findPerson(head);	if(temp == NULL){printf("找不到该联系人\r\n");}else{printf("请输入新的联系电话:");scanf("%s",temp->number);}
}void delPerson(struct Node **head)
{struct Node *pre = NULL;struct Node *temp = NULL;struct Node *cur = NULL; char inputname[32]={0};cur = findPerson(*head);if(cur == NULL){printf("没有该联系人\r\n");}else{temp = *head;while(temp != NULL && temp != cur){pre = temp;temp = temp->next;}//删除待办事项,将删除的待办事项放入内存池 if(pre == NULL){*head = cur->next;}else{pre->next= cur->next;}if(count < MAX){temp = pool;pool = cur;cur->next = temp;count++; } else{free(cur);}} 
}//显示所有联系人 
void displayPerson(struct Node *head)
{struct Node *temp = head;while(temp != NULL){printf("联系人:%s",temp->name);printf("电话%s",temp->number);temp = temp->next;}	
}//释放内存 
void releaseContacts(struct Node **head)
{struct Node *temp = NULL;while(*head != NULL){temp = *head;*head = (*head)->next;free(temp);}
}void releasePool(void)
{struct Node *cur;while(cur != NULL){cur = pool;pool = pool->next;free(cur);	}
}int main()
{int input = 0;printf("|  欢迎使用通讯录管理程序  |\r\n");printf("|---  1:插入新的联系人  ---|\r\n");	printf("|---  2:查找已有联系人  ---|\r\n");printf("|---  3:更改已有联系人  ---|\r\n");printf("|---  4:删除已有联系人  ---|\r\n");printf("|---  5:显示已有联系人  ---|\r\n");printf("|---  6:退出通讯录程序  ---|\r\n");struct Node *person = NULL;while(1){printf("请输入指令代码:");scanf("%d",&input);switch(input){case 1:addPerson(&person);break;case 2:findPerson(person);break;	case 3:changePerson(person);break;case 4:delPerson(&person);break;case 5:displayPerson(person);break;case 6:releaseContacts(&person);releasePool();break;		default:break;}printf("\n");	}} 

答案:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define MAX 1024  // 定义内存池最大大小// 待办事项结构体
struct Todo {char name[40];  // 待办事项名称char description[100];  // 待办事项描述struct Todo *next;  // 指向下一个待办事项的指针
};struct Todo *pool = NULL;  // 内存池指针
int count;  // 记录内存池中待办事项的数量// 函数声明
void getInput(struct Todo *todo);
void printTodo(struct Todo *todo);
void addTodo(struct Todo **todos);
void changeTodo(struct Todo *todos);
void delTodo(struct Todo **todos);
struct Todo *findTodo(struct Todo *todos);
void displayTodos(struct Todo *todos);
void releaseTodos(struct Todo **todos);
void releasePool(void);// 获取待办事项的输入信息
void getInput(struct Todo *todo) {printf("请输入待办事项名称:");scanf("%s", todo->name);printf("请输入待办事项描述:");scanf("%s", todo->description);
}// 添加新的待办事项
void addTodo(struct Todo **todos) {struct Todo *todo;struct Todo *temp;// 如果内存池中有空闲的待办事项,我们复用它而不是分配新的内存if (pool != NULL) {todo = pool;pool = pool->next;count--;} else {// 如果内存池为空,我们分配新的内存todo = (struct Todo *)malloc(sizeof(struct Todo));if (todo == NULL) {printf("内存分配失败!\n");exit(1);}}getInput(todo);// 如果待办事项列表不为空,我们将新的待办事项添加到列表的头部if (*todos != NULL) {temp = *todos;*todos = todo;todo->next = temp;} else {// 如果待办事项列表为空,我们设置新的待办事项为列表的唯一节点*todos = todo;todo->next = NULL;}
}// 打印待办事项的详细信息
void printTodo(struct Todo *todo) {printf("待办事项:%s\n", todo->name);printf("描述:%s\n", todo->description);
}// 查找特定的待办事项
struct Todo *findTodo(struct Todo *todos) {struct Todo *current;char input[40];printf("请输入待办事项名称:");scanf("%s", input);current = todos;// 遍历待办事项列表,寻找与输入名称匹配的待办事项while (current != NULL && strcmp(current->name, input)) {current = current->next;}return current;
}// 修改待办事项的描述
void changeTodo(struct Todo *todos) {struct Todo *todo;todo = findTodo(todos);if (todo == NULL) {printf("找不到该待办事项!\n");} else {printf("请输入新的待办事项描述:");scanf("%s", todo->description);}
}// 删除特定的待办事项
void delTodo(struct Todo **todos) {struct Todo *temp;struct Todo *todo;struct Todo *current;struct Todo *previous;todo = findTodo(*todos);if (todo == NULL) {printf("找不到该待办事项!\n");} else {current = *todos;previous = NULL;// 遍历待办事项列表,找到待删除的待办事项while (current != NULL && current != todo) {previous = current;current = current->next;}// 删除待办事项,并重新连接待办事项列表if (previous == NULL) {*todos = current->next;} else {previous->next = current->next;}// 如果内存池未满,我们将删除的待办事项放入内存池if (count < MAX) {temp = pool;pool = current;current->next = temp;count++;} else {// 如果内存池已满,我们释放待办事项的内存free(current);}}
}// 显示所有的待办事项
void displayTodos(struct Todo *todos) {struct Todo *current;current = todos;// 遍历待办事项列表,并打印每个待办事项的详细信息while (current != NULL) {printTodo(current);current = current->next;}
}// 释放所有待办事项的内存
void releaseTodos(struct Todo **todos) {struct Todo *current;current = *todos;// 遍历待办事项列表,并释放每个待办事项的内存while (current != NULL) {*todos = current->next;free(current);current = *todos;}
}// 释放内存池中所有待办事项的内存
void releasePool(void) {struct Todo *current;current = pool;// 遍历内存池,并释放每个待办事项的内存while (current != NULL) {pool = current->next;free(current);current = pool;}
}int main(void) {struct Todo *todos = NULL;int option;while (1) {printf("1. 添加待办事项\n");printf("2. 修改待办事项描述\n");printf("3. 删除待办事项\n");printf("4. 查看所有待办事项\n");printf("5. 退出\n");printf("请选择操作:");scanf("%d", &option);switch (option) {case 1:addTodo(&todos);break;case 2:changeTodo(todos);break;case 3:delTodo(&todos);break;case 4:displayTodos(todos);break;case 5:releaseTodos(&todos);releasePool();return 0;default:printf("无效的选项!\n");}}return 0;
}

1. 兵不厌诈,熟能生巧!还是一样的套路,让我们来设计一个学生信息管理系统。
主要功能包括:
        插入新的学生信息 - 它会提示用户输入学生的学号,姓名和专业,并将输入的信息存储在一个新创建的 Student 结构体实例中。这个新创建的学生信息会被添加到链表的开始。
        查找已有学生信息 - 该功能会提示用户输入一个学生的学号,然后遍历链表查找该学号对应的学生。如果找到,它将显示该学生的信息,否则,它将打印一个消息说找不到该学生。
        更改已有学生信息 - 这个功能也会提示用户输入一个学生的学号,然后查找该学生。如果找到,它将提示用户输入新的专业,并更新该学生的信息。
        删除已有学生信息 - 用户输入一个学号,程序会查找并删除对应的学生信息。如果找到并删除了该学生,它将把该学生的内存空间添加到一个内存池中,以便再次使用。如果内存池已满,它将释放该学生的内存空间。
        显示当前所有学生信息 - 它将遍历链表,打印出所有学生的信息。
        退出学生信息管理程序 - 当用户选择这个选项时,程序将释放所有的学生信息和内存池中的内存空间,并退出程序。

答:

答案:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define MAX 1024  // 定义内存池的最大容量// 定义一个学生的结构体
struct Student
{char id[10];  // 学生的学号char name[40];  // 学生的姓名char major[20];  // 学生的专业struct Student *next;  // 指向链表中下一个学生的指针
};struct Student *pool = NULL;  // 定义一个全局的内存池
int count;  // 当前内存池中的学生数量// 获取用户输入的学生信息并保存到给定的学生结构体中
void getInput(struct Student *student);// 打印给定的学生的信息
void printStudent(struct Student *student);// 添加一个新的学生到链表
void addStudent(struct Student **students);// 修改链表中的一个学生的信息
void changeStudent(struct Student *students);// 从链表中删除一个学生
void delStudent(struct Student **students);// 根据学号查找链表中的一个学生
struct Student *findStudent(struct Student *students);// 打印链表中所有学生的信息
void displayStudents(struct Student *students);// 释放链表中所有学生的内存
void releaseStudents(struct Student **students);// 释放内存池中所有学生的内存
void releasePool(void);// ... 此处省略了函数的实现 ...int main(void)
{int code;  // 用户输入的操作代码struct Student *students = NULL;  // 链表的头指针struct Student *student;  // 临时变量,用于保存查找到的学生// 打印欢迎信息和操作菜单printf("| 欢迎使用学生信息管理程序 |\n");printf("|--- 1:插入新的学生信息 ---|\n");printf("|--- 2:查找已有学生信息 ---|\n");printf("|--- 3:更改已有学生信息 ---|\n");printf("|--- 4:删除已有学生信息 ---|\n");printf("|--- 5:显示当前所有学生信息 ---|\n");printf("|--- 6:退出学生信息管理程序 ---|\n");while (1)  // 主循环,直到用户选择退出{printf("\n请输入指令代码:");scanf("%d", &code);  // 获取用户输入的操作代码// 根据用户输入的操作代码执行相应的操作switch (code){case 1: addStudent(&students); break;  // 添加新的学生case 2:  // 查找学生student = findStudent(students);if (student == NULL)  // 如果找不到学生,打印错误信息{printf("找不到该学生!\n");}else  // 如果找到学生,打印其信息{printStudent(student);}break;case 3: changeStudent(students); break;  // 修改学生信息case 4: delStudent(&students); break;  // 删除学生case 5: displayStudents(students); break;  // 显示所有学生信息case 6: goto END;  // 退出程序}}END:releaseStudents(&students);  // 释放链表中所有学生的内存releasePool();  // 释放内存池中所有学生的内存return 0;
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • DeepSORT(目标跟踪算法)中自由度决定卡方分布的形状
  • 34、matlab输入命令汇总
  • 中科数安 |-公司办公透明加密系统,数据防泄漏软件
  • 【Vue】核心概念 - module
  • MySQL之查询性能优化(七)
  • JavaWeb期末知识点复习
  • Unity 使用TextMeshPro实现图文混排
  • azure cli的安装和使用
  • 硬件工程师学习规划
  • 多客圈子论坛系统 httpGet 任意文件读取漏洞复现
  • 臻奶惠的行业优势与市场竞争力解析
  • Spring-Security(一)-源码分析及认证流程
  • 电子元器件批发的几种模式
  • 嵌入式C语言面试题笔试题
  • 华为和锐捷设备流统配置
  • [数据结构]链表的实现在PHP中
  • 4个实用的微服务测试策略
  • Electron入门介绍
  • ES6系列(二)变量的解构赋值
  • express + mock 让前后台并行开发
  • passportjs 源码分析
  • PHP 7 修改了什么呢 -- 2
  • REST架构的思考
  • Zsh 开发指南(第十四篇 文件读写)
  • 配置 PM2 实现代码自动发布
  • 浅谈Kotlin实战篇之自定义View图片圆角简单应用(一)
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • 使用 @font-face
  • 通信类
  • C# - 为值类型重定义相等性
  • ​Java基础复习笔记 第16章:网络编程
  • ​LeetCode解法汇总2304. 网格中的最小路径代价
  • ### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException
  • #pragma multi_compile #pragma shader_feature
  • (02)vite环境变量配置
  • (1)bark-ml
  • (19)夹钳(用于送货)
  • (Python) SOAP Web Service (HTTP POST)
  • (Redis使用系列) Springboot 实现Redis消息的订阅与分布 四
  • (vue)el-checkbox 实现展示区分 label 和 value(展示值与选中获取值需不同)
  • (笔试题)分解质因式
  • (第9篇)大数据的的超级应用——数据挖掘-推荐系统
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (附源码)计算机毕业设计SSM基于健身房管理系统
  • (免费领源码)Python#MySQL图书馆管理系统071718-计算机毕业设计项目选题推荐
  • (三)centos7案例实战—vmware虚拟机硬盘挂载与卸载
  • (十八)三元表达式和列表解析
  • (顺序)容器的好伴侣 --- 容器适配器
  • (学习日记)2024.01.19
  • (一)80c52学习之旅-起始篇
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...
  • (轉貼) UML中文FAQ (OO) (UML)
  • (轉貼) 蒼井そら挑戰筋肉擂台 (Misc)
  • .NET/C# 将一个命令行参数字符串转换为命令行参数数组 args
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地中转一个自定义的弱事件(可让任意 CLR 事件成为弱事件)