2021-06-01 C语言指针数组深入分析

指针内存大小
一个基本的数据类型(包括结构体等自定义类型)加上“”号就构成了一个指针类型,
在这里插入图片描述**指针大小是一定的,与“
”号前面的数据类型无关。“*”号前面的数据类型只是说明指针所指向的内存里存储的数据类型。所以,在32 位系统下,不管什么样的指针类型,其大小都为4byte。** 指针存放所指向内容的首地址。

*int p = NULL 和 p = NULL 有什么区别?
a 和&a 的区别
在这里插入图片描述
如上图&aa+1表示aa的下一个数组,即aa[5]的首地址。即aa+20的地址,每个int型为4个byte。
则赋值的ck指针的指向的地址为aa[5]的地址,则
(ck-1)则为aa[4]的地址。
&aa + 1: 取数组aa的首地址,该地址的值加上sizeof(aa) 的值,即&aa + 5*sizeof(int),也就是下一个数组的首地址,显然当前指针已经越过了数组的界限。
(ck-1): 因为ck 是指向aa[5],并且ck是int * 类型,所以(ck-1) 是指向aa[4] ,输出589。

定义为指针,声明为数组
文件1
char *p = “abcdefg”;
文件2
extern char p[];
在文件1 中,编译器分配4 个byte 空间,并命名为p。同时p 里保存了字符串常量“abcdefg”的首字符的首地址。这个字符串常量本身保存在内存的静态区,其内容不可更改。在文件2中,编译器认为p 是一个数组,其大小为4 个byte,数组内保存的是char 类型的数据。在文件2 中使用p 的过程如下图:
在这里插入图片描述
在这里插入图片描述
指针数组和数组指针
指针数组:可以理解为数组,数组里存的是指针。即存储指针的数组。
指针数组就相当于一次声明了多个指针。数组的每一个元素都是一个指针。

在这里插入图片描述
在这里插入图片描述

   int *p[3];
   p[0]=(int*)malloc(20);
   p[1]=(int*)malloc(30);
   p[2]=(int*)malloc(30);
   *p[0]=124;
   *(p[0]+1)=155;
   *p[1]=888;

指针数组的应用
在这里插入图片描述
如上图所示,manuel[ ]数组存的是几个字符串的首地址。也可以输出*(manuel[2]+3)表示字符h。

应用2

int a[4]={111,2114,34575,415367};
int main(void)
{
   int *ptr2=(int *)(a+1);
   int *ptr1=(int *)(&a+1);
   printf( "%x\n",*ptr2);
   return 0;
}

*ptr2为数组a的第二个元素。

但是

int a[4]={111,2114,34575,415367};
int main(void)
{
   int *ptr2=(int *)((int)a+1); //注意注意注意
   int *ptr1=(int *)(&a+1);
   printf( "%x\n",*ptr2);
   return 0;
}

这里的ptr2则是a元素的首地址加1个byte,而不是加一个元素。
在这里插入图片描述
如上图ptr2的地址为a数组第一个元素的地址加1个byte,所以*ptr2的值需要涉及到大端小端。

二维数组与数组指针
数组指针
首先它是一个指针,它指向一个数组,简称指向数组的指针。
数组指针就相当于一次声明了一个指针。只不过这个指针指向很特别,是一个数组

首先定义一个二维数组,5行5列,定义一个数组指针,指向的数组长度为5.
p的地址为二维数组的首地址。

int hsb[5][5]={{1,2,3,4,5},
               {6,7,8,9,10},
               {11,12,13,14,15},
               {16,17,18,19,20},
               {21,22,23,24,25}
};
int (*p)[5];
 p=hsb;

注意数组指针的用法与指针数组不能混淆。(*(p+1))[2] 这里的括号是不能取消的。
((p+1))[i]这里的i可以为0-4,表示第二个数组里面的元素,地址是元素加1 。
(
(p+i))[2] 这里的表示递增为1个数组,分别表示3、8、13、18、23
(*(p+1))[2] 也可以表示为p[1][2]
***(p+1)[i]*不加括号的时候不能表示数组指针,这时候i加1,则表示递加一个数组的地址。并且该地址为递加数组的首地址。
在这里插入图片描述
总结:数组指针的括号是绝对不能省略掉的。
[]优先级大于
,故数组指针声明时要加()
实列1:

#include<stdio.h>
#include<stdlib.h>
void main()
{
    //数组指针的用法,用处。
    int b[16]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
    int (*p)[4]; //该语句是定义一个数组指针,指针步长为4个int即16位。
    //int *p2=b;
    p=b;
    int i=0;
    while(i<16)
    {
          printf("%d\t",(*p)[i]);
          //printf("%d\t",*p2++);
          i++;
    }
}

printf("%d\t",(*p)[i]);遍历输出数组b;
数组指针就相当于舞王僵尸一样,带了小弟,n就是小弟的个数,通过下标值能直接访问到具体哪一个小弟,即数组里哪一个数
数组指针下标自增(i++)的时候,指针指向不变。
实列2:
把例1的while()语句替换。

**while(i<4)
    {
          printf("%d\t",(*p++)[0]);
          i++;
    }**

输出1 5 9 13,相当于指针一次移动了4个int.16个字节。
实列3:

**while(i<4)
    {
          printf("%d\t",(*p+i)[0]);
          i++;
    }**

这时则是增加一个int元素的地址,则输出 1 2 3 4;

**

实列4

:**
数组指针指向二维数组

#include<stdio.h>
#include<stdlib.h>
void main()
{
    int a[3][4]={{1,2,3,4},{11,12,13,14},{21,22,23,24}};
    int (*p)[4]; //该语句是定义一个数组指针,指针步长为4个int即16位。
    p=a;
    int i=0;
    while(i<3)
    {
        //printf("%d\t",(*p)[i]);
        //数组指针,指向的是一个数组整体,相当于指针也带了下标,当执行i++操作时,下标+1,得到该数组的下一个元素,
        //在该例中,指针没有位移,所以依次输出为1 2 3

        printf("%d\t",(*p++)[0]);
        //整型数组类型的指针,指向的是一个数组整体,当执行*p++操作时,指针位移该数组长度的位数
        //在该例中,即指针位移4个int的长度,所以输出是1 11 21
        i++;
    }
}

&p[4][2] - &a[4][2]的值为多少?

int a[5][5];
int (*p)[4];
p = a;

在这里插入图片描述
&a[4][2]=45+2=22个int
&p[4][2]=4
4+2=18个int

当数组名a 作为右值时,代表的是数组首元素的首地址。这里的a 为二维数组,我们把数组a 看作是包含5 个int 类型元素的一维数组,里面再存储了一个一维数组。如此,则a 在这里代表的是a[0]的首地址。a+1 表示的是一维数组a 的第二个元素。a[4]表示的是一维数组a 的第5 个元素,而这个元素里又存了一个一维数组。所以&a[4][2]表示的是&a[0][0]+45sizeof(int) + 2sizeof(int)。根据定义,p 是指向一个包含4 个元素的数组的指针。也就是说p+1 表示的是指针p 向后移动了一个“包含4 个int 类型元素的数组”。这里1 的单位是p 所指向的空间,即4sizeof(int)。所以,p[4]相对于p[0]来说是向后移动了4 个“包含4 个int 类型元素的数组”,即&p[4]表示的是&p[0]+44sizeof(int)。由于p 被初始化为&a[0],那么&p[4][2]表示的是&a[0][0]+44sizeof(int)+2* sizeof(int)。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值