1

我以为我理解 c 和指针,但只是在调试我认为不应该工作但确实可以工作的其他人的代码。作为一个(粗略的)例子......

void clear_buffer(char* buff, int len)
{
    while(len)
    {
        *buff++ = ' ';
        len--;
    }
}

main()
{
    char buffer[10];

    clear_buffer(&buffer,10);   // 1. what I found, it still works...
    clear_buffer(buffer,10);    // 2. what I would have wrote
}

令我惊讶的是,上面的两个调用的工作方式完全相同。第一个给出编译器警告(不兼容的指针类型),但它仍然可以正确构建和运行。所以我的问题是:这是 C 中的预期行为,还是只是我使用的编译器很聪明并修复了错误?fwiw,这是使用微芯片 xc16 编译器。

4

2 回答 2

2

在表达式clear_buffer(buffer, 10)中,buffer被转换为指向其第一个元素的指针,因此等价于&buffer[0]。在表达式clear_buffer(&buffer, 10)中,buffer不转换为指向其第一个元素的指针,因为它是&地址运算符的操作数。这是数组衰减为表达式中的指针的规则的例外之一。(该规则的另一个例外是sizeof运算符。)

数组的第一个元素与数组本身的地址相同,因此&buffer&buffer[0]具有相同的地址,但类型不同。&buffer具有类型char (*)[10](指向数组 [10] 的指针char),并且&buffer[0]具有类型char *

警告是由于调用中的指针类型不匹配clear_buffer(&buffer, 10)

于 2021-05-25T10:50:51.493 回答
1

这个电话

clear_buffer(&buffer,10);

不正确,编译器将发出错误消息。

表达式的类型&bufferchar ( * )[10],而相应的函数参数的类型是char *,并且没有从一种类型到另一种类型的隐式转换。

程序按预期工作,因为表达式的值&bufferbuffer相同的:尽管表达式的类型不同,但它是数组占用的内存范围的地址。

考虑另一个例子。这是一个演示程序

#include <stdio.h>

int main(void) 
{
    struct A
    {
        int x;
    } a = { 10 };
    
    printf( "&a   = %p\n", ( void * )&a );
    printf( "&a.x = %p\n", ( void * )&a.x );

    return 0;
}

程序输出为

&a   = 0x7ffef64abb84
&a.x = 0x7ffef64abb84

如您所见,尽管表达式的类型不同,但程序输出相同的地址&a并且&a.x是不同的。

在您的程序中也会发生同样的情况。尽管整个数组及其元素的类型不同,但整个数组的地址等于其第一个元素的地址。

实际上,在您的函数中,您将指向整个类型数组的指针重新解释为指向类型char ( * )[10]的第一个数组元素的指针char *

于 2021-05-25T10:48:53.070 回答