当前位置: 首页 > news >正文

深入理解指针(一)

1.内存和地址

2.指针变量和地址

3.指针变量类型的意义

4.指针运算


1. 内存和地址

1.1 内存

在讲内存和地址之前,为了大家更好的理解举了这么个例子:

假如有一栋教学楼,刚好你今天在这栋楼的某一个课室上课,已知这栋楼有50个课室,但是没有编号,你的舍友来找你拿宿舍门钥匙, 如果想找到你,就得挨个教室去找,这样效率很低,但是我们如果根据楼层和楼层的教室的情况,给每个房间编上号,如:

一楼:101,102,103......

二楼:201,202,203......

. . . . . . . . . . . . . . . . . .

有了教室号,你的舍友知道你在那一间教室上课,就可以快速的找到你且拿到宿舍钥匙。生活中,给每个房间编写编号,就能提高效率,能快速地找到你想要找的房间位置。 

 

如果把上面的例子对照到计算机中,又是怎么样呢? 我们知道计算机上CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数据也会放回内存中,那我们买电脑的时候,电脑上内存是 8GB/16GB/32GB 等,那这些内存空间如 何⾼效的管理呢? 其实也是把内存划分为⼀个个的内存单元,每个内存单元的大小取1个字节。 计算机中常见的单位(补充): ⼀个比特位可以存储⼀个2进制的位1或者0

内存单位:

  1. bit - 比特位
  2. Byte - 字节
  3. KB
  4. MB
  5. GB
  6. TB
  7. PB

 

 

  1. 1Byte = 8bit
  2. 1KB = 1024Byte
  3. 1MB = 1024KB
  4. 1GB = 1024MB
  5. 1TB = 1024GB
  6. 1PB = 1024TB

其中,每个内存单元,相当于⼀个教室,⼀个字节空间里面能放 8个比特位,就好比同学们住的八人间,每个人是⼀个比特位。 每个内存单元也都有⼀个编号(这个编号就相当
于宿舍房间的门牌号),有了这个内存单元的编号,CPU就可以快速找到⼀个内存空间。生活中我们把门牌号也叫地址,在计算机中我们 把内存单元的编号也称为地址。C语言中给 地址起了新的名字叫: 指针。 所以我们可以理解为: 内存单元的编号 == 地址 == 指针
1.2 究竟该如何理解编址

首先,必须理解,计算机内是有很多的硬件单 元,而硬件单元是要互相协同工作的。所谓的协同,至少相互之间要能够进行数据传递。但是硬件与硬件之间是互相独立的,那么如何通
信呢?答案很简单,用"线"连起来。而CPU和内存之间也是有⼤量的数据交互的,所以,两者必须也用线连起来。不过,我们今天关心一组线,叫做地址总线。CPU访问内存中的某个字节空间,必须知道这个字节空间在内存的什么位置,而因为内存中字节很多,所以需要给内存进行编址(就如同宿舍很 多,需要给宿舍编号⼀样)。 计算机中的编址,并不是把每个字节的地址记录下来,而是通过硬件设计完成的。钢琴、吉他 上面没有写上“剁、来、咪、发唆、拉、西”这样的信息,但演奏者照样能够准 确找到每⼀个琴弦的每⼀个位置,这是为何?因为制造商已经在乐器硬件层面上设计好了,并且 所有的演奏者都知道。本质是⼀种约定出来的共识

 


 

2. 指针变量和地址 

2.1 取地址操作符(&)

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

#include <stdio.h> 1
int main()
{int a = 10;return 0;
}

比如,上述的代码就是创建了整型变量a,内存中
申请4个字节,⽤于存放整数10,其中每个字节都
有地址,上图中4个字节的地址分别是:
  1. 0x00EEFAE4  0a  
  2. 0x00EEFAE5  00  
  3. 0x00EEFAE6  00  
  4. 0x00EEFAE7  00
那我们如何能得到a的地址呢?
这里就得学习⼀个操作符(&)-取地址操作符

 


#include <stdio.h>
int main()
{int a = 10;&a;//取出a的地址printf("%p\n", &a);return 0;
}

 按照我画图的例子,会打印处理:006FFD70 &a取出的是a所占4个字节中地址较小的字节的地址。虽然整型变量占用4个字节,我们只要知道了第⼀个字节地址,顺藤摸瓜访问到4个字节的数据也是可行的。

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

 

2.2.1 指针变量
那我们通过取地址操作符(&)拿到的地址是⼀个数值,比如:0x00EEFAE4 ,这个数值有时候也是需要存储起来,方便后期再使用的,那我们把这样的地址值存放在哪里呢?答案是:指针变量中。
比如:
#include <stdio.h>
int main()
{int a = 10;int* pa = &a;//取出a的地址并存储到指针变量pa中return 0;
}
指针变量也是⼀种变量,这种变量就是用来存放地址的,存放在指针变量中的值都会理解为地址。
2.2.2 如何拆解指针类型
我们看到pa的类型是 int* ,我们该如何理解指针的类型呢?
int a = 10;
int * pa = &a;
这里pa左边写的是 int* , * 是在说明pa是指针变量,而前面的 int 是在说明pa指向的是整型(int)
类型的对象。
char ch = 'w';
pc = &ch;//pc 的类型怎么写呢?
2.2.3 解引用操作符
我们将地址保存起来,未来是要使用的,那怎么使用呢?
在现实生活中,我们使用地址要找到⼀个房间,在房间里可以拿去或者存放物品。
C语言中其实也是⼀样的,我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针) 指向的对象,这里·必须学习⼀个操作符叫解引用操作符(*)。
#include <stdio.h>
int main()
{int a = 100;int* pa = &a;*pa = 0;return 0;
}
上面代码中第6行就使用了解引用操作符, *pa 的意思就是通过pa中存放的地址,找到指向的空间, *pa其实就是a变量了;所以*pa = 0,这个操作符是把a改成了0。有同学肯定在想,这里如果目的就是把a改成0的话,写成 a = 0; 不就完了,为啥非要使用指针呢? 其实这里是把a的修改交给了pa来操作,这样对a的修改,就多了⼀种的途径,写代码就会更加灵活, 后期慢慢就能理解了。

 

2.3 指针变量的大小

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

#include <stdio.h>
//指针变量的⼤⼩取决于地址的⼤⼩
//32位平台下地址是32个bit位(即4个字节)
//64位平台下地址是64个bit位(即8个字节)
int main()
{printf("%zd\n", sizeof(char*));printf("%zd\n", sizeof(short*));printf("%zd\n", sizeof(int*));printf("%zd\n", sizeof(double*));return 0;
}

 32位平台下地址是32个bit位(即4个字节):

 

64位平台下地址是64个bit位(即8个字节):

结论:
• 32位平台下地址是32个bit位,指针变量大小是4个字节
• 64位平台下地址是64个bit位,指针变量大小是8个字节
• 注意指针变量的大小和类型是无关的,只要指针类型的变量,在相同的平台下,大小都是相同的。

 

 

3. 指针变量类型的意义

指针变量的大小和类型无关,只要是指针变量,在同⼀个平台下,大小都是⼀样的,为什么还要有各种各样的指针类型呢? 其实指针类型是有特殊意义的,我们接下来继续学习。
3.1 指针的解引用
对比,下面2段代码,主要在调试时观察内存的变化。
代码1:
//代码1
#include <stdio.h>
int main()
{int n = 0x11223344;int* pi = &n;*pi = 0;return 0;
}

代码2:

#include <stdio.h>
int main()
{int n = 0x11223344;char* pc = (char*)&n;*pc = 0;return 0;
}
调试我们可以看到,代码1会将n的4个字节全部改为0,但是代码2只是将n的第⼀个字节改为0。
结论:指针的类型决定了,对指针解引用的时候有多大的权限(⼀次能操作几个字节)。
比如: char* 的指针解引⽤就只能访问⼀个字节,而int* 的指针的解引用就能访问四个字节。

3.2 指针+-整数

先看⼀段代码,调试观察地址的变化。
#include <stdio.h>
int main()
{int n = 10;char* pc = (char*)&n;int* pi = &n;printf("%p\n", &n);printf("%p\n", pc);printf("%p\n", pc + 1);printf("%p\n", pi);printf("%p\n", pi + 1);return 0;
}

运行结果: 

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

 

3.3 void* 指针
在指针类型中有⼀种特殊的类型是 void * 类型的,可以理解为无具体类型的指针(或者叫泛型指
针),这种类型的指针可以用来接受任意类型地址。但是也有局限性,void* 类型的指针不能直接进行指针的+-整数和解引用的运算。

 

例:
#include <stdio.h>
int main()
{int a = 10;int* pa = &a;char* pc = &a;return 0;
}
在上面的代码中,将⼀个int类型的变量的地址赋值给⼀个char*类型的指针变量。编译器给出了⼀个警告,是因为类型不兼容。而使用void*类型就不会有这样的问题, void* 类型的指针可以接收不同类型的地址,但是无法直接进行指针运算。

 


4. 指针运算

指针的基本运算有三种,分别是:
•   指针+- 整数
•    指针-指针
•   指针的关系运算
4.1 指针+整数
因为数组在内存中是连续存放的,只要知道第⼀个元素的地址,顺藤摸瓜就能找到后面的所有元素。
  1. int arr[10] = {1,2,3,4,5,6,7,8,9,10};

 代码:

#include <stdio.h>
//指针+- 整数
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int* p = &arr[0];int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);for (i = 0; i < sz; i++){printf("%d ", *(p + i));//p+i 这⾥就是指针+整数}return 0;
}

运行效果:

  

4.2 指针 - 指针

代码 :

#include <stdio.h>
int my_strlen(char* s)
{char* p = s;while (*p != '\0') //判断没有'\0';p++;return p - s;
}
int main()
{printf("%d\n", my_strlen("abcdef"));//存在'\0'有7个字符。return 0;
}

运行效果:

4.3 指针的关系运算 

代码: 

//指针的关系运算
#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int* p = &arr[0];int sz = sizeof(arr) / sizeof(arr[0]);while (p < arr + sz) //指针的⼤⼩⽐较{printf("%d ", *p);p++;}return 0;
}

 运行效果:


本章学习就到这啦!如果内容对你有用 ,请不忘三连支持一波!!!!

完。

 

相关文章:

  • Ubuntu24.04安装Dify
  • C++开发基础之理解std::condition_variable中的wait与wait_for的区别与使用场景
  • zipkin+micrometer实现链路追踪
  • 在QT中栅格布局里套非栅格布局的布局会出现父布局缩放子布局不跟随的问题
  • 图论学习笔记 3
  • C/C++ 整数类型的长度
  • 一道并发的面试题,控制并发数量
  • Baklib构建AI就绪型知识中台实践
  • Python中列表相关操作
  • PIL库的图像增强函数
  • Docker中部署Alertmanager
  • 从代码学习数学优化算法 - 拉格朗日松弛 Python版
  • 查看数据库占用磁盘空间的方法
  • JAVA面向对象——对象和类的基本语法
  • 第一章走进java世界
  • 数据库实验——备份与恢复
  • JavaScript 深拷贝:从基础到实践的全面指南
  • 2025年- H38-Lc146 --142.环形链表(快慢指针,快2慢1,快1慢1)--Java版
  • 前端流行框架Vue3教程:21. 插槽(3)
  • C语言| 指针变量的初始化
  • 美最高法允许政府撤销委内瑞拉移民临时保护身份,35万人或将被驱逐
  • 外交部副部长马朝旭会见美国新任驻华大使庞德伟
  • 观察|脱欧5年后英欧再办峰会,多项突破性协议意味着什么?
  • 上海国际电影电视节 | 奔赴电影之城,开启光影新程
  • 内塔尼亚胡称将控制“整个加沙”,英、法、加威胁对以“制裁”
  • 藤井树与藤井树:岩井俊二式的爱情,情书的三重生命