C语言--数组指针、数组指针与二维数组的关系

一、数组指针

        数组指针本质是一个指针类型的变量,指向一个二维数组。

        格式:

                  数据类型  (*数组指针变量名) [列宽] (列宽 == 指向的二维数组的列宽)

int arr1[2][3] = {{1,2,3},{4,5,6}};
int arr2[2][4] = {{1,2,3,4},{5,6,7,8}};

int (*p)[3] = arr1;
int (*q)[3] = arr2;   //错误的
int (*q)[4] = arr2;   //正确的

         数组指针的应用:

                在函数定义时,二维数组作为形参----------------row为行数,col为列数

返回值类型 函数名(数据类型 二维数组名[][列宽], int row, int col)
{
    //代码块
}

                可以使用数组指针代替二维数组作为函数的形参

返回值类型 函数名(数据类型 (*数组指针变量名)[][列宽], int row, int col)
{
    //代码块
}

二、二维数组变量名与数组指针变量名的含义 

int arr1[2][3] = {{1,2,3},{4,5,6}};

int (*p)[3] = arr1;

        其中,arr1 为二维数组名,同时也代表二维数组的首地址。

        二维数组在内存中实际上是在连续的内存空间上存储的,可以通过一维数组的遍历方式进行遍历。也可以将二维数组当成几个一维数组来看待。arr1[2][3]就是由arr1[0]、arr1[1] 两个一维数组组成的,arr1的第一个元素不是arr1[0][0],而是arr[0]。数组名arr1代表的是arr[0]的地址,而不是arr1[0][0]的地址。

        数组指针本质是一个指针,指向一个二维数组。

        数组指针变量名 p 指向的是 arr1 数组的第一行的首地址,即arr[0]的地址,不是arr1[0][0],虽然arr[0]的地址与arr[0][0]的地址在数值上是一致的,但是其所表示的含义不同。p 指向的是一个由3个int类型的元素组成的数组的首地址arr[0],因此其在进行偏移时,p + 1增加了3 *sizeof(int)  =  12个字节,而arr1[0][0]的地址在进行偏移时只会偏移一个数组元素的大小,增加了 sizeof(int) = 4个字节。因此,数组指针也称为行指针。

printf("p = %p\n", p);
printf("&arr1[0][0] = %p\n", &arr1[0][0]);

printf("p + 1= %p\n", p +1);
printf("&arr1[0][0] + 1 = %p\n", &arr1[0][0] + 1);

  结果:

p = 0x7ffc2c0550b0
&arr1[0][0] = 0x7ffc2c0550b0
p + 1 = 0x7ffc2c0550bc
&arr1[0][0] + 1 == 0x7ffc2c0550b4

        通过sizeof函数可以看出arr1[0]与arr1[0][0]所占空间的大小,所以在对行地址与行地址首元素进行偏移运算时,发现其地址的增量是不一样的。

printf("sizeof(p[0]) = %d\n",sizeof(p[0]));
printf("sizeof(p[0][0] = %d\n)",sizeof(p[0][0]));


//结果
sizeof(p[0]) = 12
sizeof(p[0][0] = 4

 

三、使用数组指针遍历二维数组 

        使用数组指针指向二维数组,可以将数组指针变量名当做二维数组名使用。

        注意:在进行偏移量的计算过程中,通过观察前面的值是行地址,还是行首元素的地址。例如,p + 1, &arr1[0] + i 皆为行地址,偏移时以一行为单位进行计算。p[0] + 1,arr1[0] + i,*(p + i) + 1,*(arr + i) + 1皆为行首元素地址,偏移时以一个元素为单位进行计算,可以看出p[i] <==> *(p + i)。

        通过二维数组名和数组指针访问二维数组中每个元素的值。

数组名[row][col] <==> *(数组名[row] + col) <==> *(*(数组名 + row) + col)

数组指针变量名[row][col] <==> *(数组指针变量名[row] + col)  
			<==> *(*(数组指针变量名 + row) + col)
//数组名方式
for (int i = 0; i < row; i++)
{
   for (int j = 0; j < col; j++)
   {
        //printf("%d\n",*(*(arr1 + i) + j));
        //printf("%d\n",*(arr1[i] + j));
        printf("%d\t", arr1[i][j]);
        
   }
   putchar('\n');
}

//数组指针方式
for (int i = 0; i < row; i++)
{
   for (int j = 0; j < col; j++)
   {
       //printf("%d\t", *(*(p + i) + j));
       //printf("%d\n",*(p[i] + j));
       printf("%d\n",p[i][j]); 
   }
   putchar(10);
}

         通过二维数组名和数组指针访问二维数组的每个元素的地址。

取二维数组每个元素的地址:
	&数组名[row][col] <==> 数组名[row] + col <==> *(数组名+row) + col

通过数组指针变量指向二维数组的每个元素的地址:(数据类型 *)
	&数组指针变量名[row][col] <==> 数组指针变量名[row] + col
			<==> *(数组指针变量名 + row) + col
//数组名方式
for (int i = 0; i < row; i++)
{
   for (int j = 0; j < col; j++)
   {
       printf("%p\t", &arr[i][j]);
       //printf("%p\t", arr[i] + j);
       //printf("%p\t", *(arr + i) + j);
   }
   putchar('\n');
}

//数组指针方式
for (int i = 0; i < row; i++)
{
   for (int j = 0; j < col; j++)
   {
       printf("%p\t", &p[i][j]);
       //printf("%p\t", p[i] + j);
       //printf("%p\t", *(p + i) + j);
   }
   putchar('\n');
}

        通过二维数组名和数组指针访问二维数组的每行首元素的地址。

取二维数组每行的首地址:
    数组名[row] <==> *(数组名 + row)

通过数组指针变量指向二维数组的每行的首地址:(数据类型 *)
	数组指针变量名[row] <==> *(数组指针变量名 + row)
//数组名方式
for (int i = 0 ; i < row; i++)
{
    printf("%p\t", arr[i]);
    //printf("%p\n", *(arr + i));
}

//数组指针方式
for (int i = 0 ; i < row; i++)
{
    printf("%p\t", p[i]);
    //printf("%p\n", *(p + i));
}

         通过二维数组名和数组指针访问二维数组的行地址。

二维数组对应的行地址:
    数组名 + row

通过数组指针变量指向二维数组的每行的地址:
	数组指针变量名 + row
//数组名方式
for (int i = 0; i < row; i++)
{
    printf("%p\t", arr + i);
}

//数组指针方式
for (int i = 0; i < row i++)
{
    printf("%p\t", p + i);
}

四、总结

        在使用数组指针指向二维数组时。有以下的等价关系

                                数组指针变量名 == 二维数组名 == &二维数组名[0]

        二维数组名与数组指针变量名的异同点:

        相同:二维数组名和数组指针变量名都是一个行地址,在使用时二维数组名和数组指针变量名的用法基本一致。

        不同点:二维数组名是一个常量,不可以被修改,数组指针变量名是一个变量,可以修改数组指针的指向。              

  • 8
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值