与C中函数参数中的char数组的大小相比,传递更大的char数组

时间:2017-12-01 17:15:22

标签: c arrays

我有一个以下C代码:

#include <stdio.h>
void test(char a[2])
{
    printf("%s", a);
}
int main()
{
    char t[5] = {'a', 'b', 'c', 'd'};
    test(t);
    return 0;
}

输出:abcd

在上面的代码中,我传递一个char指针(大小为5字节的char数组)。但该函数的参数大小为2个字节(char a[2])。该计划运作良好。

为什么没有编译错误或警告?这不是说这行void test(char a[2])期待2个字节的数组吗?

我和我的同事就此进行了辩论。在这种情况下请你开悟。

5 个答案:

答案 0 :(得分:3)

编译器忽略函数参数中数组第一维的大小。原型

void test(char a[2]);  

相当于

void test(char a[]);   
void test(char *a);  

或者你可以说编译器只是将void test(char a[2]);解释为void test(char *a) 同样

void void test2(char a[5][5]);   

相当于

  void void test2(char a[][5]);   
  void void test2(char (*a)[5]);    

答案 1 :(得分:3)

  

为什么没有编译错误或警告?这不是故意的吗?   line void test(char a 2)期待2个字节的数组?

除非前面有static,否则2中的void test(char a[2]);(由于向后兼容性原因一直追溯到B language (C's predecessor))只有评论。

换句话说,

void test(char a[2]);
void test(char a[2017]);
void test(char a[]);
void test(char *a);

都是完全等同的声明。

新(C11)允许:

void test(char a[static 2]);

语法允许test的作者说它真的必须得到一个指向至少 2个项目的数组的指针(更多很好),C11 makes it undefined表示test的调用者用任何不满足此要求的东西来调用它。但是,你不能指望一个警告。

实际上,在gcc / clang中,只有clang警告并且只有时候(并且tinycc甚至不支持这种扩展语法)

void test(char a[static 2]);
int main()
{
    char a[1]={0}, b=0;
    test(a); //clang warns about array bounds (gcc doesn't)
    test(&(char){'a'}); //no warning
    test(&b); //no warning
    return 0;
}

答案 2 :(得分:1)

没有。它衰变为char*。并且print通过提供地址来终止\0个char数组。

数组衰减成指向第一个元素的指针。这里第一个元素是char,因此它衰变为包含第一个元素地址的char*

而且,当您传递数组时,编译器会忽略第一个维度。

为什么编译器没有抱怨?

所以主要的是无法在C 中传递数组。如果你传递一个,那么基本上传递指向第一个元素的指针。由于此处不需要数组大小,因此忽略2。这就是编译器没有抱怨的原因。

这不是说这行void test(char a[2])期待2个字节的数组吗?

没有。它没有。这就是为什么你甚至可以这样做void test(char a[])void test(char a[2017])

答案 3 :(得分:1)

作为函数参数的数组会自动转换为指针。所以这个:

void test(char a[2])

与此相同:

void test(char *a)

这是有效的,因为数组在大多数上下文中衰减为指针,包括作为函数的参数。

答案 4 :(得分:1)

当传递数组作为函数参数时,它会立即衰减为指针,数组永远不会实际传递给函数。所以,你得到指针的大小而不是数组。

C11 6.3.2.1/3:

  

除非它是sizeof运算符或一元&amp;的操作数。   operator,或者是用于初始化数组的字符串文字,a   具有类型''数组类型''的表达式将转换为   带有''指向类型'的指针的表达式,指向初始值   数组对象的元素,而不是左值。