【C】指针笔记_2

二级指针和解引用

二级指针: 指向一级指针的指针, 二级指针是存储一级指针的地址

int **ppa = &pa, **ppb=&pb , **ppc =&pc;
printf("ppa=%d, ppb=%d, ppc=%d\n", ppa, ppb ,ppc);

二级指针解引用

*ppa <=> pa
*pa <=> b

printf("*ppa=%d, *ppb=%d, *ppc=%d\n", *ppa, *ppb, *ppc);

**ppa <=> *(*ppa) <=> *pa <=> b

printf("**ppa=%d, **ppb=%d, **ppc=%d\n", **ppa, **ppb, **ppc);

多级指针

三级指针

int*** pppa, ***pppc, ***pppb;

野指针
四级指针 : 应该存储三级指针的地址

a = (int)&ppa;
printf("a=%d\n", a);
int ****ppppa = &a;
printf("*ppppa=%d\n", *ppppa);				//一次解引用=>三级指针 ppa的地址
printf("**ppppa=%d\n", **ppppa);			//两次解引用=> ppa =>pa的地址
printf("****ppppa=%d\n", ****ppppa);		//四次解引用=>数据 a

四级指针 *ppppa => 等价于三级指针 pppa
三级指针 *pppa => 等价于二级指针 ppa

指针的运算

  • 指针 + 整数 = 指针
  • 指针 - 整数 = 指针
  • 指针 - 指针 = n单位(取决于数据类型)

指针之间也可以进行大小比较(>, <, >=, <=),但是在同一段连续的内存当中进行指针的运算,才有意义。【此外还有!= ,==】


数组

数组:一段连续的内存

int* arr[10] = {1,2,3,4,5,6,7,8,9,10};
for (int i = 0; i < 10;i++)
{
	printf("%d, ", arr[i]);
}
printf("\n");
  • 数组名是一个地址, 表示数组的首地址, 数组下标为0的元素的地址, arr[0]这个元素的地址,是个指针.
  • 数组名是一个指针, 类型是什么? int型指针, int*型 , 取决于元素的类型。
  • 数组名是一个常量,不能修改。
printf("arr=%d\n", arr);		 //假设第一个数字所在内存位置为10000
printf("arr + 1=%d\n", arr + 1); //内存位置不是10001,应该+4,10004
printf("arr + 2=%d\n", arr + 2); 
...
printf("arr + 9=%d\n", arr + 9); 
printf("arr + 10=%d\n", arr + 10);//属于越界了,不在初始化的范围之内

数组内指针的应用

指针 - 整数

int* parr = arr + 8;
printf("parr-9=%d\n", parr - 9);	//越界了

指针 - 指针

printf("parr - arr=%d\n", parr- arr);

指针必须是一个变量,不能是常量

arr++;
arr--;

指针 ++
指针 - -

parr = arr;
parr++;
parr = parr + 1;
parr--;
parr = parr - 1;
printf("parr++=%d\n", parr);

数组和指针的关系

指针和一维数组的关系

printf("arr + 0=%d\n", arr + 0);		 //10000
printf("arr + 1=%d\n", arr + 1); //不是10001 ,应该+4
printf("arr + 2=%d\n", arr + 2);
//...
printf("arr + 9=%d\n", arr + 9);


printf("&arr[0]=%d\n", &arr[0]);
printf("&arr[1]=%d\n", &arr[1]);
//....
printf("&arr[9]=%d\n", &arr[9]);

	/*
	推导
	arr + 0	<=> &arr[0]
	arr + 1 <=> &arr[1]
	arr + 2 <=> &arr[2]
	...
	arr + 9 <=> &arr[9]	
	*/

printf("*(arr + 0)=%d\n", *(arr + 0));
printf("*(arr + 1)=%d\n", *(arr + 1));

	/*
	推导
	*(arr + 0) <=> arr[0]
	*(arr + 1) <=> arr[1]
	*(arr + 2) <=> arr[2]
	....
	*(arr + 9) <=> arr[9]	
	*/

for (int i = 0; i < 10;i++)
{
	printf("%d, ", *(arr+i));
}
printf("\n\n\n");

:在一段连读的内存中, 下标方式访问间接访问 有什么区别?
:下标访问可以和间接访问互相转化,用间接访问的方式效率还会更高

指针和二维数组的关系

int arr2[4][5] = 
{
	{1,2,3,4,5},
	{6,7,8,9,10},
	{11,12,13,14,15},
	{16,17,18,19,20}
};
for (int i = 0; i < 4;i++)
{
	for (int j = 0; j < 5;j++)
	{
		printf("%d, ", arr2[i][j]);
	}
	printf("\n");
}
printf("\n");

指针和一维数组的关系,同样适用于二维数组
arr2:二维数组的数组名,表示什么,类型是什么?
:数组的首地址, 数组的下标为0的元素的地址, 也就是数组arr2[0]这个元素的地址

int arr2[4][5] = {{ 1, 2, 3, 4, 5 },{ 6, 7, 8, 9, 10 },{ 11, 12, 13, 14, 15 },{ 16, 17, 18, 19, 20 }};

把二位数组就看成 一维数组
arr2的类型是 一维数组的地址, 指向数组的指针,简称数组指针

int(*parr2)[5];	 //parr2就表示指向数组的指针, 5是不能省略   int(*)[5]
printf("arr2 + 0=%d\n", arr2 + 0);			//指向数组的指针	
printf("arr2 + 1=%d\n", arr2 + 1);	//
printf("arr2 + 3=%d\n", arr2 + 3);

printf("&arr2[0]=%d\n", &arr2[0]);

	/*
	推导
	arr2 + 0 <=> &arr2[0]
	arr2 + 1 <=> &arr2[1]
	...
	arr2 + 3 <=> &arr2[3]	

	再次推导:
	*(arr2 + 0) <=> arr2[0]
	*(arr2 + 1) <=> arr2[1]
	...
	*(arr2 + 3) <=> arr2[3]

	再次推导
	*(arr2 + 0) + 0 <=> arr2[0]+0 <=> &arr2[0][0]
	*(arr2 + 0) + 1 <=> arr2[0]+1 <=> &arr2[0][1]
	...
	*(arr2 + 0) + 4 <=> arr2[0]+4 <=> &arr2[0][4]
	*(arr2 + 1) + 4 <=> arr2[1]+4 <=> &arr2[1][4]

	再次推导
	*(*(arr2 + 0) + 0 ) <=> arr2[0][0]
	*(*(arr2 + 0) + 1 ) <=> arr2[0][1]
	...
	*(*(arr2 + 1) + 0 ) <=> arr2[1][0]
	*/


printf("*(arr2+0)=%d\n", *(arr2 + 0));
printf("arr2[0]=%d\n", arr2[0]);			//arr2[0]一维数组的数组名 , arr2[0][0]的地址,类型:int*

printf("arr2[0] + 1=%d\n\n", arr2[0] + 1);

for (int i = 0; i < 4; i++)
{
	for (int j = 0; j < 5; j++)
	{
		printf("%d, ", (*(arr2 + i))[j] );  //(*(arr2 + i))
	}
	printf("\n");
}
printf("\n");

:怎么定义一定一个指向三维数组的指针

int arr4[2][3][4] = {0};
int(*parr4)[3][4] = arr4;

指针和字符串数组的关系

char* str = "HelloWorld";
printf("%s\n", str);  //打印整个字符串
printf("%d\n", "HelloWorld"[0]);  //打印字符串首个字符的ACSII码 72
printf("%c\n", *("HelloWorld"));  //打印字符串的首个字符"H"
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值