二维数组与指针的联系与区别

例1:
#include <iostream>
using namespace std;
int main()
{
       int array[2][3] = { { 1, 2, 3 },{ 4, 5, 6 } };
       int *ptr = (int *)array;
       int i = 0;
       while (i < 6)
       {
              cout << "  " << ptr[i];
              i++;
       }
       
       return 0;
}
输出:

分析:可看出array[0][2]和array[1][0]地址是连续的。

例2:
#include <iostream>
using namespace std;
int main()
{
       int array[2][3] = { { 1, 2, 3 },{ 4, 5, 6 }};
       int **ptr = (int **)malloc(2 * sizeof(int));
       if (ptr == NULL)
       {
              cout << "malloc error!" << endl;
              exit(1);
       }
       for (int i = 0; i < 2; i++)
       {
              ptr[i] = (int *)malloc(3 * sizeof(int));
              if (ptr[i] == NULL)
              {
                     cout << "malloc error!" << endl;
                     exit(1);
              }
              for (int j = 0; j < 3; j++)
              {
                     ptr[i][j] = array[i][j]; // 因为在堆上分配了内存空间
              }
       }
       for (int i = 0; i < 2; i++)
       {
              for (int j = 0; j < 3; j++)
              {
                     cout << "  " << ptr[i][j];
              }
              cout << endl;
              free(ptr[i]);
       }      
       free(ptr);
       return 0;
}
输出:


分析:

malloc分配的内存空间如上图所示。可看出ptr[0][2]和ptr[1][0]地址不一定是连续的。

例3
#include <iostream>
using namespace std;
int main()
{
       int array[2][3] = { { 1, 2, 3 },{ 4, 5, 6 }};
       int **ptr = (int**)array; /* array相当于指向一维数组的指针变量;int (*ptr)[3] = array;下面cout << "  " << ptr[i][j]; 就不会报错了。*/
       for (int i = 0; i < 2; i++)
       {
              for (int j = 0; j < 3; j++)
              {
                     //cout << "  " << ptr[i][j]; /* 报错! 原因见下面分析 */
                     
                     cout << "  " << *((int*)ptr + 3*i + j);
              }
              cout << endl;
              
       }      
       
       return 0;
}
输出:

分析:重点分析下//cout << "  " << ptr[i][j]这行代码。
 执行 int **ptr = (int**)array; 
ptr的内存布局如下:

array的内存布局如下:
 执行 int **ptr = (int**)array;  之后,ptr的值(起始地址)就为array的值,因为32位系统存放地址都是4字节,int也是4字节,所以*(ptr+0)就是取内存里面的数据,刚好值就为array[0][0]。因为ptr是指向指针的指针,所以*(ptr+0)为ptr[0][0]的地址,即&ptr[0][0]值为array[0][0],&ptr[0][1]为array[0][0]+sizeof(int), &ptr[0][2]为array[0][0]+2*sizeof(int) ; *(ptr+1)为ptr[1][0]的地址,即&ptr[1][0]值为array[0][1],&ptr[1][1]为array[1][0]+sizeof(int),&ptr[1][2]为array[1][0]+2*sizeof(int) ;
为什么 //cout << "  " << ptr[i][j];报错呢?以ptr[0][0]为例,&ptr[0][0]值为array[0][0],这里array[0][0]=1;而地址为1的内存里面的数据是不能访问的,所以报错。

补充知识:
如:
#include <iostream>
using namespace std;
int main()
{
       short int array[2][3] = { { 1, 2, 3 },{ 4, 5, 6 } };   
       short int **ptr = (short int **)array;
       cout << "&array = " << hex << &array << endl;
       cout << "ptr = " << hex << ptr << endl;
       cout << "ptr[0] = " << hex << ptr[0] << endl;
       cout << "ptr[1] = " << hex << ptr[1] << endl;
       cout << "&ptr[0][0] = " << hex << &ptr[0][0] << endl;
       cout << "&ptr[0][1] = " << hex << &ptr[0][1] << endl;
       cout << "&ptr[0][2] = " << hex << &ptr[0][2] << endl;
       cout << "&ptr[1][0] = " << hex << &ptr[1][0] << endl;
       cout << "&ptr[1][1] = " << hex << &ptr[1][1] << endl;
       cout << "&ptr[1][2] = " << hex << &ptr[1][2] << endl;
       
       return 0;
}
输出:

分析:
short int 是2个字节,而存放地址是4个字节。即array[0][0]占2个字节,ptr[0]也就是*ptr占4个字节。
因为X86平台是小端序(数据低位存放在低内存地址),所以二维数组内存array内存从低到高前8个字节为:
注:关于大小端网上资料很多,这里不做讲解。
ptr[0]取前4个字节,因为是小端序,所以ptr[0]=&ptr[0][0] =0x00020001,
同理ptr[1]=&ptr[1][0] = 0x00040003;(这里"="理解为等于号)

例4:
#include <iostream>
using namespace std;
int main()
{
       int array[2][3] = { { 1, 2, 3 },{ 4, 5, 6 } };
       int (*ptr)[3] = array;
       for (int i = 0; i < 2; i++)
       {
              for (int j = 0; j < 3; j++)
              {
                     cout << "  " <<  ptr[i][j]; /* 因为ptr是指向一维数组的指针变量,所以完全等价: cout << "  " <<  array[i][j]; */
                     cout << "  " <<  *((int*)ptr + 3 * i + j); // 相当于:cout << "  " << *((int*)array + 3 * i + j);
              }
              cout << endl;
       }
              
       return 0;
}
输出:

例5:
#include <iostream>
using namespace std;
int main()
{
       int array[2][3] = { { 1, 2, 3 },{ 4, 5, 6 } };  
       int **ptr = (int **)array;
       cout << "array = " << hex << array << endl;
       cout << "array[0] = " << hex << array[0] << endl;
       cout << "ptr = " << hex << ptr << endl;
       cout << "array[0][0] = " << hex << array[0][0] << endl;
       for (int i = 0; i < 2; i++)
       {
              *(ptr + i) = array[i]; //???
              cout << "array[0][0] = " << hex << array[0][0] << endl;
              cout << "array[0][1] = " << hex << array[0][1] << endl;
       }
       return 0;
}
输出:

分析:
注意:array[0]和ptr[0]意义完全不同。
array[0]是0行0列地址,即和array的值一样。ptr[0]即*ptr,为地址为ptr值的内存里面存的数据。这程序里刚好为array[0][0]的值,执行*(ptr + i) = array[i];之后,就把ptr值的内存里面存的数据修改为array[i]的值,即array[0][0]也修改为了array[i]的值。

补充一下:
如:
#include <iostream>
using namespace std;
int main()
{
       short array[2][3] = { { 1, 2, 3 },{ 4, 5, 6 } };       
       short **ptr = (short int **)array;
       cout << "array = " << hex << array << endl;
       cout << "array[0] = " << hex << array[0] << endl;
       cout << "ptr = " << hex << ptr << endl;
       cout << "array[0][0] = " << hex << array[0][0] << endl;
       for (int i = 0; i < 2; i++)
       {
              *(ptr + i) = array[i]; //???
              cout << "array[0][0] = " << hex << array[0][0] << endl;
              cout << "array[0][1] = " << hex << array[0][1] << endl;
              cout << "array[0][2] = " << hex << array[0][2] << endl;              
              cout << "array[1][0] = " << hex << array[1][0] << endl;
       }
       return 0;
}
输出:

分析:
有了上面的分析这就很好理解了。(注意X86平台是小端)
如果是大端平台,执行 *(ptr + i) = array[i];之后array[0][0]=0x004E,array[0][1]=0xfdbc

全文总结:最重要一点要明白: 二维数组每个元素内存中是连续存放的,而指向指针的指针变量本质上还是指针变量,即存放地址的变量而已。


原文地址:https://www.cnblogs.com/a3192048/p/12241332.html