Menu
CoddyTech

析构函数模式

本课属于 Coddy C 学习旅程的“面向对象编程”单元。第 13 课,共 61 课。

每个通过 malloc 创建的对象最终都必须释放。就像我们编写 create_ 函数来处理分配一样,我们也编写 free_ 函数来处理清理。这就是析构函数模式。

关键点是,释放必须按照分配的相反顺序进行。如果你的构造函数先分配内部成员,然后再分配结构体本身,那么析构函数必须先释放结构体的成员,然后再释放结构体:

typedef struct {
    char *name;
    int age;
} Person;

void free_person(Person *p) {
    if (p == NULL) return;  // 安全检查
    free(p->name);          // 先释放内部成员
    free(p);                // 再释放结构体本身
}

开头的 NULL 检查可以防止有人意外传入无效指针时发生崩溃。释放内部的 name 字符串后,我们再释放结构体本身。如果先释放 p,我们就无法再访问 p->name,从而导致内存泄漏。

析构函数的使用很简单:

Person *alice = create_person("Alice", 30);
// ……使用 alice……
free_person(alice);  // 用完后清理资源

这种模式可以确保正确释放所有内存。否则,你创建的每个对象都会造成内存泄漏,直到程序耗尽内存。

challenge icon

挑战

简单

让我们构建一个 Movie 模块,演示对象的完整生命周期,包括创建和销毁。你将练习编写析构函数,按正确顺序妥善清理所有已分配的内存。

你将创建 3 个文件:

  • movie.h:声明一个包含两个成员的 Movie 结构体:char *title(动态分配的字符串)和 int year。声明构造函数 create_movie,它接收标题和年份;还要声明析构函数 free_movie,它接收一个 Movie 指针。使用符号 MOVIE_H 作为包含保护宏。
  • movie.c:实现这两个函数。构造函数应为结构体及其标题字符串分配内存(别忘了空终止符)。析构函数必须按分配顺序的相反顺序释放内存:先释放内部的 title 字符串,再释放结构体本身。为确保安全,在析构函数开头检查 NULL。
  • main.c:创建一部电影,显示其信息,然后妥善清理内存。

你将收到两个输入:电影标题(字符串)和上映年份(整数)。

在主文件中,使用 create_movie 创建一部新电影,打印其信息,然后调用 free_movie 释放所有内存。释放内存后,打印一条确认消息。

按以下格式打印输出:

Movie: {title} ({year})
Memory freed

例如,输入 Inception 和 2010 时,输出如下:

Movie: Inception (2010)
Memory freed

记住:正确编写析构函数的关键是按相反顺序释放内存。构造函数最先分配的内容最后释放,最后分配的内容最先释放。

亲手试试

#include <stdio.h>
#include <stdlib.h>
#include "movie.h"

int main() {
    char title[100];
    int year;
    
    // 读取输入
    scanf("%[^\n]", title);
    scanf("%d", &year);
    
    // TODO: 使用 create_movie 创建电影
    
    // TODO: 按以下格式打印电影信息:
    // Movie: {title} ({year})
    
    // TODO: 使用 free_movie 释放电影占用的内存
    
    // TODO: 打印 "Memory freed"
    
    return 0;
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: C 在线编译器