如果是一个数组名或“转化”成一个指针的函数的名字吗? (C语言) [英] When is an array name or a function name 'converted' into a pointer ? (in C)

查看:227
本文介绍了如果是一个数组名或“转化”成一个指针的函数的名字吗? (C语言)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

1) 误区的:


  • 每当阵列是用C语言声明,一个指针数组的第一元素是<青霉>创建的隐式(所述阵列的名称)。 (是吗?我不这么认为!)


  • 此页面(虽然我不知道有关的信息的正确性)状态是一样的。


      

    正如我们所看到的,当我们声明数组,一个连续的内存块被分配给数组和指针细胞(适当类型的)的细胞也被分配和初始化为指向的第一个单元格数组。
      



  • 但是,当我输出的地址包含在的指针和地址的 的指针,它们变成是相同的。
    所以,我认为一个指针不是的创建的毕竟。


2)我拿起这从问题。


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

谁能给出一个详细的解释的编译器决定的转换的数组名成为一个指针,而为什么的?

PS:请解释用相同的功能的。此外,在环节,给出了一个例子,他说,对于一个函数 INT方(INT,INT),任何平方&安培;方 *平方 **方指的是同一个函数指针。你可以解释吗?

编辑:code段

  INT水果[10];
的printf(在不断的指针地址%P \\ N,水果);
的printf(常量指针地址是%P \\ N,&安培;水果);

输出:

 在不断的指针地址0xbff99ca8
常量指针地址是0xbff99ca8


解决方案

数组类型的前pression被隐式转换为指向数组对象的第一个元素的除非的是:


  • 的操作数一元&安培; 运营商;

  • 的sizeof的的操作;或

  • 一个字符串中使用初始化数组对象的初始化文字。

第三种情况的一个例子是:

 改编的char [6] =你好;

你好是一个数组前pression,类型的char [6] (5加1对'\\ 0'终止)。它不转换的地址;的充分6字节的值你好复制到数组对象改编

在另一方面,在此

 的char * PTR =你好;

数组前pression 你好衰变的指针到'H' ,那指针值是用来初始化指针对象 PTR 。 (它确实应该为const char * PTR ,但这是一个次要问题。)

函数类型(如函数名称)的前pression被隐式转换为函数指针的除非的是:


  • 单目&放的操作; 运营商;或

  • 的sizeof sizeof的函数名是非法的,而不是一个指针的大小)。

这就是它。

在这两种情况下,没有指针的对象的被创建。恩pression被转换成(衰变)一个指针值,也被称为一个地址。

请注意,这两个数组索引运算符 [] 和函数调用操作员()需要一个指针。在一个普通的函数调用,比如 FUNC(42),函数名 FUNC 衰减为指针,于─功能,然后在呼叫中使用。 (这种转换实际上并不需要在生成的$ C $下进行,只要在函数调用做正确的事。)

有关函数的规则有一些奇怪的后果。这位前pression FUNC 是,在大多数情况下,转化为函数指针 FUNC 。在&放大器; FUNC FUNC 不转换为一个指针,但&安培; 得到函数的地址,即一个指针值。在 * FUNC FUNC 隐式转换为指针,那么 * 解除引用它,得到函数本身,然后将其(在大多数情况下)转换为指针。在 **** FUNC ,这种情况反复。

(在C11标准的草案说,有一个为阵列的另一个异常,即当数组是新的 _Alignof 运算符的操作数。这是一个错误草案在最终公布的标准C11纠正; _Alignof 只能适用于带括号的类型名称,而不是一个前pression)

的阵列的地址与它的第一部件的地址:

  INT改编[10];
&安培;编曲; / *整个阵列的地址* /
&放大器;常用3 [0]; / *第一个元素的地址* /

是相同的内存地址,但它们是不同的类型。前者是整个数组对象的地址,类型为 INT(*)[10] (指向10数组 INT S);后者是类为int * 。这两种不兼容(不能合法地分配为int * 值到 INT(*)[10] 对象,例如),和指针运算的行为不同在他们身上。

有一个单独的规则,即数组或函数类型的声明的函数参数的调整的在编译时(不转换)的指针参数。例如:

 无效FUNC(INT ARR []);

完全等同于

 无效FUNC(INT * ARR);

这些规则(转换阵列前pressions和数组参数调整)相结合,创造关于C数组和指针之间的关系混淆了很大的。

comp.lang.c常见问题解答部分6很好地解释细节的出色的工作。

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

顺便说一句,的printf 调用你的例子是严格不正确的:

  INT水果[10];
的printf(在不断的指针地址%P \\ N,水果);
的printf(常量指针地址是%P \\ N,&安培;水果);

%P 格式需要键入无效* 的参数。如果类型的指针为int * INT(*)[10] 具有相同的重presentation为无效* 并以同样的方式传递参数,因为对于大多数实现的情况下,它可能工作,但它不能保证。你应该指针显式转换为无效*

  INT水果[10];
的printf(在不断的指针地址%P \\ N(无效*)水果);
的printf(常量指针地址是%P \\ N(无效*)及水果);

那么为什么做这样?问题是,数组在某种意义上是二等公民C.你不能按值传递数组作为函数调用的参数,并且不能返回它作为函数的结果。数组是有用的,需要能够在不同长度的阵列操作。为单独的的strlen 函数的char [1] 的char [2] 的char [3] ,等等(这些都是不同的类型)是不可能笨重。因此,而不是阵列通过指针访问和操作自己的元素,指针运算提供了一个方法来遍历这些元素。

如果一个数组前pression的没有的衰变的指针(在大多数情况下),那么就不会有多少,你可以用做结果。和C是从并不一定数组和指针之间的区别,甚至更早的语言(BCPL和B)的。

其他的语言能够处理数组作为一流的类型,但这样做需要额外的功能,那会不会是在C的精神,这仍然是一个比较低层次的语言。

我对治疗功能,这样的理由不太确定。有功能型没有的的这是真的,但语言可能需要一个功能(而不是一个指针到功能)作为一个函数调用preFIX,要求明确 * 运营商间接调用:(* funcptr)(ARG)。能够省略 * 是一个方便的,但不是巨大的。这可能是历史惯性和一致性阵列的处理的组合。

1) Misconception :

  • Whenever an array is declared in C language, a pointer to the first element of the array is created (the name of the array) implicitly. (Is it? I don't think so!)

  • The first two lines of this page (though I am not sure about the correctness of the information) state the same.

    As we have seen, when we declare an array, a contiguous block of memory is allocated for the cells of the array and a pointer cell (of the appropriate type) is also allocated and initialized to point to the first cell of the array.

  • But when I output the address contained in that pointer and the address of that pointer, they turn out to be the same. So, I think a pointer is not created after all.

2) I picked this up from this question.

  • In most cases array names are converted to pointers.

Can anyone give a detailed explanation of WHEN the compiler decides to convert an array name into a pointer, and WHY?

PS: Please explain the same with functions. Also in this link, an example was given, saying that for a function int square(int,int), any of the square, &square, *square, **square refers to the same function pointer. Can you explain?

Edit : Code snippet

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

Output :

Address IN constant pointer is 0xbff99ca8
Address OF constant pointer is 0xbff99ca8

解决方案

An expression of array type is implicitly converted to a pointer to the array object's first element unless it is:

  • The operand of the unary & operator;
  • The operand of sizeof; or
  • A string literal in an initializer used to initialize an array object.

An examples of the third case are:

char arr[6] = "hello";

"hello" is an array expression, of type char[6] (5 plus 1 for the '\0' terminator). It's not converted to an address; the full 6-byte value of of "hello" is copied into the array object arr.

On the other hand, in this:

char *ptr = "hello";

the array expression "hello" "decays" to a pointer to the 'h', and that pointer value is used to initialize the pointer object ptr. (It should really be const char *ptr, but that's a side issue.)

An expression of function type (such as a function name) is implicitly converted to a pointer to the function unless it is:

  • The operand of the unary & operator; or
  • The operand of sizeof (sizeof function_name is illegal, not the size of a pointer).

That's it.

In both cases, no pointer object is created. The expression is converted to ("decays" to) a pointer value, also known as an address.

Note that both the array indexing operator [] and the function call "operator" () require a pointer. In an ordinary function call like func(42), the function name func "decays" to a pointer-to-function, which is then used in the call. (This conversion needn't actually be performed in the generated code, as long as the function call does the right thing.)

The rule for functions has some odd consequences. The expression func is, in most contexts, converted to a pointer to the function func. In &func, func is not converted to a pointer, but & yields the function's address, i.e., a pointer value. In *func, func is implicitly converted to a pointer, then * dereferences it to yield the function itself, which is then (in most contexts) converted to a pointer. In ****func, this happens repeatedly.

(A draft of the C11 standard says that there's another exception for arrays, namely when the array is the operand of the new _Alignof operator. This is an error in the draft, corrected in the final published C11 standard; _Alignof can only be applied to a parenthesized type name, not to an expression.)

The address of an array and the address of its first member:

int arr[10];
&arr;    /* address of entire array */
&arr[0]; /* address of first element */

are the same memory address, but they're of different types. The former is the address of the entire array object, and is of type int(*)[10] (pointer to array of 10 ints); the latter is of type int*. The two types are not compatible (you can't legally assign an int* value to an int(*)[10] object, for example), and pointer arithmetic behaves differently on them.

There's a separate rule that says that a declared function parameter of array or function type is adjusted at compile time (not converted) to a pointer parameter. For example:

void func(int arr[]);

is exactly equivalent to

void func(int *arr);

These rules (conversion of array expressions and adjustment of array parameters) combine to create a great deal of confusion regarding the relationship between arrays and pointers in C.

Section 6 of the comp.lang.c FAQ does an excellent job of explaining the details.

The definitive source for this is the ISO C standard. N1570 (1.6 MB PDF) is the latest draft of the 2011 standard; these conversions are specified in section 6.3.2.1, paragraphs 3 (arrays) and 4 (functions). That draft has the erroneous reference to _Alignof, which doesn't actually apply.

Incidentally, the printf calls in your example are strictly incorrect:

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

The %p format requires an argument of type void*. If pointers of type int* and int(*)[10] have the same representation as void* and are passed as arguments in the same way, as is the case for most implementations, it's likely to work, but it's not guaranteed. You should explicitly convert the pointers to void*:

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

So why is it done this way? The problem is that arrays are in a sense second-class citizens in C. You can't pass an array by value as an argument in a function call, and you can't return it as a function result. For arrays to be useful, you need to be able to operate on arrays of different lengths. Separate strlen functions for char[1], for char[2], for char[3], and so forth (all of which are distinct types) would be impossibly unwieldy. So instead arrays are accessed and manipulated via pointers to their elements, with pointer arithmetic providing a way to traverse those elements.

If an array expression didn't decay to a pointer (in most contexts), then there wouldn't be much you could do with the result. And C was derived from earlier languages (BCPL and B) that didn't necessarily even distinguish between arrays and pointers.

Other languages are able to deal with arrays as first-class types but doing so requires extra features that wouldn't be "in the spirit of C", which continues to be a relatively low-level language.

I'm less sure about the rationale for treating functions this way. It's true that there are no values of function type, but the language could have required a function (rather than a pointer-to-function) as the prefix in a function call, requiring an explicit * operator for an indirect call: (*funcptr)(arg). Being able to omit the * is a convenience, but not a tremendous one. It's probably a combination of historical inertia and consistency with the treatment of arrays.

这篇关于如果是一个数组名或“转化”成一个指针的函数的名字吗? (C语言)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆