C++多维数组和指向表的指针

Mic*_*cki 0 c++ pointers function multidimensional-array dynamically-generated

这就是事情.我可以完全理解多维数组的概念(让我们考虑2D一段时间)由指针指向数组到指针等等......

我们做这样的事情:

// we can use dynamically defined size n and m
int n = 3, m = 5 ;
int **T = new int *[n];
for (int i = 0 ; i < n ; ++i)
    T[i] = new int[m];
Run Code Online (Sandbox Code Playgroud)

我们得到的是:(检查我是否在这里)

  • 3个内存块,5个整数,放在内存中的某个位置
  • 一个额外的内存块,其大小与int的块数(行数)相同.这个块是指向那些int行的指针数组(对于像int这样的指针通常是4个字节).
  • 我们最感兴趣的是 - 类型为(**T)的T - 指向指针的指针.这正是指针数组的指针,因为在C++中,数组实际上是指向内存块的指针,因此t []或t [0]表示*t,t [x]表示*(t + X).

现在问题是当我们这样做时:

int n = 3, m = 5 ;
int T[n][m] ;
Run Code Online (Sandbox Code Playgroud)

我们得到的并不是我以前展示过的东西.我们很奇怪.什么是T?当打印T时,我们得到与T [0]相同的值.看起来我们保留了一个大小为n*m的整数块,而没有额外的行指针数组.

我的问题是:编译器是否记得数组的维度以及行数和列数?当要求T [i] [j]它实际上要求*(T + i*n + j)所以这个n存储在某个地方?问题是当我们试图将这个东西(T)传递给一个函数时.我不知道为什么,但如果n和m是常量,它可以传递T作为指向这个数组的指针,就像在这个程序中一样:

#include <stdio.h>
const int n = 3, m = 4 ; // this is constant!
void add_5(int K[][m])
{
    for (int i = 0 ; i < n ; ++i)
        for (int j = 0 ; j < m ; j++)
            K[i][j] += 5 ;
}
int main()
{
    // n x m array the most straight forward method
    int T[n][m] ;
    for (int i = 0 ; i < n ; ++i)
        for (int j = 0 ; j < m ; ++j)
            T[i][j] = i*m + j ;

    for (int i = 0 ; i < n ; ++i)
    {
        for (int j = 0 ; j < m ; j++)
            printf("%d ",T[i][j]) ;
        printf("\n") ;
    }
    printf("\n") ;

    // adding 5 to all cells
    add_5(T) ;
    printf("it worked!!\n") ;

    for (int i = 0 ; i < n ; ++i)
    {
        for (int j = 0 ; j < m ; j++)
            printf("%d ",T[i][j]) ;
        printf("\n") ;
    }

    int ss ;
    scanf("%d",&ss) ;
}
Run Code Online (Sandbox Code Playgroud)

但如果n和m不是常数,我们就不能.所以我需要的是将动态创建的多维数组指针传递给函数,而无需为此手动分配内存.这该怎么做?

Jos*_*eld 5

在C++中,数组实际上是指向内存块的指针

绝对不.数组完全独立于指针.您可能会遇到这种混淆的原因是因为标准转换称为数组到指针的转换.考虑:

int arr[10];
Run Code Online (Sandbox Code Playgroud)

变量arr表示一个数组.它根本不是指针.恰巧在许多情况下,数组的名称将转换为指向其第一个元素的指针.也就是说,转换将其转换为int*.

int T[n][m] ;
Run Code Online (Sandbox Code Playgroud)

在这种情况下,T是一个" s 数组的n数组m int".您提到打印两者TT[0]给出相同的结果,这是由于数组到指针的转换.

  1. 表达式T可以转换为指向第一个元素的指针; 也就是说int (*)[m],因为第一个元素T本身就是一个带m元素的数组.

  2. 表达式T[0]可以转换为指向第一个子数组的第一个元素的指针.所以你得到一个指向T[0][0]类型元素的指针int*.

由于数组在内存中的布局方式,这些指针保持相同的地址.数组开始的地址与该数组的第一个元素的地址相同.但是,指针的行为方式不同.如果增加由此产生的指针T,则移动到下一个子阵列.如果增加由此产生的指针T[0],则移动到下一个int.

与动态分配的"2D阵列"相比,它可以帮助您查看2D阵列在内存中的布局图.3乘3 2D阵列看起来像这样:

  0,0   0,1   0,2   1,0   1,1   1,2   2,0   2,1   2,2
???????????????????????????????????????????????????????
? int ? int ? int ? int ? int ? int ? int ? int ? int ?
???????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

而如果您动态分配3乘3"2D阵列":

???????
?     ? // The int**
???????
   ?
   ?
???????????????????
?     ?     ?     ??????????????????????????????  // An array of int*
???????????????????                            ?
   ?     ?????????????????                     ?
   ?                     ?                     ?
???????????????????   ???????????????????   ???????????????????
? int ? int ? int ?   ? int ? int ? int ?   ? int ? int ? int ? // Arrays of ints
???????????????????   ???????????????????   ???????????????????
  0,0   0,1   0,2       1,0   1,1   1,2       2,0   2,1   2,2
Run Code Online (Sandbox Code Playgroud)

编译器是否记得数组的维度以及行数和列数?

是的,如果您有一个包含数组类型的变量,则该数组的大小是该类型的一部分.编译器始终知道变量的类型.

当要求T [i] [j]它实际上要求*(T + i*n + j)所以这个n存储在某个地方?

表达式T[i][j]相当于*(*(T + i) + j).让我们理解这是做什么的.首先,进行数组到指针的转换T,给出一个int (*)[m].然后我们添加i到此处以指向i第n个子阵列.然后取消引用以获得子阵列.接下来,这个子阵列也经历了数组到指针的转换,给出了一个int*.然后添加j到此以获取指向该子数组中的j第th个int对象的指针.这是解除引用int.

问题是当我们试图将这个东西(T)传递给一个函数时.我不知道为什么,但如果n和m是常量,它可以传递T作为指向这个数组的指针来运行

这实际上是一个谎言.您没有将2D数组传递给函数.实际上,没有数组类型参数这样的东西.你的论点int K[][m]实际上相当于int (*K)[m].也就是说,所有数组类型参数都转换为指针.

因此,当您调用此函数时add_5(T),您没有传递表示的数组T.T实际上正在进行数组到指针的转换,为你提供一个int (*)[m]这个指针传递给函数.