自学内容网 自学内容网

(C语言)深入理解指针1基础

指针是C语言中的一个难点,但如果真正理解了指针,其实没有很难,本篇文章介绍了指针的基础知识,后面还会继续更行指针的内容。感谢支持。

目录

1. 内存和地址

1.1 内存

1.2 究竟该如何理解编址

2. 指针变量和地址

2.1 取地址操作符(&)

2.2 指针变量和解引⽤操作符(*)

2.2.1 指针变量

2.2.2 如何拆解指针类型

2.2.3 解引⽤操作符

2.3 指针变量的⼤⼩

3. 指针变量类型的意义

3.1 指针的解引⽤

3.2 指针+-整数

3.3 void* 指针

4. const修饰指针

4.1 const修饰变量

4.2 const修饰指针变量

5. 指针运算

5.1 指针+- 整数

5.2 指针-指针

5.3 指针的关系运算


1. 内存和地址

1.1 内存

CPU( 中央处理器) 在处理数据的时候 ,需要的数据是在内存中读取的 ,处理后的数   据也会放回内存中 ,那我们买电脑的时候  电脑上内存是8GB/16GB/32GB等 内存划分为一个个的内存单元 ,每个内存单元的大小取1个字节,方便高效管理。

计算机中常见的单位

其实每个内存单元都有自己的唯一确定的编号,通过这个编号,CPU就可以快速,找到对应的内存空间,这个编号也就是地址,在C语言中也有一个名字叫作:地址。

我们可以理解为:内存单元的编号==地址==指针

1.2 究竟该如何理解编址

CPU访问内存中的某个字节空间 ,必须知道这个 字节空间在内存的什么位置 ,而因为内存中字节很多 ,所以需要给内存进行编址(就如同宿舍很 ,需要给宿舍编号一样)。

计算机中的编址 ,并不是把每个字节的地址记录 下来 ,而是通过硬件设计完成的。

首先 ,必须理解 ,计算机内是有很多硬件单元,而硬件单元是要互相协同工作的。所谓的协 ,至少相互之间要能够进行数据传递。

但是硬件与硬件之间是互相独立的 ,那么如何通信呢?答案很简单 ,用"线"连起来。

而CPU和内存之间也是有大量的数据交互的 ,所 ,两者必须也用线连起来。

不过 ,我们今天关心一组线 ,叫做地址总线

我们可以简单理解,32位机器有32根地址总线,每根线只有两态 ,表示0或1【电脉冲有无】 ,那么一根线 ,就能表示2种含义 ,2根线就能表示4种含  ,依次类推。32根地址线 ,就能表示2^32种含   ,每一种含义都代表一个地址。

地址信息被下达给内存 ,在内存上 ,就可以找到该地址对应的数据 ,将数据在通过数据总线传入 CPU内寄存器。

2. 指针变量和地址

2.1 取地址操作符(&)

理解了内存和地址的关系,我们再回到C语⾔,在C语⾔中创建变量其实就是向内存申请空间,

我们知道C语言中一个整形占4个字节,创建时会向内存申请4字节的空间,当取整形变量的地址时会取出4个字节地址的第一个地址,因为知道是int类型,当需要这个变量时就能顺藤摸瓜,将这4个字节全部访问。

2.2 指针变量和解引⽤操作符(*)

2.2.1 指针变量

在这里p就是指针变量,int*是指针变量类型,p变量里存放的是变量a的地址。

2.2.2 如何拆解指针类型

其实int* p理解为:int是p指针变量所指向的变量的类型。

              *理解为:告诉我们p是指针变量。

              p理解为:指针变量的名字。

如果是char类型的数据:

2.2.3 解引⽤操作符

我们得到了一个变量的地址,将他存在了一个指针变量中,我们这样做有什么用呢?

我们可以通过地址找到这个地址所指向的变量。来操作,改变它。我们必须要用到解引用操作符:*。

*pa=0;相当于通过pa中存放的地址找到了这个a变量,并把a赋值为0;

我们因为可以看到打印a与打印*pa的结果是一样的。

2.3 指针变量的⼤⼩

前⾯的内容我们了解到,32位机器假设有32根地址总线,每根地址线出来的电信号转换成数字信号后是1或者0,那我们把32根地址线产⽣的2进制序列当做⼀个地址,那么⼀个地址就是32个bit位,需要4个字节才能存储。
如果指针变量是⽤来存放地址的,那么指针变的⼤⼩就得是4个字节的空间才可以。
同理64位机器,假设有64根地址线,⼀个地址就是64个⼆进制位组成的⼆进制序列,存储起来就需要8个字节的空间,指针变的⼤⼩就是8个字节。

我们可以分别看一下在X86(32位)和X64(64位)下打印地址大小的结果:

32位下的结果:

64位下的结果:

可以看到在同一环境下不同类型的地址所占内存的大小是相同的,也就是说地址无贵贱,所占内存大小都遵循下面的规律:

32位平台下地址是32个bit位,指针变量⼤⼩是4个字节
64位平台下地址是64个bit位,指针变量⼤⼩是8个字节
注意指针变量的⼤⼩和类型是⽆关的,只要指针类型的变量,在相同的平台下,⼤⼩都是相同的。

3. 指针变量类型的意义

3.1 指针的解引⽤

代码一:

代码二:

代码一是将int*类型强制类型转变成了char*类型,解引用时只访问了一个字节将44变成了00

而代码二int*类型的pi解引用访问了四个字节,将n全变为0;

结论:指针的类型决定了,对指针解引⽤的时候有多⼤的权限(⼀次能操作⼏个字节)。
⽐如: char* 的指针解引⽤就只能访问⼀个字节,⽽ int* 的指针的解引⽤就能访问四个字节。

3.2 指针+-整数

我们可以看出, char* 类型的指针变量+1跳过1个字节, int* 类型的指针变量+1跳过了4个字节。
这就是指针变量的类型差异带来的变化。
结论:指针的类型决定了指针向前或者向后⾛⼀步有多⼤(距离)。

3.3 void* 指针

在指针类型中有⼀种特殊的类型是 void* 类型的,可以理解为⽆具体类型的指针(或者叫泛型指
针),这种类型的指针可以⽤来接受任意类型地址。但是也有局限性, void* 类型的指针不能直接进⾏指针的+-整数和解引⽤的运算。
举例:
将⼀个int类型的变量的地址赋值给⼀个char*类型的指针变量。编译器给出了⼀个警
告,是因为类型不兼容。⽽使⽤void*类型就不会有这样的问题。
但是void*并不是万能的:
这⾥我们可以看到, void* 类型的指针可以接收不同类型的地址,但是⽆法直接进⾏指针运算。
那么 void* 类型的指针到底有什么⽤呢?这里有一篇博客可以参考,使用在了函数传参上面
(C语言)qsort函数模拟实现: http://t.csdnimg.cn/FMB3k

4. const修饰指针

4.1 const修饰变量

变量是可以修改的,如果把变量的地址交给⼀个指针变量,通过指针变量的也可以修改这个变量。
但是如果我们希望⼀个变量加上⼀些限制,不能被修改,怎么做呢?这就是const的作⽤
上面代码中m被const修饰了不能再被修改了,
但是如果我们绕过m直接通过地址去修改m也是可以的。
我们可以看到这⾥⼀个确实修改了,但是我们还是要思考⼀下,为什么m要被const修饰呢?就是为了不能被修改,如果p拿到m的地址就能修改m,这样就打破了const的限制,这和我们的想法是不一样的,所以应该让p拿到m的地址也不能修改m,那接下来怎么做呢?

4.2 const修饰指针变量

总结: const修饰指针变量的时候
const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。
但是指针变量本⾝的内容可变。
const如果放在*的右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指
向的内容,可以通过指针改变。

5. 指针运算

指针的基本运算有三种,分别是:
指针+- 整数
指针-指针
指针的关系运算

5.1 指针+- 整数

因为数组在内存中是连续存放的,只要知道第⼀个元素的地址,顺藤摸⽠就能找到后⾯的所有元素。
我们通过运用地址访问了数组中所有的元素,并打印出来。

5.2 指针-指针

5.3 指针的关系运算

C语言中指针的知识多而复杂,可能有的地方写的不明白,欢迎在评论区讨论。
感谢观看,感谢指正错误。

原文地址:https://blog.csdn.net/2301_81224771/article/details/136502781

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!