数组指针 和 指针数组

        在C语言中,指针是个神奇的东西,在window底层对指针的妙用无处不在。这里来总结数组针指的小结。在内存里面系统就是通过指针来寻找数组的每个元素的。


一、数组指针

1.一维数组:

数组指针:指向一个数组的指针。

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

        这里有个整形数组 arr,这里我们知道arr是数组名,也是地址首元素的地址。 那么能不能定义一个指针来指向这个数组并调用数组里面的元素呢。

        其实是可以的。那么指针的类型是什么样的呢。

我们定义指针的时候:

int a=10;
int* p=&a;
printf("%d",*p);

         这里p就是一个指向a地址的指针,取地址a (&a),取得的就是a的地址,解引用(*p)就是获得变量a上存的值。

        这里可以总结一个小规律,一个变量取地址(&)就相当于原来的类型加上一个*,一个指针解(*)引用就相当原来的类型减一个*。

        &a(取地址)的后获得的类型就是 int*,*p(解引用)后获得的类型是 int

那么对于数组来说也是一样的,把数组取地址(&arr),得到的类型是原类型加上一个*。

int (*arr)[];
//注意不是 int *arr[];

那么用来接受这个数组地址的类型也该是

int arr[10];
int (*p)[10]=&arr;

        这里指针p是一个指针,指向一个数组,数组的返回类型是int类,所以p就叫数组指针,表达了整个数组。

 PS:

int (*p1)[10];
int (*p2)[5];

         这里 [ ] 里面10跟5的差别很大,是10的时候 p+1,跳过数组的10个元素,是5的时候则跳过5个元素。

void print(int (*p)[10],int sz) //这种写法属于绕远路,一般写的少
{
	for(int i=0;i<sz;i++){
        printf("%d ",*(*p+i));  
    }
}	

int arr[10]={1,2,3,4,5,6,7,8,9,10};
int sz=sizeof(arr)/sizeof(arr[0]);
print(&arr,sz);

         指针p解引用(*p),原类型去掉一个*,就是 int p[10],这里p就代表数组名,数组名就是首元素的地址。所以解引用数组指针,就是数组首元素地址。

        那么 首元素地址再加上一个数 i,就能取到第i个元素的地址 *(*p+i )

        

PS:这里 p,&arr,arr的值是一样的,代表的含义不同。 

数组名:

1.sizeof(arr) ,这里arr表示的是整个数组。

2.&arr,这里也是表示取的整个数组的地址。

然后其他的数组名,都是表示数组首元素地址。

* :虽然地址首元素的地址跟整个数组的地址是一样的,但是 首元素的地址+1,则跳到下一个元素,整个数组的地址+1,则跳过整个数组。

2.二维数组:

        对于二维数组来说,数组指针有又有些不同。   

void print(int (*p)[3],int c,int r) 
{
	for(int i=0;i<r;i++){
        for(int j=0;j<c;j++){
            printf("%d ",*(*(p+i)+j); 
         
        }  
    }
}	 
                   
int arr[3][3]={{1,2,3},{4,5,6},{7,8,9}};
print(arr,3,3);
//int (*p)[3][3],必须三行三列,才能接收二维数组arr

         在二维数组中 arr 代表的是第一行的地址,相当于*(arr+0)、arr[0]。也叫行指针。

        会发现这里  int arr[3][3],跟上面的 int (*p)[3]  很相似。所以这里的 arr也可以理解为一个数组指针指向数组的第一行。

        &arr[0][0],*(arr+0)+0,才是第一个元素的地址(地址是一样的,意义不同)。

             

         按照上面,arr取地址(&arr),原类型加一个*,int (*arr)[3][3],还是要注意不是int* arr[3][3],那么用来接收指向二维数组的指针的类型就是,int(*p)[3][3]。

        解引用p (*p) ,原类型减去一个*,就是 int p[3][3],这里的p代表的是数组第一行的地址,       *(p+i),就获得的是数组第i行首元素的地址,再解引用*(*p),原类型再减去一个*就是int p[3],这里的p就是首元素地址了,*(*(p+i)+j)获得的就是第几行第几个元素。

        这里有多中写法:1.p[ i ][ j ]        2.*( p + i ) [ j ]

         PS:这里的p[3][3],元素的个数必须跟二维数组一样。 

         PS:理解去*,加*的时候,*是从变量名最近的*号开始的,也就是从最里面的*开始算。

二、指针数组

        那么为什么数组指针不能写成  int*arr[10],这种形式呢。

        因为这种数组代表的意义不同,此数组叫指针数组,意思是一个数组arr,有10个元素,每个元素的类型是 int* 的指针。

int a1,a2,a3;
int *p1=&a1;
int *p2=&a2;
int *p3=&a3;
int *arr[3]={p1,p2,p3};

指针数组也可以定义一个指向数组的指针:

        int* (*arr)[3];        二维数组: int* (*arr)[3][3];

        当然不管是在这里还是在上面,都还可以进行无限的套娃(加*),不过意义已经不大而且几乎使用不到,并且非常复杂。 

对于指针数组来说,则就可以使用 int * *arr(二级指针)来接受数组。

void test(int* *p){ }

int *arr[3];
test(arr)  //不是&arr

但是为什么某些编译器或者网站则使用 int* * arr来接受二维数组呢?

其实它们不是标准的二维数组,只是二维数组的一个模拟


总结

        光是在数组里面的指针的意义和用法都多种多样,要熟练指针,多练习和运用。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值