指针初阶_C语言

1.什么是指针

1.1 指针是什么?

指针是一个变量,我们称之为指针变量,指针的本质就是地址,因为一个指针变量中存放的就是地址。

1.2 内存和地址

既然指针存放的是地址,那么地址是什么呢?我们都知道在现实中,可以通过地址找到一个人的住所。而在程序中也是一样的,我们想要找到一块特定的空间,必须要知道它的地址。就像门牌号一样,一个地址对应一个房间。在内存中也是,一个地址对应一块空间。而指针存放的就是这块空间的地址。

2.指针的定义及解引用

2.1 如何定义一个指针?

既然我们都知道,指针存放的是地址,那么我们应该给指针赋值一个地址,我们可以用操作符&取出一个变量的地址。 如果指针存放的是一个整形的地址,那我们 就用int* 来定义它,如果存放的是一个字符的地址,那么我们用 char* 定义它

int main()
{
	int a = 10; //a
	int* p = &a; //整形指针的定义
	
	char ch = 'a';
	char* a = &ch; //字符指针的定义
	
	float f = 10.0;
	float* pf = &f; //浮点数指针
	return 0;
}

定义了指针之后,那我们再用%p 打印它们的地址
在这里插入图片描述
我们发现指针p存的地址,就是a在内存中的地址

2.2 指针如何使用?

我们现在知道指针存放的是内存地址,那我们怎么使用指针呢?这时候我们就要用到一个操作符 ‘*’,它看起来和乘号是一样的。但是意义是不同的 , *是双目操作符的时候表示乘法,作单目操作符的时候表示 “间接引用操作符”


int main()
{
	int a = 10;
	int b = 20;
	int c = a * b; // * 作双目操作符,乘法
	int* pa = &a;
	*pa;//* 作单目操作符,表示间接引用
	return 0;
}

分清楚了它们的区别之后,那么 间接引用操作符有什么用呢?我们打印 *pa看看效果。

在这里插入图片描述
这时候我们就可以发现,它打印了10,而a的值也是10。这会不会是巧合呢,我们把a的值改成100,再打印试试。
在这里插入图片描述
此时a = 100, *pa的值还是100,那我们可以得出结论,间接引用操作符 可以直接通过地址访问这个地址所对应的空间。 那我们可以修改 *pa的值吗?我们改成200再打印看看。
在这里插入图片描述

结论:
1.指针存放的是一个内存地址
2.我们可以通过指针解引用访问指向空间的值
3.我们可以通过指针解引用修改指向空间的值

3.指针之间的运算

3.1 指针+1

那么之间之间可以进行运算吗?答案是当然可以 。我们让一个指针+1,然后看看它们的地址。

int main()
{
	int a = 10;
	int* pa = &a;
	printf("%p\n",pa);
	printf("%p\n", pa+1);
	printf("%p\n", pa+2);
	return 0;
}

在这里插入图片描述
我们会发现,指针 +1 ,地址跳动了四个字节,那 我们把指针 int类型改成char * 呢?
在这里插入图片描述
我们会发现,此时指针+1,地址往后跳了一个字节。 所以指针的类型 决定了指针访问内存的权限。 char
类型的指针向后访问一个字节。 int* 类型的指针向后访问四个字节

3.2 指针相减

我们现在知道指针+1是根据指针的类型决定访问多少个字节。那么指针相减呢?我们先创建一个数组。因为数组名是数组首元素的地址。所以我们根据 : 数组名+数组的长度-1 = 数组最后一个元素的地址


int main()
{
	int arr[] = { 1,2,3,4,5 };
	int* p1 = arr;
	int* p2 = arr + 4;
	printf("%d\n",p2-p1);

	return 0;
}

在这里插入图片描述
我们会发现,数组最后一个元素的地址减去首元素的地址,等于它们之间的元素个数。而不是相差的字节个数。
更准确来说,指针-指针的绝对值是它们之间的元素个数
在这里插入图片描述

结论:
1.指针+1,加的是类型大小
2.指针相减的绝对值是指针与指针之间的元素个数

4.二级指针

我们上面说的都是 一级指针,一个指针指向一个变量的内存地址,那么这个指针本身也有地址。因为指针也是个变量,是变量就有地址。有地址就是可以用指针来存储。所以,当一级指针的地址被一个指针指向时,那么这个指针就是二级指针。

指向一级指针的指针就是二级指针

int main()
{
	int a = 10;
	int* pa = &a; // pa 指向 a,指向的类型是int
	int** ppa = &pa;//ppa 指向 pa的地址,指向的类型是int*
	return 0;
}

让我们分别打印一下 pa 和ppa的地址
在这里插入图片描述
我们可以这样理解,pa 指向的是a的地址,所以第一行其实就是a的地址,ppa 指向的是pa这个指针的地址。所以第二行是pa的地址,因为指针变量是个变量,它也有属于自己的空间,在内存中存在,那么就一定会有其对应的地址。

简单来说就是,套娃,三级指针也是一样的道理,指向二级指针的指针就是三级指针。

5.未初始化的非法指针

我们先来看看下面这个代码。

int main()
{
	int* a;
	*a = 20;
	return 0;
}

我们可以看到创建一个 int*类型的指针,但是没有初始化,所以没法预料到 20 这个值会存储到什么地方。 从这一点看,指针变量和其他变量没有什么区别。局部变量未初始化的值是随机值,而全局变量未初始化是0。更严重的问题是,如果这个指针随机到了一个合法的地址,那么就会改变这个值,这是非常危险的操作。

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值