C语言中令无数人谈指色变的指针!了解指针(比较详细)

在学习的过程中,把学到的知识写出来一篇博客,可以帮助我们融会贯通,对知识更了解,记忆更深刻。

1.内存和地址

1.1内存

首先,什么是内存和地址?我们可以用生活中的案例来形象说明一下:

比如说一个楼房,我们知道楼房有许多房间,当我们要去别人家的时候,如果说房间没有门牌号,那我们就需要一个房间一个房间的去找,但是这样效率非常低,所以在现实生活中,我们给每个房间都标有门牌号,比如说101,102,301,603,808等等像这样的门牌号,然后我们知道门牌号之后,那我们寻找别人家的房间就会非常快,因为我们知道门牌号就不需要一个一个去找去敲门,而是只看门牌号就知道是那个房间,我们可以直奔我们知道门牌号的那个房间,找到那个房间,就能找到那个人,这样效率就会非常快。

如果把上面的例子对找到计算机中,又是怎末样的呢?

我们知道计算机上cpu(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数据又会放回在内存中,买电脑的时候,电脑上的内存一般是8GB/16GB/32GB等,这些内存能存储非常大的信息,这就不得不让我们对内存进行高效的管理。

我们是把内存划分为一个一个的单元,每个单元的大小是一个字节(1Byte),内存中最小的单位是1bit,1Byte=8bit,1KB=1024Byte,1MB=1024KB,1GB=1024MB,1TB=1024GB,1PB=1024TB等等.....如图所示:

其实,每个内存单元就相当于一个房间,大小是一个字节,每个房间里边里边能放8个bit位,就相当于八个人,每个内存单元都有一个编号,这个编号就相当于房间的门牌号,有了这个内存单元的编号,cpu就可以快速找到一个内存空间。                        生活中,我们就把房间的门牌号叫做地址,计算机中,也把内存单元的编号叫做地址,C语言中给地址取了个名字,叫做:指针    所以可以这样理解:内存单元的编号==地址==指针。就是0XFFFFFFF这样的内存单元编号叫做地址也叫做指针。

2.指针变量和地址

2.1 取地址操作符(&)

C语言中创建变量,本质上就是向内存申请空间。而取地址操作符&可以取到所创建变量的地址

这里int类型的数据所占用的内存空间是四个字节,我们取地址取到的地址是他第一个字节的地址,因为内存中数据的存储是一段连续的空间,所以我们就可以顺藤摸瓜找到他全部的四个字节。

2.2 指针变量

神魔是指针变量呢?我们看一段代码:

我们&a,取出来a的地址,如果想要存储起来,以便于后期我们使用他,就需要创建一个变量,就像图中的p,p里边存储了a的地址,所以我们使用p就可以通过p里边存储的a的地址去找到a,而前边我们说过地址就是指针,指针就是地址,所以p就是存放地址的,也可以说成是存放指针的,那p就可以称为指针变量(也就是存放指针的变量)。int* 就是p的指针类型。int a是一个整型变量用来存储10这个整形,那int*p就是一个指针变量,用来存储a的地址。

2.3 指针类型

我们看到p的类型是int *,注意这里int*合起来是一个完整的类型。

那如何理解int*呢?

我们可以看到,前边创建了一个变量a,里边存放的是10,是int类型的数据,0X0012FF40就是他第一个字节的地址,我们对a取地址之后放在了指针变量p里边,p里边存放的就是a的地址,也可以说p指向了a,而a是int类型的变量,所以,int*我们分开理解,*说明p是一个指针变量,而他指向的对象是int类型,所以p的指针类型就是int*类型。同理,如果创建一个变量char b='w',然后我们创建一个指针变量pa用来存储char类型b变量的地址,那么就应该写成char*pa=&b。

2.4 解引用操作符

解引用操作符也叫间接访问操作符。

解引用操作符如何使用呢?

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	int a = 10;
	&a;
	//这个p就是指针变量 int*就是他的指针类型
	int* p = &a;
//这个*号就是解引用操作符
	*p=20;
	printf("%d", a);
}

通过解引用操作符可以解引用p存放的地址直接找到a,从而修改a。

2.5 指针变量的大小

指针变量存放的是地址,地址的存放需要多大的空间呢?指针变量的大小取决于是32位还是64位,32位的话一个地址是32个bit位,所以需要4个字节存储,64位的话一个地址是64个bit位,所以需要8个字节存储。

我们可以看到,再x86平台下也就是32位,一个指针变量所需要的内存是4个字节。

在x64平台下也就是64位,一个指针变量所需要的内存空间是8个字节。

注意,指针变量的大小和类型是无关的,任何类型的指针变量的大小在相同的平台下大小是相同的。

3.指针变量类型的意义

3.1 指针的解引用

先看图:

这里我们发现,int*类型的指针会把a的四个字节全部改为0.

这里我们发现,char*类型的指针会把a的第一个字节改为0.

结论:指针的类型决定了,对指针解引用的时候有多大的权限(可以访问多少个字节),int*指针可以访问4个字节,char*指针可以访问一个字节,short*指针可以访问两个字节。所以指针的类型是非常重要的,决定了未来在访问内存的时候要选择什么样的指针类型。

3.2 指针+-整数

还是废话不多说,先看图:

我们可以发现,int*类型的指针pa+1之后直接跳过了四个字节,而char*类型的指针pb+1后跳过了一个字节,如下图:

结论:指针加减整数跳过的字节数取决于它的指针类型,也就是指针类型决定了指针加减一个数后所走的距离。当然不是只能+1,如果是int*pa,pa+n那就是pa+(n乘sizeof(int)),同理其他的也可以推出来。

3.2 void*指针

void是无,空的意思,所以void*类型的指针就是无具体类型的指针,也叫泛型指针,是一种特殊类型的指针,这种指针变量的作用是可以接收任意类型的地址。

图中我们把int 类型的数据放在一个char*类型的指针中,编译器会报警告,因为类型不一样,这时候我们就可以用void*类型的指针来接收。

当然,void*的指针不能直接使用,需要进行强制类型转换来使用,一般void*指针用途是别人给你传一个指针,而你不知道指针类型,就先用void*指针接收,然后使用的时候把他强制转换成自己想要使用的类型,这里是对void*指针进行简单的解释,后边还会深挖,不在这篇博客里做过多介绍。 

 4.const修饰指针

4.1 const修饰变量

首先,我们要知道变量就是可以改变的量,就叫做变量。比如说int a=0; a=20;通过这段代码,a的值就变成20了,这个a就叫做变量。那const是什莫呢?

const:常属性,被const修饰之后,就拥有常属性,就无法修改了。

1.const修饰普通变量,但是用const修饰普通变量之后,我们通过指针还是可以修改,所以就有const修饰指针变量。const int a=0;这里a就无法修改了,但是这个a不是常量,在C语言中,这里的a被const修改后是常变量,编译器在语法上不允许修改a,但是本质上还是变量。在C++语言中,这个a就是常量,这也是语言之间的区别。这里的a我们还是可以通过指针来修改,所以这里的a不是常量,而是常变量。但是这样就违背了我们用const修饰a的初衷,我们本意是不想让a被修改,但是通过指针还是可以修改。

所以有了const修饰指针变量。

2.const修饰指针变量

const可以放在*左边,也就是const int*p,如果const放在*左边,就表示指针指向的内容不能通过指针来改变了,const放在*左边,那么限制的就是*p,*p不能改变,但是p本身可以改,也就是p的指向可以改,可以让他指向另一个内存地址。

const也可以放在*右边,也就是int *const p,如果放在*右边,那么*p的内容可以改,就是指针指向的内存里边存储的数据可以改,但是指针指向的地址不能更改了。也就是限制了p本身。

const也可以同时放在*左边和右边,也就是const int * const p,这样的话*p不能改变,p本身也不能改变。

这里确实在我学习的时候也有点晦涩难懂,但是在通过反复思考后发现其实也是很简单的问题,所以建议反复咀嚼,反复思考,书读百遍,其意自现。

5.指针运算

5.1 指针+-整数

指针+1整数在上边有提到过,这里是讲如何应用。

如何用指针来打印一个数组的每个元素呢?

我们可以看到,首先我们先让指针指向数组首元素的地址,然后因为是int*类型的指针,所以每次+1会跳过一个整形,那以此类推,我们就可以让指针以此指向数组的每个元素。代码如下:

int main()
{
    int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
	int* p = &arr[0];
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", *(p + i));
	}
}

5.2 指针-指针

指针-指针其实就是地址-地址。指针-指针得到的是两个指针之间的元素个数,并且他有大地址和小地址之分,大地址减小地址得到的是正数,小地址减去大地址得到的是负数。当然,指针-指针这种运算前提条件是两个指针指向同一块空间。如图:

这是指针知识的一部分,如果能对您有所帮助,这是我的荣幸!

  • 18
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值