在C语言中,是数组指针或用作指针? [英] In C, are arrays pointers or used as pointers?

查看:116
本文介绍了在C语言中,是数组指针或用作指针?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的理解是,数组被简单地定指针值的序列,而当你宣布C中的数组,你声明指针和它所指向的顺序分配空间。

但是,这混淆了我:以下code:

 字符Y [20];
字符* Z = Y;的printf(Y大小%lu个\\ N的sizeof(Y));
的printf(y是%P \\ N,Y);
的printf(Z大小为%lu \\ n的sizeof(Z));
的printf(z是%P \\ N,Z);

在与苹果的GCC编译给出了以下结果:

  y值是20
y是0x​​7fff5fbff930
ž大小为8
z是0x7fff5fbff930

(我的机器是64位的,指针是8个字节长)。

如果Y是一个常量指针,为什么它有一个大小为20,如价值观它所指向的顺序?是变量名Y在编译时,只要是通过appropiate内存地址取代?是数组,然后,在C某种语法糖,这只是编译时转换为指针的东西?


解决方案

下面是从C标准的确切语言(的n1256 ):


6.3.2.1左值,数组和功能代号的结果
...结果
3除非它是的sizeof 运营商或一元运营商的操作数或者是一个字符串字面来初始化数组,即具有类型''转换为类型的前pression''指针的键入的'中的键入的阵'的前$​​ p $ pssion 那指向数组对象的初始元素,不是左值。如果数组对象有注册存储类,这种行为是未定义。

这里要记住的重要一点是,之间是有区别的的对象的(在C而言,这意味着什么,占用内存)和前pression 用来指该对象

当你声明一个数组,如

  int类型的[10];

对象的通过的前pression指定 A 是一个数组(即连续的块内存大到足以容纳10 INT 值),而前pression类型的一个是10个元素的数组 INT ,或 INT [10] 。如果的前pression A 出现在上下文不是作为操作数以外的的sizeof &安培; 运营商,那么它的类型被隐式转换为为int * ,其值是地址第一元件的。

的sizeof 运营商的情况下,如果操作数是类型的前pression T [N] ,那么结果是字节数组对象的数量,而不是一个指向对象: N * sizeof的牛逼

&放大器的情况下; 运算符,值是数组,这是相同的数组的第一元素的地址的地址,但恩pression的的键入的不同的是:鉴于声明 T一[N]; ,前$ p $的类型pssion &放大器;一个 T(*)[N] ,或指向T的N个元素的数组的的相同 A &放大器;一个[0] (该地址该阵列是相同的阵列中的第一个元素的地址),但在类型方面的差异。例如,给定的code

  int类型的[10];
INT * P = A;
INT(* AP)[10] =&放大器;一个;的printf(P =%P,AP =%P \\ N(无效*)P,(无效*)AP);
p ++;
AP ++;
的printf(P =%P,AP =%P \\ N(无效*)P,(无效*)AP);

您将看到的顺序输出

  P = 0xbff11e58,AP = 0xbff11e58
P = 0xbff11e5c,AP = 0xbff11e80

IOW,推进 P 补充的sizeof INT (4)为原始值,而推进 AP 补充 10 * sizeof的INT (40)。

更多的标准语言:


6.5.2.1数组下标的搜索结果
限制的搜索结果
1一个除权pressions应该是一个类型的'指针对象的键入的'',在其他前pression应具有整数类型,结果类型为''的键入的''。搜索结果
语义的搜索结果
2一个后缀前pression随后在方括号中前pression [] 是一个数组对象的元素的下标名称。下标运算符 [] 的定义是: E1 [E2] ( *((E1)+(E2)))。因为适用于二进制 + 运营商转换规则,如果 E1 是一个数组对象(等同于一个指针数组对象的初始元素)和 E2 是一个整数, E1 [E2] 指定的 E2 E1 (从零开始计数)。

因此​​,当你下标数组前pression,什么引擎盖下发生的是,从阵列中的第一个元件的地址偏移被计算并且该结果被取消引用。这位前pression

  A [I] = 10;

等同于

  *((A)+(I))= 10;

这相当于

  *((我)+(A))= 10;

这相当于

  I [A] = 10;

是,阵列使用C下标是可交换的;对上帝的爱,从来没有在生产code做到这一点。

由于指针操作来定义的数组下标,就可以申请下标运算符指针类型的前pressions以及数组类型:

 为int * p =的malloc(sizeof的* P * 10);
INT I;
对于(I = 0; I&小于10;我+ +)
  P [I] = some_initial_value();

下面是一个方便的表来记录一些概念:


声明:T了[N];防爆pression类型转换为数值
---------- ---- ------------ -----
         第一个元素在一个T [N] T *地址;
                                        相同的文字与A [0]
        &为T(*)[N]的数组地址;值是相同的
                                        如上述,但类型是不同的
  sizeof的数组中包含的一个字节为size_t数
                                        对象(N * sizeof的T)
        *在一件T值[0]
      在[I]一[I]的T值
     &A [I]的[I] T *地址声明:T A [N] [M]。防爆pression类型转换为数值
---------- ---- ------------ -----
          第一子阵列的一个T [N] [M] T(*)[M]。地址(一个[0])
         &为T(*)[N]的数组[M]的地址(相同的值
                                             以上,但不同类型的)
   sizeof的包含在字节为size_t数
                                             数组对象(N * M * sizeof的T)
         *的T [M] T *值的[0],这是地址
                                             第一子阵列的第一元件的
                                             (同与一个[0] [0])
       一个[I] T [M] T *的值一个由[i],其是地址
                                             第i子阵列的第一个元素的
      &第i子阵列的[I] T(*)[M]的地址;相同的值
                                             以上,但不同类型的
sizeof的包含在第i子阵列一个由[i]为size_t字节数
                                             对象(M * sizeof的T)
      *第i个的第一个元素的[I]的T值
                                             子阵列(一个由[i] [0])
    一个[I] [J] T,在[I] [j]的值
   &A [I] [J]。[I] [J]。T *地址声明:T A [N] [M] [O];防爆pression类型转换为
---------- ---- -----------
         一个T [N] [M] [O] T(*)[M]。[O]
        &一个T(*)[N] [M] [O]
        *一个T [M] [O] T(*)[O]
      一个[I] T [M] [O] T(*)[O]
     &A [I] T(*)[M]。[O]
     * A [I] T [O] T *
   一个由[i] [j]的T [O] T *
  &A [I] [J] T(*)[O]
  * A [I] [J] T ...
一个由[i] [j]的[K] T ...

从这里开始,对更高维数组的模式应该是清楚的。

因此​​,简言之:数组不是指针。在大多数情况下,数组的前pressions 的转换为指针类型。

My understanding was that arrays were simply constant pointers to a sequence of values, and when you declared an array in C, you were declaring a pointer and allocating space for the sequence it points to.

But this confuses me: the following code:

char y[20];
char *z = y;

printf("y size is %lu\n", sizeof(y));
printf("y is %p\n", y);
printf("z size is %lu\n", sizeof(z));
printf("z is %p\n", z);

when compiled with Apple GCC gives the following result:

y size is 20
y is 0x7fff5fbff930
z size is 8
z is 0x7fff5fbff930

(my machine is 64 bit, pointers are 8 bytes long).

If 'y' is a constant pointer, why does it have a size of 20, like the sequence of values it points to? Is the variable name 'y' replaced by a memory address during compilation time whenever it is appropiate? Are arrays, then, some sort of syntactic sugar in C that is just translated to pointer stuff when compiled?

解决方案

Here's the exact language from the C standard (n1256):

6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.

The important thing to remember here is that there is a difference between an object (in C terms, meaning something that takes up memory) and the expression used to refer to that object.

When you declare an array such as

int a[10];

the object designated by the expression a is an array (i.e., a contiguous block of memory large enough to hold 10 int values), and the type of the expression a is "10-element array of int", or int [10]. If the expression a appears in a context other than as the operand of the sizeof or & operators, then its type is implicitly converted to int *, and its value is the address of the first element.

In the case of the sizeof operator, if the operand is an expression of type T [N], then the result is the number of bytes in the array object, not in a pointer to that object: N * sizeof T.

In the case of the & operator, the value is the address of the array, which is the same as the address of the first element of the array, but the type of the expression is different: given the declaration T a[N];, the type of the expression &a is T (*)[N], or pointer to N-element array of T. The value is the same as a or &a[0] (the address of the array is the same as the address of the first element in the array), but the difference in types matters. For example, given the code

int a[10];
int *p = a;
int (*ap)[10] = &a;

printf("p = %p, ap = %p\n", (void *) p, (void *) ap);
p++;
ap++;
printf("p = %p, ap = %p\n", (void *) p, (void *) ap);

you'll see output on the order of

p = 0xbff11e58, ap = 0xbff11e58
p = 0xbff11e5c, ap = 0xbff11e80

IOW, advancing p adds sizeof int (4) to the original value, whereas advancing ap adds 10 * sizeof int (40).

More standard language:

6.5.2.1 Array subscripting

Constraints

1 One of the expressions shall have type ‘‘pointer to object type’’, the other expression shall have integer type, and the result has type ‘‘type’’.

Semantics

2 A postfix expression followed by an expression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th element of E1 (counting from zero).

Thus, when you subscript an array expression, what happens under the hood is that the offset from the address of the first element in the array is computed and the result is dereferenced. The expression

a[i] = 10;

is equivalent to

*((a)+(i)) = 10;

which is equivalent to

*((i)+(a)) = 10;

which is equivalent to

 i[a] = 10;

Yes, array subscripting in C is commutative; for the love of God, never do this in production code.

Since array subscripting is defined in terms of pointer operations, you can apply the subscript operator to expressions of pointer type as well as array type:

int *p = malloc(sizeof *p * 10);
int i;
for (i = 0; i < 10; i++)
  p[i] = some_initial_value(); 

Here's a handy table to remember some of these concepts:

Declaration: T a[N];

Expression    Type    Converts to     Value
----------    ----    ------------    -----
         a    T [N]   T *             Address of the first element in a;
                                        identical to writing &a[0]
        &a    T (*)[N]                Address of the array; value is the same
                                        as above, but the type is different
  sizeof a    size_t                  Number of bytes contained in the array
                                        object (N * sizeof T)
        *a    T                       Value at a[0]
      a[i]    T                       Value at a[i]
     &a[i]    T *                     Address of a[i] 

Declaration: T a[N][M];

Expression     Type        Converts to     Value
----------     ----        ------------    -----
          a    T [N][M]    T (*)[M]        Address of the first subarray (&a[0])
         &a    T (*)[N][M]                 Address of the array (same value as
                                             above, but different type)
   sizeof a    size_t                      Number of bytes contained in the
                                             array object (N * M * sizeof T)
         *a    T [M]      T *              Value of a[0], which is the address
                                             of the first element of the first subarray
                                             (same as &a[0][0])
       a[i]    T [M]      T *              Value of a[i], which is the address
                                             of the first element of the i'th subarray
      &a[i]    T (*)[M]                    Address of the i-th subarray; same value as
                                             above, but different type
sizeof a[i]    size_t                      Number of bytes contained in the i'th subarray
                                             object (M * sizeof T)
      *a[i]    T                           Value of the first element of the i'th 
                                             subarray (a[i][0])
    a[i][j]    T                           Value at a[i][j]
   &a[i][j]    T *                         Address of a[i][j]

Declaration: T a[N][M][O];

Expression        Type             Converts to
----------        ----             -----------
         a        T [N][M][O]      T (*)[M][O]
        &a        T (*)[N][M][O]
        *a        T [M][O]         T (*)[O]
      a[i]        T [M][O]         T (*)[O]
     &a[i]        T (*)[M][O]
     *a[i]        T [O]            T *
   a[i][j]        T [O]            T *
  &a[i][j]        T (*)[O]
  *a[i][j]        T 
a[i][j][k]        T

From here, the pattern for higher-dimensional arrays should be clear.

So, in summary: arrays are not pointers. In most contexts, array expressions are converted to pointer types.

这篇关于在C语言中,是数组指针或用作指针?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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