何时数组名称或函数名称"转换"为指针?(在C中)

jsp*_*p99 17 c arrays pointers function-pointers function

1) 误解:

  • 每当用C语言声明数组时,都会隐式创建指向数组第一个元素的指针(数组的名称).(是吗?我不这么认为!)

  • 这个页面的前两行(虽然我不确定信息的正确性)说明相同.

    正如我们所看到的,当我们声明一个数组时,为数组的单元分配了一个连续的内存块,并且还分配了一个指针单元(适当类型)并初始化为指向数组的第一个单元.

  • 但是,当我输出包含的地址该指针和地址该指针,就变成是相同的.所以,我认为毕竟不会创建指针.

2)我从这个问题中选了这个.

  • 在大多数情况下,数组名称将转换为指针.

任何人都可以详细解释编译器何时决定数组名称转换为指针,为什么

PS:请解释一下功能.此外,在这个环节中,已经给出,说是一个函数int square(int,int),任意 square,&square,*square,**square是指同一个函数指针.你可以解释吗?

编辑:代码段

int fruits[10];
printf("Address IN constant pointer is %p\n",  fruits);
printf("Address OF constant pointer is %p\n", &fruits); 
Run Code Online (Sandbox Code Playgroud)

输出:

Address IN constant pointer is 0xbff99ca8
Address OF constant pointer is 0xbff99ca8
Run Code Online (Sandbox Code Playgroud)

Kei*_*son 33

数组类型的表达式被隐式转换为指向数组对象的第一个元素的指针,除非它是:

  • 一元运算&符的操作数;
  • 的操作数sizeof; 要么
  • 初始值设定项中的字符串文字,用于初始化数组对象.

第三种情况的例子是:

char arr[6] = "hello";
Run Code Online (Sandbox Code Playgroud)

"hello"是一个数组表达式,类型char[6](5加1表示'\0'终结符).它没有转换为地址; 将完整的6字节值"hello"复制到数组对象中arr.

另一方面,在这:

char *ptr = "hello";
Run Code Online (Sandbox Code Playgroud)

数组表达式"hello""衰减"到指向的指针'h',该指针值用于初始化指针对象ptr.(它应该是const char *ptr,但这是一个副作用.)

函数类型的表达式(例如函数名称)被隐式转换为指向函数的指针,除非它是:

  • 一元运算&符的操作数; 要么
  • 的操作数sizeof(sizeof function_name是非法的,而不是一个指针的大小).

而已.

在这两种情况下,都不会创建指针对象.表达式转换为("衰减")指针值,也称为地址.

请注意,数组索引操作符[]和函数调用"operator" ()都需要指针.在普通的函数调用中func(42),函数名称func"衰减"到指向函数的指针,然后在调用中使用.(只要函数调用做正确的事情,这个转换实际上不需要在生成的代码中执行.)

功能规则有一些奇怪的后果.func在大多数情况下,表达式转换为指向函数的指针func.In &func,func不转换为指针,但&产生函数的地址,即指针值.In *func,func隐式转换为指针,然后*取消引用它以产生函数本身,然后(在大多数情况下)转换为指针.在****func,这反复发生.

(C11标准的草案说数组有另一个例外,即当数组是new _Alignof运算符的操作数时.这是草案中的错误,在最终发布的C11标准中得到纠正; _Alignof只能应用于括号中类型名称,而不是表达式.)

数组的地址和第一个成员的地址:

int arr[10];
&arr;    /* address of entire array */
&arr[0]; /* address of first element */
Run Code Online (Sandbox Code Playgroud)

是相同的内存地址,但它们是不同的类型.前者是整个数组对象的地址,属于类型int(*)[10](指向10 int秒数组的指针); 后者属于类型int*.这两种类型不兼容(例如,您无法合法int*地为int(*)[10]对象赋值),并且指针算法对它们的行为也不同.

有一个单独的规则,说明在编译时(未转换)将指定的数组或函数类型的函数参数调整为指针参数.例如:

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

完全等同于

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

这些规则(数组表达式的转换和数组参数的调整)相结合,对C中数组和指针之间的关系产生了很大的混淆.

comp.lang.c FAQ的第6节非常出色地解释了细节.

最终的来源是ISO C标准. N1570(1.6 MB PDF)是2011年标准的最新草案; 这些转换在6.3.2.1节,第3节(数组)和第4节(函数)中规定.该草案有错误的引用_Alignof,实际上并不适用.

顺便提一下,printf您示例中的调用严格不正确:

int fruits[10];
printf("Address IN constant pointer is %p\n",fruits);
printf("Address OF constant pointer is %p\n",&fruits); 
Run Code Online (Sandbox Code Playgroud)

%p格式需要类型的参数void*.如果类型的指针int*int(*)[10]具有相同的表示void*并以相同的方式作为参数传递,就像大多数实现的情况一样,它可能会起作用,但不能保证.你应该明确地将指针转换为void*:

int fruits[10];
printf("Address IN constant pointer is %p\n", (void*)fruits);
printf("Address OF constant pointer is %p\n", (void*)&fruits);
Run Code Online (Sandbox Code Playgroud)

那么为什么这样做呢?问题是数组在某种意义上是C语言中的二等公民.您不能通过值将数组作为函数调用中的参数传递,并且您不能将其作为函数结果返回.要使数组有用,您需要能够对不同长度的数组进行操作.strlenfor char[1],for char[2],for char[3]等等(所有这些都是不同类型)的单独函数将是不可能的笨拙.因此,数组通过指向其元素的指针进行访问和操作,指针算法提供了遍历这些元素的方法.

如果数组表达式没有衰减到指针(在大多数情况下),那么你可以用结果做很多事情.C来自早期语言(BCPL和B),它们甚至不一定能区分数组和指针.

其他语言能够将数组作为一流类型处理,但这样做需要额外的功能,这些功能不会"本着C语言",这仍然是一种相对低级的语言.

我不太确定以这种方式处理函数的理由.确实没有函数类型的,但语言可能需要一个函数(而不是指向函数的指针)作为函数调用中的前缀,需要一个显式*运算符来进行间接调用:(*funcptr)(arg).能够省略这*是一种便利,但不是一种巨大的便利.它可能是历史惯性和与阵列处理的一致性的组合.