【问题标题】:How to return a char** as a function argument如何将 char** 作为函数参数返回
【发布时间】:2020-11-25 14:52:25
【问题描述】:

我有一个函数,它返回一个指向字符指针的指针 (char**)。该函数有 2 个参数

  • int* num_paths:指向整数的指针,表示要返回的字符串数。
  • int* errno:指向整数的指针以指示错误代码。这可以包含不同的值,因此我不能简单地检查是否在出现错误时返回 NULL

下面编写了一些示例代码(为简单起见,省略了大部分错误检查):

char** get_paths(int* num_paths, int* errno) {
    char* path1 = NULL;
    char* path2 = NULL;
    char** paths = NULL;

    if(errno == NULL) {
        printf("Set errno in case of error, but cannot dereference NULL pointer\n");
        goto exit;
    }

    path1 = calloc(1, strlen("foo") + 1);
    path2 = calloc(1, strlen("bar") + 1);

    strcpy(path1, "foo");
    strcpy(path2, "bar");

    *num_paths = 2;
    paths = calloc(1, *num_paths*sizeof(char *));
    paths[0] = path1;
    paths[1] = path2;

    *errno = 0;
exit:
    return paths;
}

int main(void) {
    char** paths = NULL;
    int num_paths = 0;
    int errno = 0;

    paths = get_paths(&num_paths, &errno);
    if(errno != 0) {
        return -1;
    }

    for(int i = 0; i < num_paths; i++) {
        printf("%s\n", paths[i]);
        free(paths[i]);
    }
    free(paths);
}

我遇到的问题是,如果 NULL 指针作为 errno 的参数传递,我无法设置错误代码。您可以争辩说这是一个用户错误,但我仍然希望首先避免这种情况。

所以我的问题是:我可以重写我的get_paths 函数,使其返回一个整数作为错误代码,但也可以通过函数参数返回一个char**,而不使用char***,如下例所示:

int get_paths_3(char*** paths, int* num_paths) {
    char* path1 = NULL;
    char* path2 = NULL;

    path1 = calloc(1, strlen("foo") + 1);
    path2 = calloc(1, strlen("bar") + 1);

    strcpy(path1, "foo");
    strcpy(path2, "bar");

    *num_paths = 2;
    *paths = calloc(1, *num_paths*sizeof(char *));
    (*paths)[0] = path1;
    (*paths)[1] = path2;

    return 0;
}

【问题讨论】:

  • 如果 that 指针也是NULL,则无法设置路径数。我不明白你为什么不能记录函数:NULL 指针参数不允许。
  • “通过函数参数返回char**”的正确方法是使用char*** 参数。有很多方法可以设计这个函数,但设计选择很大程度上决定了函数签名需要什么。
  • 我不会使用errno 作为变量名。标准的 &lt;errno.h&gt; 标头(从许多其他地方间接包含)#define-s 它作为一个宏。
  • 您可以将指针和整数都包装在 struct 中并返回。
  • 一般来说,我会将诸如“如果将 NULL 作为参数传递给错误”之类的琐碎事情的错误处理工作交给调用者。只需记录该函数:“如果您将 NULL 传递给此参数,那么您就是 f****d”。应在调用方进行各种此类健全性检查和防御性编程。

标签: c pointers char return-value dynamic-memory-allocation


【解决方案1】:

这几乎是唯一可以使用“三星”指针的情况。在 API 设计中为错误代码保留返回值是相当普遍的做法,因此这种情况并不少见。

还有其他选择,但可以说它们并没有好多少。你可以滥用void* 可以转换为char** 或从char** 转换的事实,但它并没有更漂亮和更不安全:

// not recommended

int get_paths_4 (void** paths, size_t* num_paths)
{
    char* path1 = calloc(1, strlen("foo") + 1);
    char* path2 = calloc(1, strlen("bar") + 1);

    strcpy(path1, "foo");
    strcpy(path2, "bar");

    *num_paths = 2;
    char** path_array;
    path_array= calloc(1, *num_paths*sizeof(char *));
    path_array[0] = path1;
    path_array[1] = path2;
    *paths = path_array;
    return 0;
}

...

void* vptr;
size_t n;

get_paths_4 (&vptr, &n);
char** paths = vptr;

for(size_t i=0; i<n; i++)
{
  puts(paths[i]);
}

一个更合理的选择可能是将所有参数包装成一个 struct 类型并将其作为指针传递。

【讨论】:

  • 感谢您的有趣讨论。这非常有帮助。如果被接受,我要么坚持我原来的实现,要么应用“三星级”指针解决方案。
【解决方案2】:

很遗憾,你不能在 C 中混合返回类型是一个可怕的错误,不应该这样做,你可以:

  • 返回你需要的指针并向变量添加错误代码
  • 返回错误代码并添加指向变量的指针

两者都是有效的策略,我会选择与您的其余代码相匹配的策略以保持一致性。

【讨论】:

    猜你喜欢
    • 2014-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-31
    • 2021-12-26
    • 2011-08-30
    • 2015-03-03
    • 2020-02-21
    相关资源
    最近更新 更多