C/C++中的字符指针和指向指针的数组

3

有一个带有以下头部的函数:

BPS_API int dialog_event_get_filebrowse_filepaths(bps_event_t* event,
                                            char** file_paths[], int* num_paths);

这是来自黑莓10本地SDK的内容,如果有人想知道它在哪里可以找到(可以在这里找到)。
问题是:我应该提供什么作为第二个参数。这个函数应该填充一个char指针数组以便返回所选文件路径。
我尝试以这种方式调用它:
char* ar[2];
dialog_event_get_filebrowse_filepaths(event, &ar, &number_paths);

我在QNX Momentics中遇到了以下错误:

cannot convert 'char * (*)[2]' to char * * * for argument 2 to int
dialog_event_get_filebrowse_filepaths(bps_event_t *, char * * *, int *)

这似乎是最合理的称呼方式。据我所知,它需要一个指向指针数组的内存地址才能设置它们。 然而,如果我声明:
char** ar[2];
dialog_event_get_filebrowse_filepaths(event, ar, &number_paths);

它能够工作,但这样我创建了一个指向字符指针的指针数组(一个字符指针数组的数组)。这才是我真正应该提供给函数的吗?

1
@Macmade 这可能是初学者的错误,但您的讽刺似乎并没有帮助我。您能详细解释一下吗? - user1114055
1
该函数需要 char** file_paths[],这是一个指向 char 指针的指针数组(可能是指向 char 数组的指针数组),因此请将其作为第二个示例提供。在调用之前,您可能需要为数组成员分配存储空间。 - Daniel Fischer
2
@Alex 需要查阅文档。书写方式表明它需要一个指向C字符串的指针数组。但是作为函数参数,它是'char ***',所以Vaughn Ctao的猜测可能是正确的。将'指向char *数组的指针'强制转换为该类型可能是正确的方法,但与签名不太相符。 - Daniel Fischer
@Daniel Fischer,是的,你可能在Vaughn Ctao的观点上是正确的(谈论间接性,呵呵)。正如我在评论中所说,我会测试一下,如果它返回正确的结果,我会将其标记为答案。然而,他们选择了一种非常不方便的方式来声明参数,因为他们知道指针和字符数组的混淆会带来很多困惑。 - user1114055
我并不是说任何人是正确的(或错误的)。我没有足够的信息去判断这个函数。 - Daniel Fischer
显示剩余4条评论
4个回答

3
文档应该更加明确,但我相信这就是函数期望的内容:
首先,有一些经验法则可以帮助解码函数:
- 类型等效于 char***。这意味着我们必须找到三个指针的含义。 - C 中的字符串是 char*(为简洁起见省略 const)。由于我们希望函数填充一个字符串数组,因此这就是一个 * 的解释。 - 在 C 中,数组通常由指针表示。因此这就是第二个 *。 - "输出参数" 可以采用两种方式处理:要么调用方分配内存并传递指针,告诉被调用者在哪里写入其数据;要么调用方不分配任何内存,只需传递指向指针的指针。被调用者将修改 "最内层" 指针,使其指向被调用者自己分配的一块内存。第二种方法会解释最后一个 *。这也解释了文档注释,即 "保存这些值的内存在不再需要时必须使用 bps_free() 释放" -- 因为内存是由库函数分配而不是你分配的,所以很重要使用正确的 free 函数。
因此,函数应该像这样调用:
char** strs;
dialog_event_get_filebrowse_filepaths(foo, &strs, bar);

当函数返回时,strs将指向由dialog_event_get_filebrowse_filepaths分配的字符串数组的第一个条目。


谢谢你解密。这可能是正确的方式。 - user1114055

2
我猜测应该像这样调用:

只是一个猜想,但我认为它应该这样命名:

char** ar = 0;
dialog_event_get_filebrowse_filepaths(event, &ar, &number_paths);

虽然它是用数组语法声明的,但这是C风格函数返回分配的字符串数组的常见方式,这可能会让人感到困惑。


这肯定能编译通过,我已经试过了,但我还没有测试过它。如果在我测试后它能够正常工作,我会将其标记为问题的答案。 - user1114055

2

这个函数将通过参数返回一个字符串数组和数组的长度,您可以像这样使用它:

char **ar=0;
int i,number_paths = 0;
dialog_event_get_filebrowse_filepaths(event, &ar, &number_paths);
for( i=0; i<number_paths; i++ )
  puts( ar[i] );

您需要释放内存(请参阅库文档),方法如下:

for( i=0; i<number_paths; i++ )
  free( ar[i] );
free( ar );

1

这里有一些(非Blackberry)代码,应该能够满足编译器的要求:

char *file_paths[];
iret = dialog_event_get_filebrowse_filepaths (event, &ar, &number_paths);

重点是:
1)在声明中不要分配固定长度。
2)将数组指针的地址(&)传递给您的函数。
3)确保某人(API函数或您自己)分配了数组和数组中的所有字符串。

如果我不指定一个固定的长度,编译器会报错:file_paths 的存储大小未知。 - user1114055
char *file_paths[]; 不是有效的 C 数组定义;哪个 C 编译器会编译这个? - user411313

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接