如何 return 一个 char** 作为函数参数
How to return a char** as a function argument
我有一个函数 returns 一个指向字符指针的指针 (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
函数,使其 returns 一个整数作为错误代码,而且 returns 一个 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;
}
不幸的是,你不能在 C 中混合 return 类型是一个可怕的错误,不应该这样做,你可以:
- return你需要的指针并添加一个错误代码到一个变量
- return 错误代码并添加指向变量的指针
两者都是有效的策略,我会选择与您的其余代码相匹配的策略以保持一致性。
这几乎是唯一可以使用“三星级”指针的情况。在 API 设计中,为错误代码保留 return 值是相当普遍的做法,因此这种情况并不少见。
有其他选择,但可以说它们也好不了多少。您可能会滥用 void*
可以转换为 to/from 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
类型中并将该类型作为指针传递。
我有一个函数 returns 一个指向字符指针的指针 (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
函数,使其 returns 一个整数作为错误代码,而且 returns 一个 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;
}
不幸的是,你不能在 C 中混合 return 类型是一个可怕的错误,不应该这样做,你可以:
- return你需要的指针并添加一个错误代码到一个变量
- return 错误代码并添加指向变量的指针
两者都是有效的策略,我会选择与您的其余代码相匹配的策略以保持一致性。
这几乎是唯一可以使用“三星级”指针的情况。在 API 设计中,为错误代码保留 return 值是相当普遍的做法,因此这种情况并不少见。
有其他选择,但可以说它们也好不了多少。您可能会滥用 void*
可以转换为 to/from 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
类型中并将该类型作为指针传递。