无法将 char *[2] 类型的数组的地址传递给采用 char *** 的函数

Posted

技术标签:

【中文标题】无法将 char *[2] 类型的数组的地址传递给采用 char *** 的函数【英文标题】:Unable to pass an address of array of type char *[2] to function taking char *** 【发布时间】:2013-09-10 20:06:11 【问题描述】:

我的 XCode(默认编译器应该是 clang?)在此代码上向我显示警告:

Incompatible pointer types passing 'char *(*)[2]' to parameter of type 'char ***'(调用func时)

void func (char ***arrayref, register size_t size) 
    /// ...


int main()

    char *array[2] = "string", "value";
    func(&array, 2);

虽然这段代码没有问题(=没有警告):

void func (char **arrayref, register size_t size) 
    /// ...


int main()

    char *array[2] = "string", "value";
    func(array, 2);

虽然这消除了警告

func((char***)&array, 2);

我仍然不知道为什么第一个发出警告,而后者没有。

此外,当第一个出现问题时,我还希望第一个发出警告,例如:

Incompatible pointer types passing 'char *[2]' to parameter of type 'char **'

【问题讨论】:

错误很明显:char *[10]char ** 是两个不同的东西。 因为演员说I know what I'm doing don't warn me @LihO 是的。但是为什么第二个代码没有发出警告呢? @user814064 这不是我的问题。我只是和演员一起写,以表明我知道解决方法...... 我不明白你的问题。此演员表的唯一功能是删除警告。 【参考方案1】:

您有一个 char *[2] 类型的数组,即由 2 个指向 char 的指针组成的数组。它是一个具有自动存储持续时间的固定大小的数组。您的函数可以对这种数组做的唯一事情是使用它的元素或更改它们(它不能调整它的大小或取消分配它......因此尝试使更改数组成为可能是没有意义的本身 ~> 换句话说:你真的不需要指向这种数组的指针)。

这是一个简单的例子:

void func (char *arrayref[2]) 
    printf("%s", arrayref[1]);
    arrayref[1] = "new value";


int main()     
    char *array[2] = "string", "value";
    func(array);
    printf(" -> %s", array[1]);
    return 0;

或者更改func 以获取未指定大小的数组,使其可与char *[X] 一起用于任何X,而不仅仅是2(在这种情况下,传递数组的大小已经有意义):

void func (char *arrayref[], size_t size) 
    if (size > 1) 
        printf("%s", arrayref[1]);
        arrayref[1] = "new value";
    

通过一种或另一种方式,该程序将输出value -> new value

如果您需要您的函数能够调整此数组的大小或以其他方式影响数组本身,您应该考虑使用动态分配的数组并以char** 的形式传递。

【讨论】:

【参考方案2】:

是时候简要回顾一下数组语义了。

除非它是sizeof 或一元& 运算符的操作数,或者是用于在声明中初始化另一个数组的字符串文字,否则为“T 的N 元素数组”类型的表达式将被转换(“衰减”)为“指向T的指针”类型的表达式,表达式的值将是数组中第一个元素的地址。

代码中的表达式array 的类型为“char * 的2 元素数组”或char *[2]。当您将它作为参数传递给func 时,如

func( array, 2 );

表达式被转换为“指向char *”的类型的表达式,或者char **,这是您的函数所期望的类型,表达式的值是第一个元素的地址:@987654333 @。这就是为什么您没有收到第二个代码 sn-p 的警告。

在第一个sn-p中,数组是一元&运算符的操作数,所以不会发生指针类型的转换;相反,表达式的类型是“指向char *2 元素数组 的指针”,或char *(*)[2],与char ** 不兼容。地址 value 相同(数组的第一个元素的地址与数组本身的地址相同),但类型不匹配,因此出现警告。

那么为什么这很重要?指针只是一个地址,所有地址都相同,对吧?嗯,不。指针是地址的抽象,具有相关的类型语义。指向不同类型的指针不必具有相同的大小或表示,并且指针运算取决于所指向类型的类型。

例如,如果我将一个指针声明为char **p;,那么表达式p++ 会将指针前进到指向char * 类型的下一个对象,或者从当前地址指向sizeof (char *) 字节。但是,如果p 被声明为char *(*p)[2],则表达式p++ 将前进p 以指向char * 的下一个二元素数组,即2 * @987654347 @ 来自当前地址的字节。

【讨论】:

必须读 3 遍……谢谢。 (我认为这是很多人误解的事情……) 知道很多人对此有误解,因为指针和数组语义不直观,而且几乎普遍传授得很糟糕,没有任何historical background 提供上下文。我不教 C 是件好事,因为整整半个学期都会花在复习类型上。 我已经读了一半了……明天继续。但它信息量非常。谢谢你。 (我经常将“谢谢”和“你”这两个词结合使用……) 很好的答案!仍然很难缠住头。【参考方案3】:

这是一个如何做你想做的事并改变数组指向的例子:

char *array2[] = "string", "NewValue";

void func0 (char **arrayref, register size_t size) 
    puts(arrayref[1]);


void func1 (char ***arrayref, register size_t size) 
    puts(arrayref[0][1]);
    *arrayref= (char **) array2;



int main()

    char *array[] = "string", "value";
    char **foo = array;
    func0(foo, 2);
    func1(&foo,2);
    func0(foo, 2);

【讨论】:

这与@glglgl 写的基本相同,但有一个更自我解释的代码示例。 (+1)【参考方案4】:
char *array[2] = "string", "value";

是一个包含char *的2个元素的数组。

使用array 作为地址会导致指向第一个元素的指针,即。 e.类型为char **

使用&array 会导致指向同一位置的指针,但类型为char *(*)[2](不确定拼写是否正确)。

这与char *** 不同 - 内存中的表示完全不同。

为了更详细,

+++++++++++++++++++++++
+ array[0] + array[1] +
+++++++++++++++++++++++

这是数组。

char ** p1 = array; // is a pointer to the first element, which in turn is a pointer.
char *(*p2)[2] = &array; // is a pointer to the whole array. Same address, but different type, i. e. sizeof(*p1) != sizeof(*p2) and other differences.

char ***p3 = &p1; // Now, p1 is a different pointer variable which has an address itself which has type `char ***`.

【讨论】:

现在这让我很困惑:我将如何创建一个指向数组的指针(例如指向第一个元素的指针)? @bwoebi 指向第一个元素的指针,即char *,将是char **。它是&array[0],可以缩写为array,作为数组名,在大多数情况下,降级为指向其第一个元素的指针。 例如我想在函数func中更改变量array指向的数组。 变量array 没有指向 一个数组,它is 一个数组。如果您确实有 char *** 参数,则必须提供中间变量的地址(例如我的示例中的 p3)。将array 视为常量值,例如471,您也无法更改其地址。 好的,这样描述更好。不知道这样的数组是不变的。令人困惑的 C.

以上是关于无法将 char *[2] 类型的数组的地址传递给采用 char *** 的函数的主要内容,如果未能解决你的问题,请参考以下文章

无法将二维字符数组传递给函数(C++)

无法将二维数组传递给 C++ 中的辅助函数

c语言 字符串传参问题

如何将二维数组类型 char(字符串)作为函数参数传递?

将 C# char 数组传递给 C++ 与字节数组不同

使用Struct将String数组和索引传递给C中的线程