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() 的结果。根据我的经验,它可能会导致未定义的行为。

决定比什么都重要。

这两个选项都有效,只要您了解各自的优缺点

返回指针优点:

  1. 封装内存分配
  2. 支持动态内存大小

返回指针缺点:

  1. 只有一个可能的输出参数
  2. 每次都要在堆上分配内存

接受指针作为输入的优点正好相反:

  1. 多个输出参数
  2. 内存不必在堆上分配,调用者可以使用其堆栈上的变量作为输出参数

接受指针作为输入缺点:

  1. 不封装内存分配
  2. 不支持动态内存大小 - 大小必须固定或预先指定

在您的具体示例中,我将使用输出参数,因为它是固定大小的,无需动态分配内存即可轻松调用。

要成为一个好的设计,您必须有一个匹配的函数,可以在不再需要时释放分配的内存。

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 失败。