C语言 将数组作为指针和值传递给函数

hs1ihplo  于 2022-12-26  发布在  其他
关注(0)|答案(1)|浏览(175)

用这种方法传递数组有什么区别?

static char arr[N];

void func(void *buf, size_t size) {
    // ...
}

int main(void) {
    func(arr, N);

    // ...
}

这样

// ...

int main(void) {
    func(&arr, N);

    // ...
}

在那些清单中有任何遵从吗?看起来第2版传递了一个数组作为void **,但真的是这样吗?

wlwcrazw

wlwcrazw1#

第一个是正确的,第二个是错误的,或者至少是非常值得怀疑的。
arr在表达式中使用或传递给函数时,会被调整为指向第一个元素的指针,因此它等价于char*
在第二个例子中,&arr是这个"数组衰减"规则的少数例外之一。我们得到的不是指向第一个元素的指针,而是指向整个数组的指针,类型char(*)[N]。这种类型与char*不兼容,所以如果你试图在函数内部将void* buf转换为char*,第二个例子会导致一个微妙的bug。
第二个例子之所以能够编译,是因为void*(并且只有该类型,而不是void**)是一种特殊的指针类型,可以与任何其他指向对象的指针相互转换。

void func(char *buf, size_t size)

然后func(&arr, N);给出预期的编译器诊断"从不兼容的指针类型传递" func "的参数1"。
如果你这样写函数

void func(void *buf, size_t size) {
    char* ptr = buf;
    for(int i=0; i<size; i++)
    {
      printf("%c ", ch[i]);
    }
}

它很可能适用于任何一个版本,因为第一项的地址(char*)与数组的地址(char(*)[N])相同,而且,C特有的类型系统允许我们通过相同类型的项的数组或结构体访问某种类型的内存位置("严格别名规则")。
最佳做法:

  • 使用第一版。
  • 尽可能避免使用void*,因为它们是类型不安全的。
  • 尽可能显式地使用类型,不要依赖隐式类型转换。

相关问题