return 来自 C 函数的指针是 good/bad 设计的?
return pointer from a C function is good/bad design?
我想知道来自 C 函数的 return 指针是否是 good/bad 设计的?如果这是一种不好的做法,那么在以下示例中什么是好的做法:
问题是以下内容的续集:
在 data.h
文件中:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int age;
int number;
} person;
person * getPersonInfo();
在data.c
#include "data.h"
static struct person* person_p = NULL;
person * getPersonInfo()
{
person_p = (struct person*)malloc(10 * sizeof(struct person));
return person_p;
}
在main.c
#include "data.h"
int main()
{
person* pointer = getPersonInfo();
return 0;
}
基本上main
文件中的main
函数需要获取静态指针person_p
指向的数组所有元素的值,如果不好练习,那么好的练习应该是什么?
它不好的唯一原因是它背后没有任何内存管理结构。在您当前的代码中,您有内存泄漏,因为您通过 malloc() 分配了一个 person
结构但没有释放它。
考虑编写一个包装函数来为您处理内存管理:
void freePerson(struct person * personToDelete)
{
free(personToDelete);
}
然后在你的主要部分:
int main()
{
person* pointer = getPersonInfo();
freePerson(pointer); // After you are done using it
return 0;
}
我还必须警告不要投射 malloc()
的结果。根据我的经验,它可能会导致未定义的行为。
决定比什么都重要。
这两个选项都有效,只要您了解各自的优缺点
返回指针优点:
- 封装内存分配
- 支持动态内存大小
返回指针缺点:
- 只有一个可能的输出参数
- 每次都要在堆上分配内存
接受指针作为输入的优点正好相反:
- 多个输出参数
- 内存不必在堆上分配,调用者可以使用其堆栈上的变量作为输出参数
接受指针作为输入缺点:
- 不封装内存分配
- 不支持动态内存大小 - 大小必须固定或预先指定
在您的具体示例中,我将使用输出参数,因为它是固定大小的,无需动态分配内存即可轻松调用。
要成为一个好的设计,您必须有一个匹配的函数,可以在不再需要时释放分配的内存。
return 指向私有变量的指针是不好的做法。此外,根据当前的设计,您的 .c 文件只能包含一个人 object 的实例。
而且几乎不用说,动态分配 object 的相同代码也应该负责释放它。根据设计,编写的代码是为了让程序中的其他模块清理混乱,但最终总是会出现内存泄漏。
如果您正在编写一个至少有点复杂的数据类型,您需要限制对私有变量的访问,拥有结构的多个实例等,那么最好改用 "opaque type"。示例(未测试):
// data.h
#ifndef DATA_H
#define DATA_H
#include <stdio.h>
#include <stdlib.h>
typedef struct person person; // opaque type
person* person_create (void);
void person_delete (person* p);
void person_set_age (person* p, int age);
int person_get_age (const person* p);
// ... and so on, setters/getters
#endif // DATA_H
// data.c
#include "data.h"
struct
{
int age;
int number;
} person;
person* person_create (void)
{
return malloc(sizeof(struct person));
}
void person_delete (person* p)
{
free(p);
}
void person_set_age (person* p, int age)
{
p->age = age;
}
int person_get_age (const person* p)
{
return p->age;
}
// 来电者:
#include "data.h"
int main()
{
person* p = person_create();
person_set_age(p, 50);
printf("%d", person_get_age(p));
person_delete(p);
return 0;
}
需要考虑的一些事项:
- 始终在 h 文件中使用 header 守卫。
- 切勿对 C 函数使用空参数列表
()
(但在 C++ 中始终如此)。
- 不要在 C 中转换 malloc 的结果(但总是在 C++ 中转换)。
- 需要在此代码中添加一些错误处理以防 malloc 失败。
我想知道来自 C 函数的 return 指针是否是 good/bad 设计的?如果这是一种不好的做法,那么在以下示例中什么是好的做法:
问题是以下内容的续集:
在 data.h
文件中:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int age;
int number;
} person;
person * getPersonInfo();
在data.c
#include "data.h"
static struct person* person_p = NULL;
person * getPersonInfo()
{
person_p = (struct person*)malloc(10 * sizeof(struct person));
return person_p;
}
在main.c
#include "data.h"
int main()
{
person* pointer = getPersonInfo();
return 0;
}
基本上main
文件中的main
函数需要获取静态指针person_p
指向的数组所有元素的值,如果不好练习,那么好的练习应该是什么?
它不好的唯一原因是它背后没有任何内存管理结构。在您当前的代码中,您有内存泄漏,因为您通过 malloc() 分配了一个 person
结构但没有释放它。
考虑编写一个包装函数来为您处理内存管理:
void freePerson(struct person * personToDelete)
{
free(personToDelete);
}
然后在你的主要部分:
int main()
{
person* pointer = getPersonInfo();
freePerson(pointer); // After you are done using it
return 0;
}
我还必须警告不要投射 malloc()
的结果。根据我的经验,它可能会导致未定义的行为。
决定比什么都重要。
这两个选项都有效,只要您了解各自的优缺点
返回指针优点:
- 封装内存分配
- 支持动态内存大小
返回指针缺点:
- 只有一个可能的输出参数
- 每次都要在堆上分配内存
接受指针作为输入的优点正好相反:
- 多个输出参数
- 内存不必在堆上分配,调用者可以使用其堆栈上的变量作为输出参数
接受指针作为输入缺点:
- 不封装内存分配
- 不支持动态内存大小 - 大小必须固定或预先指定
在您的具体示例中,我将使用输出参数,因为它是固定大小的,无需动态分配内存即可轻松调用。
要成为一个好的设计,您必须有一个匹配的函数,可以在不再需要时释放分配的内存。
return 指向私有变量的指针是不好的做法。此外,根据当前的设计,您的 .c 文件只能包含一个人 object 的实例。
而且几乎不用说,动态分配 object 的相同代码也应该负责释放它。根据设计,编写的代码是为了让程序中的其他模块清理混乱,但最终总是会出现内存泄漏。
如果您正在编写一个至少有点复杂的数据类型,您需要限制对私有变量的访问,拥有结构的多个实例等,那么最好改用 "opaque type"。示例(未测试):
// data.h
#ifndef DATA_H
#define DATA_H
#include <stdio.h>
#include <stdlib.h>
typedef struct person person; // opaque type
person* person_create (void);
void person_delete (person* p);
void person_set_age (person* p, int age);
int person_get_age (const person* p);
// ... and so on, setters/getters
#endif // DATA_H
// data.c
#include "data.h"
struct
{
int age;
int number;
} person;
person* person_create (void)
{
return malloc(sizeof(struct person));
}
void person_delete (person* p)
{
free(p);
}
void person_set_age (person* p, int age)
{
p->age = age;
}
int person_get_age (const person* p)
{
return p->age;
}
// 来电者:
#include "data.h"
int main()
{
person* p = person_create();
person_set_age(p, 50);
printf("%d", person_get_age(p));
person_delete(p);
return 0;
}
需要考虑的一些事项:
- 始终在 h 文件中使用 header 守卫。
- 切勿对 C 函数使用空参数列表
()
(但在 C++ 中始终如此)。 - 不要在 C 中转换 malloc 的结果(但总是在 C++ 中转换)。
- 需要在此代码中添加一些错误处理以防 malloc 失败。