【问题标题】:Dynamic objects (C pointers handling) when they are passed to a function [closed]将动态对象(C指针处理)传递给函数时[关闭]
【发布时间】:2018-01-29 13:46:05
【问题描述】:

1) 函数是否应该检查它的每个指针参数是否为 NULL?

void do_stuff(char** object1, char** object2, ...) {
    if (object1 == NULL) {
        return;
    }
    if (object2 == NULL) {
        return;
    }
    ...

2) 当一个函数创建一个动态对象时,它应该返回一个指向新创建的对象的指针还是应该将它分配给它的参数?

void allocate_object(char** object);

char** allocate_object(void);

3) 当一个函数打算分配一个对象但没有分配时,如何通知调用者分配结果?

return -1;

object = NULL;

4) 谁(通常)负责(检查、免费)指针参数:函数还是它的调用者?

5) 是否有任何指南或资源可以回答类似问题?


使用 C++ 和它的类,每个对象都有它的所有者。这与 RAII 和异常处理一起帮助我回答了我的问题。在 C 中,我还没有理解这一点。

【问题讨论】:

  • C 和 C++ 是两种不同的语言,实践非常不同,请选择。也请一次只问一个问题。
  • 我把 C 和 C++ 都放在了,因为 1) 我提到了 C++ 2) 我理解 C++ 中的这些概念并试图找到 C 的相应答案 3) 通过证明一个更好地指定我的问题C++ 中的示例。
  • 避免所有原始指针。而不是通过引用测试 NULL 使用传递。
  • @CorellianAle 您没有提供任何 c++ 示例...
  • 您的大部分问题必须由设计和规范处理。 F.e.如果设计保证它永远不会传递一个函数,则函数不必检查空参数。但是,在调试和开发过程中,无论如何都要谨慎地检查它,发出消息并中止(并在生产前删除代码)

标签: c pointers memory-management arguments


【解决方案1】:

1) 应根据上下文使用空检查。

除非 NULL 是预期的解决方案,否则在函数中保留 null 检查总是更好。

2) 最好将错误代码作为结果返回,如下面的函数。 如果我们想与指针参数一起传递一些附加信息,最好返回错误或状态代码。

int32_t allocate_object(char* object);// error code type will be int32_t

3) Enums 比 int 更适合这项工作。创建一个包含各种错误情况的枚举。

enum etype_error
{
    E_SUCCESS = 0,
    E_INVALID_INPUT = -1,
    E_FILE_NOT_FOUND = -2, 
    ...
};

4) 在 c 和 c++ 中,没有人负责指针分配和释放,您可以随时随地进行。 在分配它的同一块中释放它是唯一的好习惯。

所以,最好由调用者自己释放指针。

5) 我不确定 C 语言的良好参考教科书。 但对于 c++,Scott Meyers 的 Effective c++ 和 More Effective C++ 是很好的书籍,包含很多指导方针和编程实践。我相信这会很有帮助。

【讨论】:

  • 谢谢。 5) 是的,我能找到很多“怎么做?”而不是“什么是更可取和专业的方式?”用于 C 语言。
【解决方案2】:
  1. 取决于您自己的 API 文档。如果您已明确声明该函数将接受空指针,则应检查它们。如果不是,则不能假设检查。

  2. 由于显而易见的原因,第一种形式不起作用,请参阅Dynamic memory access only works inside function。您可以通过指针或返回值返回数据。哪一个都好。一般专业API:s的返回值是为结果/错误码保留的。

  3. 根据您自己的 API 文档。最粗暴的错误处理是返回 NULL 或类似的。包含许多可能出错的更详细的函数通常使用枚举或其他一些自定义类型。

  4. 取决于函数的用途。进行内存分配的代码负责清理。一般来说,如果可能的话,最好将分配留给调用者,但有时不是,比如在使用“不透明指针”或其他类型的 ADT 进行设计时。然后 ADT 应该像在 C++ 中一样在内部处理分配/释放。区别在于 C 只有“穷人的构造函数/析构函数”——函数必须显式调用。

  5. 并非如此,尽管有各种“事实上的”标准。您可以研究它是如何在 Windows API 等大型库中完成的。

【讨论】:

  • 基本上一切都是实现定义的,并且来自技术规范。就我而言,我经常调用 POSIX 函数。这是实现类似事物的好方法吗?
【解决方案3】:

只是对 Lundin 对第 4 点的回答的补充:

4) 谁(通常)负责(检查、免费)指针参数:函数还是它的调用者?

最好的情况是分配和解除分配可以发生在同一个函数中。在你可以预先知道数组的大小,或者如果你只需要分配一个完整的结构,你可以在调用者中进行分配并将分配的(但未填充的内存)传递给被调用者。但有时实际大小只能在被调用函数中计算。在这种情况下,被调用者负责分配,并将分配的块作为其返回值或指向指针的指针(双星指针)返回。然后调用者获得所有权(因为创建者函数已经结束)并负责取消分配,或者直接(使用free 调用)或调用关闭函数。

后一种情况的一个例子是FILE 流。它是一个不透明的对象,由fopen初始化并由fclose释放

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-28
    • 1970-01-01
    • 2014-06-20
    • 1970-01-01
    • 1970-01-01
    • 2012-10-06
    • 2014-03-31
    • 2012-02-22
    相关资源
    最近更新 更多