数组类型 - 分配/用作函数参数的规则
当我需要将数组传递给函数时,似乎该函数的以下所有声明都适用
void f(int arr[])
void f(int arr[4]) // is this one correct?
:
int a[]={1,2,3,4};
f(a);
但是当我将一个数组分配给另一个数组时,它会失败
int a[]={1,2,3,4};
int b[4] = a; // error: array must be initialized with a brace-enclosed initializer
那么为什么将数组作为函数的参数传递是可以的,但是用在rhs上简单赋值是错误的?
when I need to pass an array to a function, it seems all the following declarations of the function will work
void f(int arr[])
void f(int arr[4]) // is this one correct?
for this:
int a[]={1,2,3,4};
f(a);
But when I assign an array to another array, it fails
int a[]={1,2,3,4};
int b[4] = a; // error: array must be initialized with a brace-enclosed initializer
So why an array passed as an argument of a function is okay, but used on the rhs of simple assignment is wrong?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
为了理解差异,我们需要理解两个不同的上下文。
T
类型的数组的名称相当于指向T
类型的指针,并且等于指向数组的第一个元素。T
类型的数组的名称不会简化为指针。什么是对象上下文?
在
a = b;
中,a
位于对象上下文中。当您获取变量的地址时,它将在对象上下文中使用。最后,当您对变量使用sizeof
运算符时,它会在对象上下文中使用。在所有其他情况下,变量都在值上下文中使用。现在我们已经有了这些知识,当我们这样做时:
它完全相当于
正如您所发现的,我们可以从函数声明中省略大小(上面的 4)。这意味着您无法知道传递给
f()
的“数组”的大小。稍后,当您执行以下操作时:在函数调用中,名称
a
位于值上下文中,因此它简化为指向int
的指针。这很好,因为f
需要一个指向int
的指针,因此函数定义和使用相匹配。传递给f()
的是指向a
第一个元素的指针 (&a[0]
)。在名称
b
的情况下,在对象上下文中使用,并且不会简化为指针。 (顺便说一句,
a
这里位于值上下文中,并简化为指针。)现在,
int b[4];
分配存储值4 个int
并为其指定名称b
。a
也被分配了类似的存储空间。因此,实际上,上面的赋值意味着“我想让存储位置与之前的位置相同”。这没有道理。如果您想将
a
的内容复制到b
中,那么您可以这样做:或者,如果您想要一个指针
b< /code> 指向
a
:这里,
a
位于值上下文中,并简化为指向int
的指针,因此我们可以分配 < code>a 到int *
。最后,在初始化数组时,您可以为其指定显式值:
这里,a 有 4 个元素,初始化为 1、2、3 和 4。您还可以这样做:
如果元素较少列表中的元素数量大于数组中的元素数量,则其余值均视为 0:
将
a[2]
和a[3]
设置为 0 。For understanding the difference, we need to understand two different contexts.
T
is equivalent to a pointer to typeT
, and is equal to a pointer to the array's first element.T
does not reduce to a pointer.What is object context?
In
a = b;
,a
is in object context. When you taken the address of a variable, it's used in object context. Finally, when you usesizeof
operator on a variable, it's used in object context. In all other cases, a variable is used in value context.Now that we have this knowledge, when we do:
It is exactly equivalent to
As you found out, we can omit the size (4 above) from the function declaration. This means that you can't know the size of the "array" passed to
f()
. Later, when you do:In the function call, the name
a
is in value context, so it reduces to a pointer toint
. This is good, becausef
expects a pointer to anint
, so the function definition and use match. What is passed tof()
is the pointer to the first element ofa
(&a[0]
).In the case of
The name
b
is used in a object context, and does not reduce to a pointer. (Incidentally,a
here is in a value context, and reduces to a pointer.)Now,
int b[4];
assigns storage worth of 4int
s and gives the nameb
to it.a
was also assigned similar storage. So, in effect, the above assignment means, "I want to make the storage location the same as the previous location". This doesn't make sense.If you want to copy the contents of
a
intob
, then you could do:Or, if you wanted a pointer
b
that pointed toa
:Here,
a
is in value context, and reduces to a pointer toint
, so we can assigna
to anint *
.Finally, when initializing an array, you can assign to it explicit values:
Here, a has 4 elements, initialized to 1, 2, 3, and 4. You could also do:
If there are fewer elements in the list than the number of elements in the array, then the rest of the values are taken to be 0:
sets
a[2]
anda[3]
to 0.语法具有误导性。它们都与此相同:
即,您传递一个指向数组开头的指针。您没有复制数组。
The syntax is misleading. They are both the same as this:
i.e., you are passing a pointer to the start of the array. You are not copying the array.
C 不支持数组赋值。在函数调用的情况下,数组会衰减为指针。 C 确实支持指针赋值。几乎每天都会有人问这个问题 - 你们在读哪本没有解释这个问题的 C 教科书?
C does not support the assignment of arrays. In the case of a function call, the array decays to a pointer. C does support the assignment of pointers. This is asked here just about every day - what C text book are you guys reading that doesn't explain this?
尝试 memcpy。
谢谢你指出这一点,Steve,我已经有一段时间没有使用 C 了。
Try memcpy.
Thanks for pointing that out, Steve, it's been a while since I used C.
为了获得对此的直觉,您必须了解机器级别上发生的情况。
初始化语义 (= {1,2,3,4}) 意味着“完全按照这种方式将其放在二进制图像上”,以便可以对其进行编译。
数组赋值会有所不同:编译器必须将其转换为循环,该循环实际上会迭代元素。 C 编译器(或 C++,就此而言)从不做这样的事情。它理所当然地期望你自己做这件事。为什么?因为你可以。所以,它应该是一个用 C 语言(memcpy)编写的子程序。这都是关于简单性和接近你的武器,这就是 C 和 C++ 的全部。
To get your intuition about it, you must understand what's going on on machine level.
The initialization semantics (= {1,2,3,4}) means "put it on your binary image exactly this way" so this can be compiled.
Array assignment would be different: the compiler would have to translate it into a loop, which would actually iterate over elements. C compiler (or C++, for that matter) never does such a thing. It rightfully expects you to do it yourself. Why? Because you can. So, it should be a subroutine, written in C (memcpy). This is all about simplicity and closeness to your weapon, which is C and C++ all about.
请注意,
int a[4]
中的a
类型为int [4]
。但是TypeOf(
&a
) ==int (*)[4]
!=int [4]
。另请注意,
a
的value 类型是int *
,这与上述所有类型都不同!这是您可以尝试的示例程序:
Note that the type of
a
inint a[4]
isint [4]
.But TypeOf(
&a
) ==int (*)[4]
!=int [4]
.Also note that the type of the value of
a
isint *
, which is distinct from all of the above!Here's a sample program you can try:
我想澄清一下。答案中有一些误导性的提示...以下所有函数都可以采用整数数组:
但是形式参数并不相同。因此编译器可以以不同的方式处理它们。从内部内存管理的意义上来说,所有的参数都指向指针。
... f() 接受任意大小的数组。
... 形式参数表示数组大小。
...您还可以传递整数指针。 f() 不知道任何有关大小的信息。
I want to clarify. There are some misleading hints in answers... All following functions can take integer arrays:
But formal arguments are not the same. So the compiler can handle them differently. In the sense of internal memory management, all arguments lead to pointers.
... f() takes an array of any size.
... The formal argument indicates an array size.
... You can also pass an integer pointer. f() does not know anything about the size.