为什么 type arrayp[] 与 type* arrayp 相同作为函数的参数?
Why is type arrayp[] the same as type* arrayp as parameter of a function?
为什么是f.e。 int arrayp[]
与int* arrayp
相同,作为函数definition/declaration 中的参数?
int* foo(int arrayp[]){}
指向作为调用方参数传递的 int
数组第一个元素的指针。
喜欢:
#include <stdio.h>
int* foo (int arrayp[]);
int main(void)
{
int a[] = { 10,5,4,2,1 };
int *p;
p = foo(a);
printf("%d",*p);
return 0;
}
int* foo(int arrayp[])
{
*arrayp = 0;
return arrayp;
}
为什么 int arrayp[]
是指向 int
类型数组第一个元素的指针?恕我直言,我认为这很令人困惑。有些人可能认为他们用这个表达式传递了整个数组(按值传递)。
很难明确回答 Why 问题。在 C 语言中,array/pointer 对偶性被广泛使用。习惯了就不会觉得乱了。
不要将其视为指向第一个元素的指针 -- 将其视为指向整个数组的指针。 *a
是第一个元素,但 *(a+1)
是下一个元素。
在函数参数类型中,数组被隐式调整为它们将衰减到的指针。
因此,例如,这些函数声明对是兼容的:
void foo(int a[]);
void foo(int *a); //compatible declaration
void bar(int a[][2][3]);
void bar(int (*a)[2][3]); //compatible declaration
Dennis Ritchie(语言作者)在 https://www.bell-labs.com/usr/dmr/www/chist.html
中解释了这个令人困惑的规则
Moreover, some rules designed to ease early transitions contributed to
later confusion. For example, the empty square brackets in the
function declaration
int f(a) int a[]; { ... } are a living fossil, a remnant of NB's way
of declaring a pointer; a is, in this special case only, interpreted
in C as a pointer. The notation survived in part for the sake of
compatibility, in part under the rationalization that it would allow
programmers to communicate to their readers an intent to pass f a
pointer generated from an array, rather than a reference to a single
integer. Unfortunately, it serves as much to confuse the learner as to
alert the reader.
(注意:Chist.html 使用 K&R 风格的函数定义。上述函数定义的原型等效为 int f( int a[]){ ... }
。)
简而言之,该规则的存在主要是为了简化从 B 到 C 的转换,并允许程序员向 reader 发出信号,表明需要指向数组第一个元素的指针,而不仅仅是一个指向单个元素的指针(无需使用注释即可这样做)。
函数类型的参数也以类似的方式调整为指针。
void takeFuncPtr(void Func(void));
void takeFuncPtr(void (*Func)(void)); //compatible declaration
一个可能更深层次的问题是 "why do arrays decay to pointers at all in C"?。链接文档也提供了该问题的答案:
...
These semantics represented an easy transition from B, and I
experimented with them for some months. Problems became evident when I
tried to extend the type notation, especially to add structured
(record) types. Structures, it seemed, should map in an intuitive way
onto memory in the machine, but in a structure containing an array,
there was no good place to stash the pointer containing the base of
the array, nor any convenient way to arrange that it be initialized.
For example, the directory entries of early Unix systems might be
described in C as
struct { int inumber; char name[14]; };
I wanted the structure not
merely to characterize an abstract object but also to describe a
collection of bits that might be read from a directory. Where could
the compiler hide the pointer to name that the semantics demanded?
Even if structures were thought of more abstractly, and the space for
pointers could be hidden somehow, how could I handle the technical
problem of properly initializing these pointers when allocating a
complicated object, perhaps one that specified structures containing
arrays containing structures to arbitrary depth? The solution
constituted the crucial jump in the evolutionary chain between
typeless BCPL and typed C. It eliminated the materialization of the
pointer in storage, and instead caused the creation of the pointer
when the array name is mentioned in an expression. The rule, which
survives in today's C, is that values of array type are converted,
when they appear in expressions, into pointers to the first of the
objects making up the array.
...
为什么是f.e。 int arrayp[]
与int* arrayp
相同,作为函数definition/declaration 中的参数?
int* foo(int arrayp[]){}
指向作为调用方参数传递的 int
数组第一个元素的指针。
喜欢:
#include <stdio.h>
int* foo (int arrayp[]);
int main(void)
{
int a[] = { 10,5,4,2,1 };
int *p;
p = foo(a);
printf("%d",*p);
return 0;
}
int* foo(int arrayp[])
{
*arrayp = 0;
return arrayp;
}
为什么 int arrayp[]
是指向 int
类型数组第一个元素的指针?恕我直言,我认为这很令人困惑。有些人可能认为他们用这个表达式传递了整个数组(按值传递)。
很难明确回答 Why 问题。在 C 语言中,array/pointer 对偶性被广泛使用。习惯了就不会觉得乱了。
不要将其视为指向第一个元素的指针 -- 将其视为指向整个数组的指针。 *a
是第一个元素,但 *(a+1)
是下一个元素。
在函数参数类型中,数组被隐式调整为它们将衰减到的指针。
因此,例如,这些函数声明对是兼容的:
void foo(int a[]);
void foo(int *a); //compatible declaration
void bar(int a[][2][3]);
void bar(int (*a)[2][3]); //compatible declaration
Dennis Ritchie(语言作者)在 https://www.bell-labs.com/usr/dmr/www/chist.html
中解释了这个令人困惑的规则Moreover, some rules designed to ease early transitions contributed to later confusion. For example, the empty square brackets in the function declaration
int f(a) int a[]; { ... } are a living fossil, a remnant of NB's way of declaring a pointer; a is, in this special case only, interpreted in C as a pointer. The notation survived in part for the sake of compatibility, in part under the rationalization that it would allow programmers to communicate to their readers an intent to pass f a pointer generated from an array, rather than a reference to a single integer. Unfortunately, it serves as much to confuse the learner as to alert the reader.
(注意:Chist.html 使用 K&R 风格的函数定义。上述函数定义的原型等效为 int f( int a[]){ ... }
。)
简而言之,该规则的存在主要是为了简化从 B 到 C 的转换,并允许程序员向 reader 发出信号,表明需要指向数组第一个元素的指针,而不仅仅是一个指向单个元素的指针(无需使用注释即可这样做)。
函数类型的参数也以类似的方式调整为指针。
void takeFuncPtr(void Func(void));
void takeFuncPtr(void (*Func)(void)); //compatible declaration
一个可能更深层次的问题是 "why do arrays decay to pointers at all in C"?。链接文档也提供了该问题的答案:
... These semantics represented an easy transition from B, and I experimented with them for some months. Problems became evident when I tried to extend the type notation, especially to add structured (record) types. Structures, it seemed, should map in an intuitive way onto memory in the machine, but in a structure containing an array, there was no good place to stash the pointer containing the base of the array, nor any convenient way to arrange that it be initialized. For example, the directory entries of early Unix systems might be described in C as
struct { int inumber; char name[14]; };
I wanted the structure not merely to characterize an abstract object but also to describe a collection of bits that might be read from a directory. Where could the compiler hide the pointer to name that the semantics demanded? Even if structures were thought of more abstractly, and the space for pointers could be hidden somehow, how could I handle the technical problem of properly initializing these pointers when allocating a complicated object, perhaps one that specified structures containing arrays containing structures to arbitrary depth? The solution constituted the crucial jump in the evolutionary chain between typeless BCPL and typed C. It eliminated the materialization of the pointer in storage, and instead caused the creation of the pointer when the array name is mentioned in an expression. The rule, which survives in today's C, is that values of array type are converted, when they appear in expressions, into pointers to the first of the objects making up the array.
...