将指针作为函数参数传递并在C中返回的基本原理

将指针作为函数参数传递并在C中返回的基本原理,c,pointers,C,Pointers,我正在检查bkhive的源代码(用C编写)——一个用于从Windows NT/2K/XP系统配置单元转储系统键引导键的实用程序——并想知道原始作者所做的事情是否有任何理由:将指向struct的指针传递到函数中,然后返回相同的指针。以下是相关的源代码: 在main()中有一个如下所示的调用: struct hive h; char *root_key; // Do some stuff to init _RegGetRootKey(&h, &root_key) foo(myPtr

我正在检查bkhive的源代码(用C编写)——一个用于从Windows NT/2K/XP系统配置单元转储系统键引导键的实用程序——并想知道原始作者所做的事情是否有任何理由:将指向
struct
的指针传递到函数中,然后返回相同的指针。以下是相关的源代码:

main()
中有一个如下所示的调用:

struct hive h;
char *root_key;
// Do some stuff to init
_RegGetRootKey(&h, &root_key)
foo(myPtr);
bar(myPtr);
这要求:

int _RegGetRootKey(struct hive *h, char **root_key)
{
    nk_hdr *n;
    n = (nk_hdr*) malloc(sizeof(nk_hdr));

    /* ************************************************
     * RELEVANT FUNCTION CALL
     * Why pass n as a parameter and use return value?
     * ************************************************/
    n = read_nk(n, h, 0x1020);

    if (n->id == NK_ID && n->type == NK_ROOT)
    {
        *root_key = (char *) malloc(n->name_len + 1);
        strncpy(*root_key, n->key_name, n->name_len);
        (*root_key)[n->name_len] = 0;
        free(n);
        return 0;
    }
    free(n);
    return -1;
}
nk_hdr* read_nk(nk_hdr *nk, struct hive *h, int offset)
{
    memcpy(nk, h->base + offset + 4, sizeof(nk_hdr));
    nk->key_name = (h->base + offset + 4 + 76);
    return nk;
}
这要求:

int _RegGetRootKey(struct hive *h, char **root_key)
{
    nk_hdr *n;
    n = (nk_hdr*) malloc(sizeof(nk_hdr));

    /* ************************************************
     * RELEVANT FUNCTION CALL
     * Why pass n as a parameter and use return value?
     * ************************************************/
    n = read_nk(n, h, 0x1020);

    if (n->id == NK_ID && n->type == NK_ROOT)
    {
        *root_key = (char *) malloc(n->name_len + 1);
        strncpy(*root_key, n->key_name, n->name_len);
        (*root_key)[n->name_len] = 0;
        free(n);
        return 0;
    }
    free(n);
    return -1;
}
nk_hdr* read_nk(nk_hdr *nk, struct hive *h, int offset)
{
    memcpy(nk, h->base + offset + 4, sizeof(nk_hdr));
    nk->key_name = (h->base + offset + 4 + 76);
    return nk;
}

那么,传递
struct
指针然后返回它的目的是什么?函数调用后不能不返回任何内容并使用
n

此约定的主要好处是允许更简单的函数调用串联。如果您想使用一个函数的返回作为另一个函数的参数,让它返回指针可以使您将语句写在一行中。因此,不要写这样的东西:

struct hive h;
char *root_key;
// Do some stuff to init
_RegGetRootKey(&h, &root_key)
foo(myPtr);
bar(myPtr);
您可以这样做:

bar(foo(myPtr));

您所展示的特定代码没有使用这一点,但这是许多C函数中使用的约定,我猜代码的作者现在已经习惯了这一点。

这允许您通过引用传递对象,然后在返回时获得更新值的句柄(即指针)。。。如果出现问题,它还允许您传回NULL,以便您知道通过引用传入的对象的状态不再良好。例如:

struct my_struct* pass_by_ref = malloc(sizeof(my_struct));
//...some more code

if (foo(pass_by_ref) == NULL)
{
    free(pass_by_ref); //pass_by_ref is no longer any good ...
    perror();
}

在这种情况下,它似乎没有多大用处。但总的来说,我过去做同样的事情有两个原因:

一种是函数可能会重新分配指向的项,在这种情况下,返回可能是传递的同一指针,也可能是用不同的值替换它

另一个,即使指针不会改变,它也允许立即使用函数的返回来访问指向的项,如
somefunc(item)->member=5等等。它允许您将函数调用放到另一个表达式中,该表达式之后需要相同的指针


这也可能只是为了使函数的使用与API中的其他函数保持一致,其中一些函数可能有这样做的理由。

谢谢。我甚至没有想到这一点。请注意,这两个例子并不完全相同。正如@Dmitri所指出的,
foo
可能返回的不是
myPtr
,因此要使第一个示例与第二个示例匹配,您需要将
foo
的结果分配给一个临时变量,然后将其传递到
bar
@Caleb-您是对的,但是OP展示了一个示例,其中参数返回时没有任何修改,这在C约定中确实是一个独特的情况。使用return重新分配或returnnull是不言自明的。返回相同的指针而不进行修改是一个有趣的例子。我从来没有说过C有类似C++的对象或引用。。。我的意思是,你会称之为不通过值传递某些内容(即需要副本的内容)的广义语言约定是什么?@Als,C上下文中的object表示“连续的内存块”,如结构。通过引用传递意味着传递指针,而不是传递值本身。这个术语并不少见。事实上,Stroustrup讨论了C++语言中“对象”的不同含义,第十节我们不能调用<代码>结构> /COD>、字符串等“对象”吗?任何时候你说“对象”都是指C++对象吗?我觉得这个定义有点严格……根据C99标准N1256第3.14.1节:“执行环境中数据存储的对象区域,其内容可以表示值”好的,感谢您的参考,我查找了它,也可以找到它,所以这很好。删除不必要的注释,因为它们不正确。