类型int **和int [] []之间有什么区别?

时间:2011-12-06 04:12:23

标签: c++

如果以下分配有效:

int a[2] = {1,2};
int* b = a;

那么这有什么问题:

int a[2][2]={1,2,3,4};
int** b = a;

C ++提供的错误是无法将int[][]转换为int**。如果int[]int*相同,则两种类型之间有什么区别?

4 个答案:

答案 0 :(得分:31)

放轻松。它只是一个编译器错误。数组非常棘手。这是规则

  

数组的变量值衰减到此数组的地址

您的第一个代码段如下:

int a[2] = {1,2};

因此,根据规则,如果a位于赋值的右侧,则它会衰减元素零的地址,这就是它具有类型int *的原因。这会带你到

int *b = a;

在第二个片段中,你真正拥有的是一个数组数组。 (顺便说一句,为了明确我已经改变了你的代码。)

int a[2][2]={{1,2},{3,4}};

此时a将衰减到指向两个整数数组的指针!因此,如果您想将a分配给某些内容,则需要使用相同类型的内容。

int (*b)[2] = a; //Huh!

(这个语法对你来说可能有点令人惊叹,但只是想一想我们写的int *b[2];明白了吗?b是一个整数指针数组!不是我们真的想...)

你可以在这里停止阅读,但你也可以继续前进,因为我没有告诉你所有真相。我提到的规则有三个例外......

数组的值会衰减到元素零的地址如果

  1. 数组是sizeof
  2. 的操作数
  3. 数组是&
  4. 的操作数
  5. array是字符数组的文字字符串初始值设定项
  6. 让我们更详细地解释这些例外,并举例说明:

    int a[2];
    
    int *pi = a ; /* the same as pi = &a[0]; */
    
    printf("%d\n", sizeof(a)); /* size of the array, not of a pointer is printed! */
    
    int (*pi2)[2] = &a; /* address of the array itself is taken (not the address of a pointer) */
    

    最后

    char a[] = "Hello world ";
    

    此处不会复制指向“Hello world”的指针,但会复制整个字符串并指向此副本。

    确实有很多信息,很难一次理解所有内容,所以请慢慢来。我建议你阅读关于这个主题的K& R以及之后this优秀的书。

答案 1 :(得分:6)

这是很多东西,所以我会尝试尽可能清楚地解释它。

创建数组时,它会将元素连续存储在内存中,所以:

int arr[2] = { 1, 2 };

转换为:

arr:
+---+---+
| 1 | 2 |
+---+---+

指针指向内存中的对象,当通过一元*或通过[]取消引用时,它会访问该连续内存。所以

之后
int *ptr = arr;

ptr(或&ptr[0]如果您愿意)指向1框中的ptr + 1(或&ptr[1])指向框{ {1}}在。这是有道理的。

但是如果数组在内存中是连续的,那么数组的数组在内存中是连续的。所以:

2

在内存中看起来像这样:

int arr[2][2] = {{ 1, 2 }, { 3, 4 }};

这看起来很像我们的扁平阵列。

现在,让我们考虑如何在内存中指定指向arr: +---+---+---+---+ | 1 | 2 | 3 | 4 | +---+---+---+---+ 的指针:

int

ptr: +-------+-------+ | &sub1 | &sub2 | +-------+-------+ sub1: +---+---+ | 1 | 2 | +---+---+ sub2: +---+---+ | 3 | 4 | +---+---+ (或ptr)指向&ptr[0]sub1(或ptr + 1)指向&ptr[1]sub2sub1彼此之间没有实际关系,并且可以在内存中的任何位置,但因为它是指向的指针,所以2D数组的双重引用即使内存结构不兼容,也会被保留。

类型sub2的数组衰减到指向类型T的指针,但类型T的数组数组不会衰减到指向类型T的指针,它们会衰减指向T类型的数组。因此,当我的2D T衰减到指针时,它不是指向arr的指针,而是指向int的指针。此类型的全名是int [2],要使您的代码行工作,您需要使用

int (*)[2]

哪种类型正确。 int (*ptr)[2] = arr; 期望指向一个连续的内存数组,例如ptr确实 - arr(或ptr)指向&ptr[0]arr(或ptr + 1)指向&ptr[1]&arr[1]指向包含ptr[0]的框,1指向包含ptr[1]的框,因此3会产生1,ptr[0][0]收益2,等等。

为什么你需要知道这个? 2D指针看起来比它们值得更复杂 - 如果您使用ptr[0][1],则必须在循环中重复调用malloc,并对malloc执行相同操作。或者,你可以使用一些邪恶的*技巧来制作一个平面的,一维的内存分配 act 就像一个2D数组:

free

现在// x and y are the first and second dimensions of your array // so it would be declared T arr[x][y] if x and y were static int (*arr)[y] = malloc(x * y * sizeof(arr[0][0])); if(!arr) /* error */; 指向arry个对象的大小为int的数组的连续块。由于它指向的对象是一个数组,我们不需要int **对象的双指针间接,当你完成后,你可以通过一次调用释放它:

free(arr);

将此与使用int **的版本进行比较:

int **arr = malloc(x * sizeof(*arr));
if(!arr) /* error */;
for(size_t ii = 0; ii < x; ii++)
  {
    arr[ii] = malloc(y * sizeof(**arr));
    if(!arr[ii])
      {
        free(arr[ii]);
        free(arr);
      }
  }
// do work
for(size_t ii = 0; ii < x; ii++)
    free(arr[ii]);
free(arr);

上面的代码有内存泄漏。看看你是否能找到它。 (或者只使用带有那些看似棘手的指针到数组的版本。)

答案 2 :(得分:4)

着名的衰变约定:数组被视为指向数组第一个元素的指针。

int a[2] = {1,2};
int* b = a; //decay

但是衰变惯例不应该多次应用于同一个对象。

int a[2][2]={1,2,3,4};
int** b = a; //decay more than once

答案 3 :(得分:2)

int[]int*不同。在某些情况下,int[] 衰减int*

您可能应该特别阅读comp.lang.c FAQ,

以及Array and Pointers部分的其余部分。