数组类型 - 指定/用作函数参数的规则

Tim*_*Tim 6 c arrays initialization variable-assignment

当我需要将一个数组传递给一个函数时,似乎所有以下函数声明都可以工作

void f(int arr[])  
void f(int arr[4]) // is this one correct?
Run Code Online (Sandbox Code Playgroud)

为了这:

int a[]={1,2,3,4};
f(a);
Run Code Online (Sandbox Code Playgroud)

但是当我将一个数组分配给另一个数组时,它就失败了

int a[]={1,2,3,4};
int b[4] = a; // error: array must be initialized with a brace-enclosed initializer
Run Code Online (Sandbox Code Playgroud)

那么为什么作为函数的参数传递的数组是可以的,但是在简单赋值的rhs上使用是错误的?

Alo*_*hal 12

为了理解差异,我们需要了解两种不同的背景.

  • 上下文中,类型数组的名称T等效于指向类型的指针T,并且等于指向数组第一个元素的指针.
  • 对象上下文中,类型数组的名称T不会缩减为指针.

什么是对象上下文?

In a = b;,a在对象上下文中.当您获取变量的地址时,它将在对象上下文中使用.最后,当您sizeof对变量使用运算符时,它将在对象上下文中使用.在所有其他情况下,变量用于值上下文.

现在我们掌握了这些知识,当我们这样做时:

void f(int arr[4]);
Run Code Online (Sandbox Code Playgroud)

完全等同于

void f(int *arr);
Run Code Online (Sandbox Code Playgroud)

如您所知,我们可以省略函数声明中的大小(上面的4).这意味着您无法知道传递给的"数组"的大小f().以后,当你这样做时:

int a[]={1,2,3,4};
f(a);
Run Code Online (Sandbox Code Playgroud)

在函数调用中,名称a在值上下文中,因此它缩减为指向int.这很好,因为f需要指向一个指针int,所以函数定义和使用匹配.传递给f()它的是指向a(&a[0])的第一个元素的指针.

如果是

int a[]={1,2,3,4};
int b[4] = a;
Run Code Online (Sandbox Code Playgroud)

该名称b用于对象上下文,并不会缩减为指针.(顺便说一下,a这里一个值上下文,并缩减为指针.)

现在,int b[4];分配存储价值4 int秒并给它起名字b. a也分配了类似的存储空间.因此,实际上,上述分配意味着"我想使存储位置与先前位置相同".这没有意义.

如果要复制a into 的内容b,则可以执行以下操作:

#include <string.h>
int b[4];
memcpy(b, a, sizeof b);
Run Code Online (Sandbox Code Playgroud)

或者,如果你想要一个指针b是指向a:

int *b = a;
Run Code Online (Sandbox Code Playgroud)

这里,a是在值上下文中,并缩减为指向int,所以我们可以赋值aint *.

最后,在初始化数组时,您可以为其指定显式值:

int a[] = {1, 2, 3, 4};
Run Code Online (Sandbox Code Playgroud)

这里有一个有4个元素,初始化为1,2,3和4.您还可以这样做:

int a[4] = {1, 2, 3, 4};
Run Code Online (Sandbox Code Playgroud)

如果列表中的元素少于数组中元素的数量,则其余值将取为0:

int a[4] = {1, 2};
Run Code Online (Sandbox Code Playgroud)

a[2]a[3]为0.


dav*_*420 7

void f(int arr[]);
void f(int arr[4]);
Run Code Online (Sandbox Code Playgroud)

语法有误导性.它们都是这样的:

void f(int *arr);
Run Code Online (Sandbox Code Playgroud)

即,您正在将指针传递给数组的开头.你没有复制数组.

  • 是的,但是(在C99中)`void f(int arr [static 4]){...}`是特殊的,因为这允许编译器假设`arr`是非`'NULL`并且大小至少为4. (3认同)

小智 6

C不支持数组的赋值.在函数调用的情况下,数组衰减为指针.C确实支持指针的分配.几乎每天都会问这个问题 - 你们正在阅读哪些C教科书并不能解释这一点?