在为结构体分配内存时,运行时系统不会自动为结构体内部的指针分配内存。类似地,当结构体消失时,运行时系统也不会自动释放结构体内部的指针指向的内存。
考虑如下结构体:
typedef struct _person {
char* firstName;
char* lastName;
char* title;
uint age;
} Person;
当我们声明这个类型的变量或者为这个类型动态分配内存时,三个指针会包含垃圾数据。在下面的代码片段中,我们声明了Person
,其内存分配如下图所示,三个点表示未初始化的内存。
void processPerson() {
Person person;
...
}
在这个结构体的初始化阶段,会为每个字段赋一个值。对于指针字段,我们会从堆上分配内存并把地址赋给每个指针:
void initializePerson(Person *person, const char* fn,
const char* ln, const char* title, uint age) {
person->firstName = (char*) malloc(strlen(fn) + 1);
strcpy(person->firstName, fn);
person->lastName = (char*) malloc(strlen(ln) + 1);
strcpy(person->lastName, ln);
person->title = (char*) malloc(strlen(title) + 1);
strcpy(person->title, title);
person->age = age;
}
可以如下这样使用这个函数,下图说明了内存分配情况:
void processPerson() {
Person person;
initializePerson(&person, "Peter", "Underwood", "Manager", 36);
...
}
int main() {
processPerson();
...
}
因为这个声明是函数的一部分,函数返回后person
的内存会消失。不过,动态分配的内存不会被释放,仍然保存在堆上。不幸的是,我们丢失了它们的地址,因此无法将其释放,从而导致了内存泄漏。
用完这个实例后需要释放内存。下面的函数会释放之前创建实例时分配的内存:
void deallocatePerson(Person *person) {
free(person->firstName);
free(person->lastName);
free(person->title);
}
我们需要在函数结束前调用这个函数:
void processPerson() {
Person person;
initializePerson(&person, "Peter", "Underwood", "Manager", 36);
...
deallocatePerson(&person);
}
另外,我们必需记得调用initialize
和deallocate
函数,但诸如C++这类面向对象的编程语言会自动为对象调用这些操作。
如果用Person
指针,必须释放如下所示的person
:
void processPerson() {
Person *ptrPerson;
ptrPerson = (Person*) malloc(sizeof(Person));
initializePerson(ptrPerson, "Peter", "Underwood", "Manager", 36);
...
deallocatePerson(ptrPerson);
free(ptrPerson);
}
下图说明了内存分配情况。