jsp*_*p99 17 c arrays pointers function-pointers function
1) 误解:
每当用C语言声明数组时,都会隐式创建指向数组第一个元素的指针(数组的名称).(是吗?我不这么认为!)
这个页面的前两行(虽然我不确定信息的正确性)说明相同.
正如我们所看到的,当我们声明一个数组时,为数组的单元分配了一个连续的内存块,并且还分配了一个指针单元(适当类型)并初始化为指向数组的第一个单元.
但是,当我输出包含的地址在该指针和地址的该指针,就变成是相同的.所以,我认为毕竟不会创建指针.
任何人都可以详细解释编译器何时决定将数组名称转换为指针,为什么?
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).能够省略这*是一种便利,但不是一种巨大的便利.它可能是历史惯性和与阵列处理的一致性的组合.