【问题标题】:Why is a temporary char** argument illegal?为什么临时 char** 参数是非法的?
【发布时间】:2019-04-04 15:06:00
【问题描述】:

我有一个函数f(char **p),我想以最简单的方式调用它。

我试过了

char ** p = {"a", "b"};
f(p);

得到:

标量对象在初始化器中需要一个元素

所以我把它改成了

char * p[2] = {"a", "b"};
f(p);

一切顺利 [只要char * p[] 也可以]。

为什么我不能像下面这样动态地创建一个指针数组?

f({"a", "b"});

【问题讨论】:

  • 嗯,我能想象到的最简单的方法是char *p; f(&p); 如果需要字符串数组或应在函数中修改的指针地址,这取决于函数的语义。

标签: c function pointers


【解决方案1】:

这给出了一个警告:

char ** p = {"a", "b"};

因为p 不是数组。

这也是不合法的:

f({"a", "b"});

因为大括号本身不允许在表达式中使用(但可以用作初始值设定项)。

可以使用复合文字动态创建数组:

f((char *[]){"a", "b"});

您还可以使用复合文字来初始化临时:

char ** p = (char *[]){"a", "b"};

与第一个语句不同,这是有效的,因为字面量是 char *[2] 类型的数组,并且会衰减为 char **,可用于初始化此类型的变量。

有关复合文字的更多详细信息,请参阅C standard 的第 6.5.2.5 节。

【讨论】:

  • 不幸的是,以这种方式创建的任何复合文字的生命周期都以最近的封闭块结束,因此给定 int **p; ... if (someCondition) p=(int*[2]){&x,&y}; 在 if 控制语句周围添加大括号将导致复合创建的对象文字在代码可以使用之前就死掉了。
  • @supercat:我不得不承认我希望这样的文字表现得像字符串常量——也就是说它们真的永远存在并且在只读内存中。哦,好吧。
  • @Joshua:或者至少可以将它们声明为 static 并具有这样的行为,或者持续到代码离开当前 函数 或重新执行文字。据推测,文字不会在当前函数中持续存在的原因是,如果重新执行它们会发生什么,则存在歧义,但是将它们限制在当前块中并不能消除这种歧义。
  • @Joshua:据我所知,代码编译器需要为复合文字生成的唯一常见情况不会不必要地低效,那就是聚合成员都不是常量。与以类似于字符串文字的方式处理它们相比(产生一个指向 const 存储区域的指针,该区域可能与任何其他区域不同,也可能不同,但会保存正确的值),这相当无用。太糟糕了,标准支持的唯一一种复合文字是无用的。
【解决方案2】:

此声明char ** p = {"a", "b"}; 触发警告,因为C 不知道如何解释{ } 大括号的内容:

  • 声明类型 char** 表明它是一个指向字符的指针
  • { } 的内容指定了两个项目。

您需要通过在大括号前指定类型来告诉 C,您正在使用指向匿名数组的初始元素的指针来初始化指向指针的指针:

char ** p = (char*[]){"a", "b"}

这种结构称为“复合文字”。它可以在声明中使用,但也可以用作表达式。

注意:如果您打算将这样的数组传递给函数,您需要提供一种方法来确定数组的大小。一种方法是传递NULL 来“终止”数组,如下所示:

void f(char **p) {
    int i = 0;
    while (*p) {
        printf("%d:%s\n", i++, *p++);
    }
}
int main(void) {
    f((char*[]){"a", "b", NULL});
    return 0;
}

Demo.

【讨论】:

    【解决方案3】:

    C99 及更高版本添加 compound literals 的确切目的:动态创建数组和结构
    示例:

    struct foo {int a; char b[2];} structure;
    structure = ((struct foo) {1, 'a', 0});
    int *y = (int []) {1, 2, 3};
    int *z = (int []) {1}; 
    

    除了 std C99 及更高版本,GCC 也提供此功能作为扩展。
    在您的情况下,这将起作用

    f((char *[]){"a","b"});
    

    (char *[]){"a","b"} 是一个复合文字,它动态创建一个包含 2 个指向 char 的指针的数组。

    【讨论】:

    • GCC 也提供此功能作为扩展 - 这 (f((char *[]){"a","b"});) 在 Clang 上不起作用?
    • @CIsForCookies; Clang 也提供了相同的扩展。在clang中int []y = (int []) {1, 2, 3};也可以工作,而GCC会抛出错误。
    猜你喜欢
    • 2019-11-04
    • 2011-05-17
    • 1970-01-01
    • 2011-08-14
    • 2018-05-19
    • 1970-01-01
    • 2011-11-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多