指针----进阶

指针

指针基本概念:
1.指针是变量,用于存放地址,地址唯一标识一块空间
2.指针类型的不同,决定指针变量++后跳过的步长
3.指针的大小固定,4/8个字节(32/64位平台)
4.指针运算

字符指针

字符指针基本格式: char* 

字符指针的一般使用:
这种使用比较常见,也比较简单

int main()
{
char ch = 'w';
char *pc = &ch;
*pc = 'w';
return 0;
}

另一种是关于指针常量的用法:

int main()
{
	const char* pstr = "hello,bit";
	const char* pstr1 = "hello,bit";
	char pstr2[] = "hello, bit ";
	char pstr3[]="hello,bit";
	printf("%s", pstr);
	printf("%s", pstr2);
	return 0;
}

两种方式通过打印起到的效果一样
pstr和pstr1,pstr2和pstr3类型相同,是为了后面方便观察与字符数组的区别

const char* pstr 中存放的只是“h”的地址
char pstr2 []  ,变量名是首元素地址,但是确是将整个字符内容存放到了
数组中。

打开监视器,我们观察一下两种数据类型的区别:
在这里插入图片描述

两个常量字符指针的地址空间相同,而两个数组的空间不同。
需要说明,常量数据与普通变量存放的空间区域不同,常量数据存放在了常量区,而这里的数组数据放在了栈区,将相同的常量字符赋值给不同的字符变量指针,这两个不同的字符指针指向的是同一块地址,而对于普通变量,即使存放的内容相同,但是还会开辟不同的内存空间。

指针数组

格式:Type* arr[]

首先指针数组是一个数组,其中的元素都是指针。
就像普通的数组类型,int [] 中的元素都是int,char [] 中的元素都是char。
指针数组的类型如char* [ ] 、int * [ ] 、double* [ ]等,区别就是数组元素类型的不同。
通过一段代码来通过一维指针数组模二维数组:

int main()
{
	char str1[] = "zhangsan";
	char str2[] = "lisi";
	char str3[] = "wangwu";
	char str4[] = "laoliu";
	char* pstr[4] = { str1 ,str2,str3,str4 };
	return 0;
}

数组名是首元素地址,这里将四个数组的首元素地址放到一个char类型的指针数组中,效果如下图:
在这里插入图片描述

需要说明,数组开辟的是一块连续空间,指针数组pstr中的空间是连续的,但是str1、str2、str3、str4之间的空间不是连续的。
就像普通的数组一样,可以通过下标对数组中的各个元素进行访问:
在这里插入图片描述
在这里插入图片描述

数组指针

格式:int(*) [ ]
	 char(*)[ ]..... 

这么理解:
  (*+变量名)表示我是一个指针
   int (*+变量名)[]表示我指向的类型是int [] 

数组指针是一个指针,指向的整个数组的空间,开篇说到,指针类型的不同,
决定了指针++或者--跳过的步长。

通过代码看一下 数组名 与 &数组名的不同:
在这里插入图片描述

两个地址相同,但是++后再看一下区别:
在这里插入图片描述
很显然,arr+1跳过了4个字节,而&arr+1跳过了40个字节

所以我们说&arr取的是整个数组的空间
那么用什么类型的变量保存这样的地址呢????
很显然就是这里所说的数组指针

在这里插入图片描述

效果相同!

数组指针的使用:

数组指针的使用一般可用于二维数组传参:

void print_arr2(int (*arr)[5], int row, int col)
{
int i = 0;
for(i=0; i<row; i++)
{
for(j=0; j<col; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[3][5] = {1,2,3,4,5,6,7,8,9,10};
print_arr1(arr, 3, 5);
//数组名arr,表示首元素的地址
//但是二维数组的首元素是二维数组的第一行
//所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
//可以数组指针来接收
print_arr2(arr, 3, 5);
return 0;
}

print_arr2(arr, 3, 5);
arr是一个二维数组,传递的参数arr其实是首元素地址,即arr[0]的地址;
arr[0]是一个一维数组,一维数组的地址传给函数,这时形参可以用一个数组
指针接收;

下面是数组传参的总结。

一维数组传参:

一维数组作为实参传递给实参,形参用什么类型接受??
在这里插入图片描述
在这里插入图片描述

 int arr[] 可以,可以不指定大小
 int arr[10],当然可以
 int* arr ,可以,一维数组传参,传递的实际上就是首元素地址,用一个指针当然可以接收
 int* arr[20],可以,形参与实参类型相同
 int** arr,可以,实参是一个指针数组,每个元素都是指针,我们传递的是首元素地址,即一个地址的地址,当然可以用二级指针接收。

二维数组传参:

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

int arr[3][5]:可以,形参与实参类型相同
int [][]:不可以,二维数组类型创建的时候,可以省略行,但是不能省略列
int[][5]:可以
int *arr:不可以,二维数组传递的实质是&arr[0],是一个一维数组,类型不匹配
int * arr[5]:不可以,arr实际上是一个数组指针,形参类型是指针数组,一个数组当然不可以接收一个指针
int (*arr)[5]:可以,形参是数组指针,实参也是数组指针
int **arr:不可以,int**的意思是arr变量的内容是一个地址,该地址指向一个int整型,而传递的实参是一个指向数组的地址,类型补匹配。

函数指针

函数指针类型:returnType(* pf)(eType1,eType2,....);
returnType 是要指向的函数的返回值类型;
eType是指向的函数的参数类型;

先上一段代码:

int ADD(int x, int y)
{
	return x + y;
}
int main()
{
	ADD(3, 5);
	printf("%p", ADD);
	printf("%p", &ADD);

	return 0;
}

在这里插入图片描述
从控制台可以看出来,函数名与&函数名是同一个东西,所以,函数名的实质就像数组名一样,是一段地址。

指针常量与常量指针

const int* p;
int const* p;
int* const p;
对于常量指针与指针常量不容故意分辨,这样理解:

总体分为两类:
const在*左边;
const在*右边;

const在*左边:
const int* p 或者 int const* p 是常量指针
把const和int去掉,原表达式只剩下*p,所以这里const修饰的*p,
*p,就是我们所说的解引用p,内容就是p中的地址所指向的内容,
所以常量指针,该指针的内容不可以改变,而p可以改变。

const在*右边:
把表达式中,const前的内容删去,int* const p,变成p
即const修饰的是p,p是一个指真,p的内容不能被修改,但是*p可以被修改。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值