【C语言】指针详解

前言

许多同学闻C语言指针色变,但是指针其实并没有大家想象中的那么难,也没有那么复杂,其实连能想到生活,指针还是很好理解的,虽然题目是指针的详解,但是详细程度在大家的眼中不太相同,但是我会把我学到的有关指针的东西尽力地写出来,帮助大家更好的理解、运用指针!


一、内存和地址

内存对于计算机来说就是存储数据的地方,内存也可以划分为一个个内存单元,每个内存单元一个字节大小,而每一个内存单元都有一个相对应的地址,也就是说内存就像是一个酒店,里面的所有房间都有一个房间号,我们可以通过房间号快速地访问到我们要去的房间


二、指针变量

在C语言中,变量的声明就是向内存空间申请空间的过程,而指针变量存储的是变量的内存地址。这个地址可以是任何类型的数据,包括整数、浮点数、结构体等,我们也可以通过指针访问我们的内存空间,我们观察下面的代码

#include <stdio.h>
int main() {

	int a = 0;
	int* pa = &a;
	printf("%p\n", pa);

	return 0;
}

在这里插入图片描述
这里我们声明了一个变量 a ,并且声明了一个指针变量 pa 储存变量 a 的地址,至于取地址符号& 与 解引用符号 * 我已经在操作符详解里面讲过了


三、指针变量的类型

指针变量是用很多类型的,比如上面的代码的指针变量是整形指针变量,指针还有char* 、double*、float*等等

指针类型多种的意义: 为指针的解引用提供依据,给解引用说明按照什么类型解引用
下面我们看两段代码

//代码1
#include <stdio.h>
	int main(){
		int n = 0x11223344;
		int *pi = &n;
		*pi = 0;
	return 0;
}

在这里插入图片描述
在这里插入图片描述
下面我们看代码二

#include <stdio.h>
int main() {
	int n = 0x11223344;
	char* pi = (char*)&n;
	*pi = 0;
	return 0;
}

在这里插入图片描述
在这里插入图片描述
结论: 指针的类型决定了,对指针解引用的时候有多大的权限(一次能操作几个字节)。
比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。

※ void 类型指针(空指针)

在上面我们说过,指针解引用时会根据指针的类型对指针指向的内存进行解读,但是对于 void 类型的指针是无法解引用的,因为 void 指针的类型为空,指针解引用不知道如何去读这一段内存,所以 void 类型的指针只能当作一个零时的指针拷贝,也就是保存指针的变量,如下面的代码

#include <stdio.h>
int main() {
	int n = 0x11223344;
	int* pi = &n;
	void* tmpp = pi;
	
	int* pa = (int*)tmpp;
	printf("%d\n", *pa);

	return 0;
}

在这里插入图片描述
这里的代码,tmpp为一个空指针类型,它存储了 n 的内存地址,并且把这个地址赋值给了 pa ,这时 pa 、pi 都指向 n 的内存地址
void 指针(空指针)无法直接解引用,编译器会报错


四、指针的运算

指针是一个变量,存储的是一个地址,是十六进制的数值,它也可以进行运算,下面我们看一段代码及运行结果
指针只能进行 +、-、比较 三种运算

#include <stdio.h>
int main() {
	int n = 0;
	char a = '0';
	int* pn = &n;
	char* pa = &a;

	printf("pn-> %p\n", pn);
	printf("pa-> %p\n", pa);
	printf("pn + 1-> %p\n", pn + 1);
	printf("pa + 1-> %p\n", pa + 1);
	
	return 0;
}

在这里插入图片描述
下面是运行结果
pn-> 0000006AA94FF634
pa-> 0000006AA94FF654
pn + 1-> 0000006AA94FF638
pa + 1-> 0000006AA94FF655
我们可以发现对于整数型指针变量 pn 加 1 后它的地址向后偏移了 4,而对于字符型指针变量 pa 加 1 后,它的地址向后偏移了 1 ,4 与 1 是地址便宜的字节量,int整数型变量大小为4个字节,而char字符型数据大小为1个字节,也就说,指针类型的不同决定着指针运算时的步幅大小


五、野指针

概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

野指针有三种成因: 指针未初始化、指针越界访问、指针指向的空间释放

指针未初始化

#include <stdio.h>
int main() {
	int* p; //此时p为野指针
	int a = 10;
	p = &a;

	return 0;
}

指针越界访问

#include <stdio.h>
int main()
{
	int arr[10] = {0};
	int *p = &arr[0];
	int i = 0;
	for(i=0; i<=11; i++)
	{
		//当指针指向的范围超出数组arr的范围时,p就是野指针
		*(p++) = i;
	}
	return 0;
}

指针指向的空间释放

#include <stdio.h>
int main() {
	int* pn = (int*)malloc(sizeof(int));
	assert(pn);
	free(pn);

	return 0;
}

避免野指针的出现需要避免出现这些错误!


六、二级指针及多级指针

我们知道指针是一个变量,指针存放着其他变量的内存地址,也正是因为指针是一个变量,所以在内存中也有着相应的内存地址存放着指针变量,当我们用指针指向另一个指针的内存地址时,这个指针就称为二级指针,同理,若是我们有一个指针指向二级指针的地址时,这个指针就称为三级指针,以此类推,下面我们举例说明

#include <stdio.h>
int main() {
	int a = 0;
	int* pa = &a;//一级指针
	int** ppa = &pa;//二级指针
	int*** pppa = &ppa;//三级指针

	return 0;
}

多级指针的命名

从上面的代码中,我们也可以看出多级指针是如何命名的,类型*(N),多少级指针后面就跟多少个*号


End

好了,对于基本的指针知识就介绍到这里,后面我还会写其他有关指针的文章,希望这篇文章对你有帮助!谢谢你的阅读!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值