指针-指针数组,数组指针

Part1:

指针数组 用法  低级 写入 输出 正常

       在之前,指针数组有提到过,是一个数组,存放指针的数组。为什么会出现这个东西,当我们要把许多地址都交给指针变量的时候,需要一个一个写,太麻烦了,指针数组解了这个问题。来看一下指针数组的使用:和定义普通类型数组一般,只是赋值时的内容变成了地址,类型加上*。

使用的话,我们可以用一个循环来找到每个指针的地址,再解引用它。

#include<stdio.h>

int main(void) {
	int a = 1;
	int b = 2;
	int c = 3;
	int d = 4;
	int e = 5;
	int* parr[] = { &a,&b,&c,&d,&e };//输入,类型变为int*,一个纯纯的数组
	
	int i = 0;    //输出
	for (i = 0; i < 5; i++) {
		printf("%d ", *parr[i]);
	}

	return 0;
}

       这样的写法大多于初学者,我们有很多int类型的变量,为什么不写成一个数组呢?指针数组的类型也是统一的,只能存放相同类型的指针变量。我们平时写数组时,知道数组首地址就可以得到整个数组的元素,这里同样如此,我们只需要一个指针变量指向数组首地址即可。多个元素指向多个同类型的数组,把指针放在一起成一个指针数组,一个类似二维数组的结构就出现了

#include<stdio.h>

int main(void) {
	int a[] = { 1,2,3,4,5 };
	int b[] = { 2,3,4,5,6 };
	int c[] = { 3,4,5,6,7 };

	int* parr[] = { a,b,c };  //输入

	int i = 0;
	for (i = 0; i < 3; i++) {   //找到数组首地址
		int j = 0;
		for (j; j < 5; j++) {  //根据首地址找到各个数组元素
			printf("%d ", *(parr[i] + j));  //输出
		}
		putchar('\n');
	}

	return 0;
}

      为了加深理解,我们平时对数组进行的操作也可以对指针数组进行

printf("%d\n", sizeof(parr));
printf("%d\n", sizeof(parr)/sizeof(parr[0]));

     这里得到的结果分别是24和3,我用的是x64,指针所占字节数为8。

Part2:

数组指针 指针/数组?类比 首元素vs数组 结合性

       

       数组指针是什么?我们来类比一下,整型指针是指向整型的指针,字符指针是指向字符的指针,顾名思义:数组指针是指向数组的指针。

       

        我们需要先了解一下数组首元素地址和数组地址,之前在初学者指针那块有详细说明,这里回忆一下。

        

	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	//arr---首元素地址
	//&arr[0]---首元素地址
	//&arr---数组地址

     指向数组的指针,是这个样子的吗?

	int* p = arr;

     还是这个样子的?

	int* p = &arr[0];

      你会发现它们都是指向数组首元素地址的,并不是指向数组地址的(区别在初学者指针那篇有提到),那这样呢?

int* q = &arr;

       这样总是指向数组地址了吧?
      看起来合情合理,但并不是我们想要的,我们想要的是用一个指针可以指向数组内的所有元素,这里依旧无法用一个指针指向每个元素的地址。那看看下一个怎么样?

int* p[] = { &arr[0],&arr[1],&arr[2]......&arr[8] ,&arr[9] };
//用p[0],p[1]等来指向元素

       这样是用一个指针指向所有元素吗?嘿,如果你还记得刚刚看过的指针数组,你可以很明显的发现,这是一个指针数组,也就是说这里的p[0],p[1],并不是一个指针,它们是很多个指针放在一起的,从内存上来看每八个字节放在一块(x64),想象一下八十个字节,每八个就插一块隔板,形成一个个的指针变量,这是指针数组。而数组指针要做的就是把这些隔板拿走,把所有地址都放在一块空间内,形成一个空间为八十字节的指针,也就是数组指针。或许你曾有疑问:指针空间不是放一个地址吗?怎么可能指向所有元素地址?哈哈,这这是数组指针与其他类型指针不同的地方了!那代码要如何写呢?

       这里先了解一个结合性[ ]的结合性是高于*号的,如果我们直接写int*p[],这样p和【】结合,是一个数组,什么类型的?int*。那我们可以让*和p先结合,怎么做?加一个()。int(*p)[ ]。*p先表示这是一个指针,之后用int【】表示是整型数组类型的指针,指向整型数组。(这个和设计者有关了,他们想要这样表示也是为了方便写,不会多出一些符号,想象一下有一堆规则和一堆符号,用符号的排列来代表那些规则,经过不断地优化,活下来的符号是为了方便使用和记忆)

	int(*p)[10] = &arr;        //一个空间为80字节的指针

我们要如何解引用呢?我们知道它是一个指针,一般的指针是如何解引用的?

#include<stdio.h>
int main (void)
{
    int arr[]={1,2,3,4,5,6,7,8,9,10};
    int* p=arr;
    printf("%d",*p); //整型指针的解引用

}
//结果为:1

数组指针要如何做呢?这要先了解数组的【】。

之前说过结合性的问题,这个【】和指针在定义外的地方结合是什么意思?数组吗?

想必大家之前就有了解到数组是一个特别的指针。其【】表示的是对该地址进行运算并解引用,如下:

#include<stdio.h>
int main(void) {
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = arr;          //定义整型指针指向首元素地址        

	printf("%d\n", arr[1]); //arr表示首元素地址,进行+1运算后解引用
	printf("%d\n", p[1]);   //  p等于首元素地址,进行+1运算后解引用
 
	//二者运算结果均为:2
    
    return 0;
}

我们再来看这一段代码:

	int(*p)[10] = &arr;
	printf("%d\n",**p);  //可以发现p是一个二级指针
                         //需要解引用两次,但又有些特殊
   //运行结果为:1

再来看这一段代码:

	printf("%p\n", p);
	printf("%p\n", *p);
    
    //程序运行得到的值完全相等,是不是有些诡异了
    //这里是一个特殊的地方,我也不清楚为什么这样设计

很明显这里p=&a,一个诡异的二级指针,我们给了它一个名字:指向数组的指针,数组指针,类型:int (*)【】,一种构造类型。正确的代码应该如何去描写,如下:

#include<stdio.h>

int main(void) {
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };

	int(*p)[10] = &arr;
	printf("%d", (*p)[0]);  //解引用,我们在这里加上一个括号,使它成为一个指向首元素的指针
                               //然后对其进行运算得到某个位置的地址,再解引用。

	return 0;
}

关于&数组名和数组指针的关系可以看这篇:

&数组名与数组指针的关系_blyourself的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值