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

例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

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


猜你喜欢

转载自blog.csdn.net/a3192048/article/details/80963841