测试题:
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;
}