数组是否与常量指针相同,还是存在其他差异?

时间:2015-07-28 14:47:30

标签: c arrays pointers

我在这里阅读了有关指针和数组等效性的各种文章和问题。几乎每篇文章都解释不同。我知道数组和指针是强相关的,而下面是我的指针和数组等效的实验,包括解释给定行为的注释(如果我在某处错了,请随时纠正我)。我的问题是:数组只是常量指针还是还有其他差异?

#include <stdio.h>
int main ()
{
  // declaring array this way in fact declares a pointer with name "a" which points to the first element in the array:
  int a[] = {0,1,2,3,4};

  // assigning an array to the pointer in fact assigns the address of the first array element to the pointer, those two are thus equivalents:
  int *pa1 = a;
  int *pa2 = &a[0];

  printf("########################\n");

  // REFERENCING: arrays can use pointer syntax (following are equivalents)
  printf("%p\n", (a+0)); // a+0 == 0+a
  printf("%p\n", a);
  printf("%p\n", &a[0]);
  printf("%p\n", &0[a]); // a+0 == 0+a

  printf("########################\n");

  // DEREFERENCING: arrays can use pointer syntax (following are equivalents)
  printf("%d\n", *(a+0)); // a+0 == 0+a
  printf("%d\n", *a);
  printf("%d\n", a[0]);
  printf("%d\n", 0[a]);   // a+0 == 0+a

  printf("########################\n");

  // REFERENCING: arrays can use pointer syntax (following are equivalents)
  printf("%p\n", (a+1));
  printf("%p\n", &a[1]);

  // REFERENCING: pointers can use array syntax (following are equivalents)
  printf("%p\n", (pa1+1));
  printf("%p\n", &pa1[1]);

  printf("########################\n");

  // DEREFERENCING: assigning values via pointers using pointer/array syntax (following are equivalents)
  *(pa1+1) = *(pa1+1) + 10;
  pa2[1] = pa2[1] + 10;

  // DEREFERENCING: arrays can use pointer syntax (following are equivalents)
  printf("%d\n", *(a+1));
  printf("%d\n", a[1]);
  printf("%d\n", 1[a]);

  // DEREFERENCING: assigning values via arrays using pointer/array syntax (following are equivalents)
  *(a+2) = *(a+2) + 10;
  a[2]   = a[2] + 10;

  // DEREFERENCING: pointers can use array syntax (following are equivalents)
  printf("%d\n", *(pa1+2));
  printf("%d\n", pa1[2]);
  printf("%d\n", 2[pa1]);

  printf("########################\n");

  // REFERENCING: those two pointers points to the same address
  printf("%p\n", pa1);
  printf("%p\n", pa2);

  // DEREFERENCING: those two pointers points to the same address
  printf("%d\n", *pa1);
  printf("%d\n", *pa2);

  printf("########################\n");

  // This is correct:
  pa1++;

  printf("%p\n", pa1);
  printf("%d\n", *pa1);

  printf("%p\n", pa2);
  printf("%d\n", *pa2);
  printf("########################\n");

  return 0;
}

我会说数组只是常量指针,唯一误导我的是当我尝试递增数组和常量指针时错误消息不同,这就是我的意思:

#include <stdio.h>
int main (){
  int var1=0;
  int * const ptr;
  int a[] = {0,1,2,3,4,5};

  // This gives an error:
  // error: increment of read-only variable ‘ptr’
  ptr++;

  // This gives an error:
  // error: lvalue required as increment operand
  a++;
return 0;
}

如果它们不一样,请你发布一些这种差异显而易见的情况吗?

2 个答案:

答案 0 :(得分:3)

阵列和指针是完全不同的动物。

在大多数情况下,表达式类型为&#34; N元素数组T&#34;将被转换(&#34;衰减&#34;)到类型为&#34;指向T&#34;的表达式,但数组对象本身不是指针。

此行为源于B语言,从中派生出C语言。在B中,数组对象指针,下标操作a[i]被解释为*(a + i)(偏移i个元素来自{{1}中存储的地址},取消引用结果)。

Ritchie保留了a语义,但摆脱了显式指针; C将数组表达式转换为指针表达式(除非数组表达式是一元*(a + i)&运算符的操作数)。

答案 1 :(得分:1)

您可以假装,数组与常量指针相同,但实际上它们是不同的类型。一个值得注意的差异是sizeof运算符的结果。例如:

#include <stdio.h>

int main(void)
{
    int a[] = {0, 1, 2, 3, 4, 5};
    int * const p = a;

    printf("sizeof(a) = %zu\n", sizeof(a));
    printf("sizeof(p) = %zu\n", sizeof(p));
}

对于前者,您将获得阵列的总大小。假设sizeof(int) = 4,它会打印24。 OTOH,对于后者,你只需得到int指针的大小。

此外,您不能将数组初始值设定项用于指针变量:

int * const p = {0, 1, 2, 3, 4, 5};
如果您使用-pedantic-errors标志设置,

会导致编译器错误,例如:

  

错误:标量初始值设定项中的多余元素

另一个重要的区别是在结构赋值期间,每个元素的数组都被复制

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct threeNumbers {
    int t[3];
} a = {{1, 2, 3}}, b = {{4, 5, 6}};

int main(void)
{
    a = b;
    a.t[0] = 100;

    printf("%d\n", a.t[0]); // prints 100
    printf("%d\n", b.t[0]); // prints 4
}

指针不是这种情况。具有const指针的结构不能彼此分配。对于非const指针成员,仅复制地址。如果指针设置为malloc,则可能导致内存泄漏。