当p被声明为int(*)[size]并分配给数组时,是什么?

时间:2017-11-21 03:23:18

标签: c arrays pointers dereference

代码:

int arr[5] = {1,2,3,4,5};
int (*p)[5] = &arr;
printf("p:%p\n",p);
printf("*p:%p\n",*p);

结果:p = *p = arr = 0x7ffee517c830它们都是数组的地址 enter image description here

使用p访问arr [i]的正确方法是*(*p+i)

指针p的类型为int(*)[5],因此p指向类型为int [5]的数组。但我们不能说p指向arr的一个看不见的外壳,p毕竟是一个变量。它存储arr的地址,arr[0]也是arr的第一个元素*p的地址。

我认为1会让我arr,这是p的第一个元素。

取消引用操作意味着将arr中的值作为地址,并从该地址获取值。对? 因此,p存储0x7ffee517c830的地址,此处为1**p存储在此地址中。 1不是非法的吗?第一次取消引用会向我们提供1,第二次取消引用会使用P5.Graphics作为非法的地址。

我缺少什么?

4 个答案:

答案 0 :(得分:5)

*p的结果是数组类型的左值表达式。在您现在可以想到的任何表达式中,使用(*p) 与使用arr完全相同

例如:

  • &*p表示&arr
  • **p表示*arr(这是合法的)。
  • (*p)[i]表示arr[i]
  • sizeof *p表示sizeof arr

阵列在这方面并不特别。您可以使用int x; int *q = &x;看到相同的现象。现在*qx具有完全相同的含义。

关于你的最后一段,我认为通过将指针想象成美化的整数,你会让自己感到困惑。有些人用这种方式教指针,但是IMO并不是一种好的教学技巧,因为它会导致你现在感到困惑。

如果您取消引用int(*)[5],则会获得int[5],而这就是它的全部内容。数据类型在解除引用时很重要。谈论“解除引用0x7ffee517c830”是没有意义的。同样,这并不是数组所特有的;如果您取消引用char ***,则会获得char **等。

在本讨论中数组“不同”的唯一方法是,如果您尝试对它们进行算术运算,或输出它们等,会发生什么情况。例如,如果您提供int[5]作为printf参数,隐含转换为int *指向这5个整数中的第一个。将*运算符应用于int[5]时也会发生此转换,这就是为什么你会得到int的原因。

答案 1 :(得分:2)

p被声明为'指向int [5]'的指针。

arr被声明为'int [5]`

所以初始化程序p = &arr;并不是那么奇怪。如果你用int[5]取代任何原始类型,你就不会睁大眼睛。

*p是arr的另一个句柄。所以(* p)[0] = 1。

这真的只出现在奇怪的情况下。使用下标运算符取消引用指向数组的指针是最自然的。这是一个人为的例子,我想传递一个表作为参数。

#include <stdio.h>

int print_row_range(int (*tab) [2], int first, int last)
{
  int i;
  for(i=first; i<= last; i++)
  {
    printf("{%d, %d}\n", tab[i][0], tab[i][1]);
  }
}

int main(int argc, char *argv[])
{
  int arr[3][2] = {{1,2},{3,4},{5,6}};
  print_row_range(arr,1,2);
}

此示例将表视为行数组。

答案 2 :(得分:0)

解除引用不会为您提供。它为您提供了一个对象,如果可以转换为它,可以将其用作其类型的值。

*p相同的

arr是5个整数数组的对象,因此如果您想从数组中获取整数,您必须再取消引用,例如(*p)[3]

考虑一个更大的例子:

int arr[5][5];
int (*p)[5] = arr;

现在你得到arr[0] *p,它本身是一个5的数组。差别就是这样:

*( p+1) == arr[1];
*(*p+1) == arr[0][1];
  ^              ^^^

明白了吗?

答案 3 :(得分:0)

一个用例是能够使用malloc分配只有一个malloc的2D(或更多)数组指针:

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

static int (*foo(size_t n))[42] {
  return malloc(sizeof *foo(0) * n);
  // return malloc(sizeof(int [n][42]); works too
}

int main(void) {
  size_t n = 42;
  int (*p)[42] = foo(n);
  if (!p) {
    return 1;
  }

  printf("p:");
  int accu = 0;
  for (size_t i = 0; i < n; i++) {
    for (size_t j = 0; j < sizeof *p / sizeof **p; j++) {
      p[i][j] = accu++;
      printf(" %d", p[i][j]);
    }
  }
  printf("\n");
  free(p);
}

我觉得这很有趣。

VLA还有一个:

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

static void *foo(size_t elem, size_t n, size_t m) {
  return malloc(elem * n * m);
}

int main(void) {
  size_t n = 42;
  int (*p)[n] = foo(sizeof **p, n, n);
  if (!p) {
    return 1;
  }

  printf("p:");
  int accu = 0;
  for (size_t i = 0; i < n; i++) {
    for (size_t j = 0; j < sizeof *p / sizeof **p; j++) {
      p[i][j] = accu++;
      printf(" %d", p[i][j]);
    }
  }
  printf("\n");
  free(p);
}