【数组与指针(3)】函数、数组和指针——C Primer Plus 学习笔记


一、指针操作

1.指针的存储结果

#include <stdio.h>
int main()
{	
	int a = 10;
	int* p = &a;
	printf("&a= %p\n", &a);
	printf("*p= %d\n", *p);
	printf("p = %p\n", p);
	return 0;
}

由此代码可以清晰看出指针存储结果.
输出结果如下:

&a= 0000009137FEF5F4
*p= 10
p = 0000009137FEF5F4

p储存了变量的地址,*p对其解引用


2.指针运算

了解了指针的工作原理,我们就能对指针进行运算.
代码如下:

#include <stdio.h>
int main()
{	
	int arr1[5] = { 1,3,5,7,9 };
	int* p = arr1;
	int* p1 = arr1 + 1;//数组名+1
	printf("%d\n", *p + 1);//对p解引用,并+1
	printf("%d\n", *(p + 1));//对p+1解引用
	printf("%d\n", *p1);
	printf("%d\n", p1 - p);//指针相减
	return 0;
}

运行结果如下:

*p+1  = 2
*(p+1)= 3
*p1   = 3
p1-p  = 1

  可知,*p等价于arr1[0]的值,即为1

   *(p+1)等价于arr1[1],即为3,也等于数组名+1

   两指针相减,表示两个指针指向数组元素之间的差距,并不是指多少字节,而是指多少个类型

二、指针和多维数组

1.指针与多维数组的关系

我们知道在一维数组中,指针表示数组首元素地址

int zippo[4][2];//内含int数组的数组

在二维数组中,首元素是首行数组,即zippo[0],其内含两个整数.

既然zippo[0]是数组,那么其地址应该为其首元素地址,即zippo[0][0]

#include <stdio.h>
int main()
{	
	int zippo[4][2] = { {1,3} ,{5,7} };//创建二维数组
	printf("%p\n", &zippo);//对该数组取址
	printf("%p", &zippo[0][0]);
	return 0;
}

其结果如下:

000000F691B5F518
000000F691B5F518

地址是相同的.

换言之,zippo是一个占用了两个int对象的地址(相当于zippo+1跨了一行),而zippo[0]是一个占用了一个int对象(zippo[0]+1前进一列)的地址,

但由于首元素开始于同一地址,故值相同.


2.对多维数组指针解引用

解引用一个指针(在指针前使用运算符),或在数组名后使用带下标的 [ ] 运算符,得到对象的值

int main()
{	
	int zippo[4][2] = { {1,3} ,{5,7} };
	int* p1 = &zippo;//此写法是不规范的,下文会详解
	printf("**zippo=%d\n", **zippo);
	printf("*p1=%d\n", *p1);
	int* p2 = &zippo[1];
	printf("*p2=%d\n", *p2);
	return 0;
}

结果如下

**zippo=1
 *  p1  =1
 *  p2  =5


p本应是首元素zippo[0]地址,但其地址与zippo[0][0]相同,所以&zippo等价于&zippo[0][0],

*p是首元素zippo[0]的值,但zippo[0]本身是一个int类型的地址,地址为

&zippo[0][0],所以 **zippo与 * &zippo[0][0]等价,相当于int类型的值zippo[0][0].


即zippo是地址的地址(指针的指针) 必须解引用两次才能获得原始值.
地址的地址(指针的指针)就是双重间接的例子.

理解思路:

  • zippo 二维数组首元素地址(每个元素都是内含两个int类型元素的一维数组) zippo+2
  • 二维数组的第三个元素的地址,即zippo[2]
  • *(zippo+2) 二维数组的第三个元素的首元素地址
  • *(zippo+2)+1 二维数组的第三个元素的第二个元素(int)的地址
  • *(*(zippo+2)+1) 数组第3行第2列的值,zippo[2][1]
    

3.指向多维数组的指针

  如何声明一个指针变量pz指向一个二维数组?

  把指针声明指向int的类型还不够,因为指向int只能与zippo[0]的类型相匹配,

  说明该指针指向一个int,但二维数组zippo[4][2]的zippo是含有两个int的一维数组,所以p必须指向一个内含两个int的数组,而不是指向一个int值.

我们看以下代码:

int (*pz)[2];//1
int * pax[2];//2

  代码 1 表示pz为指向数组的指针,并含有两个int类型值
  代码 2 表示pax为内含两个元素的数组,数组内含两个指针,指针指向int类型



  产生这样的结果的原因是[ ]的优先级高于 *所以会与pax先结合变为数组, *表示数组内有两个指针(指针数组)

因此我们明白了指针数组与数组指针

  • 形如 int* pax[2]; 的指针数组(我把它理解为指针的数组),它首先要是一个数组,然后由 int* 修饰数组的内容,表示其包含 2 个指向 int 的指针
  • 而形如int (*pz)[2]; 的数组指针(数组的指针),首先要是一个指针(*与pz结合),而 int 修饰数组 [2] ,使其类型变为整型
int main()
{	
	int zippo[4][2] = { {1,3} ,{5,7} };
	int arr[2] = { 2,4 };
	int(*pa)[2] = zippo;\\数组指针,指向int
	int* pax[2] = { &zippo,&arr };\\指针数组,指向两个地址
	printf("%p\n", &arr);
	printf("%p\n", pax[1]);
	printf("%d\n", *pa[0]);
	printf("%d", *pa[1]);
	return 0;
}
&arr=00000002BACFF588
&pax[1]=00000002BACFF588
*pa[0]=1//zippo第一个元素的首元素
*pa[1]=5//zippo第二个元素的首元素





其具体应用来日再谈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值