news 2026/4/18 5:43:51

第11讲:深入理解指针(一)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第11讲:深入理解指针(一)

目录:

1.内存和地址
2.指针变量和地址
3.指针变量类型的意义
4.指针运算
———————————————————————————————————————————

1.内存和地址

1.1内存

我们知道计算机上CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数据也会放回内存中,那我们买电脑的时候,电脑上内存是 8GB/16GB/32GB 等,那这些内存空间如何高效的管理呢?

其实也是把内存划分为⼀个个的内存单元,每个内存单元的大小取1个字节。
计算机中常见的单位(补充):
⼀个比特位可以存储⼀个2进制的位1或者0
1Byte = 8bit 1KB = 1024Byte 1MB = 1024KB 1GB = 1024MB 1TB = 1024GB 1PB = 1024TB
其中,每个内存单元,相当于⼀个学生宿舍,⼀个字节空间里面能放8个比特位,就好比同学们住
的八人间,每个人是⼀个比特位。
每个内存单元也都有⼀个编号(这个编号就相当于宿舍房间的门牌号),有了这个内存单元的编
号,CPU就可以快速找到⼀个内存空间。
生活中我们把门牌号也叫地址,在计算机中我们把内存单元的编号也称为地址。C语言中给地址起
了新的名字叫:指针。

1.2究竟该如何理解编址

CPU访问内存中的某个字节空间,必须知道这个字节空间在内存的什么位置,而因为内存中字节
很多,所以需要给内存进行编址(就如同宿舍很多,需要给宿舍编号⼀样)。
计算机中的编址,并不是把每个字节的地址记录下来,而是通过硬件设计完成的。

2.指针变量和地址

2.1取地址操作符(&)

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

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

这样就可以打印出a的地址,&a取出的是a所占4个字节中地址较小的字节的地址。

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

2.2.1指针变量
那我们通过取地址操作符(&)拿到的地址是⼀个数值,比如:0x006FFD70,这个数值有时候也是需要存储起来,方便后期再使用的,那我们把这样的地址值存放在哪里呢?答案是:指针变量中。
例:
#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,ch的地址,要放在什么类型的指针变量中呢?

char ch = 'w'; char* pc = &ch; // pc 是指向 char 类型的指针
2.2.3解引用操作符
C语言中其实也是⼀样的,我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针) 指向的对象,这里必须学习⼀个操作符叫解引⽤操作符(*)。
#include <stdio.h> int main() { int a = 100; int* pa = &a; *pa = 0; return 0; }
上面代码中第7行就使用了解引用操作符,*pa就是通过pa中存放的地址,找到指向的空间, *pa其实就是a变量了;所以*pa = 0,这个操作符是把a改成了0。
但这里如果目的就是把a改成0的话,写成a = 0;不就完了,为啥非要使用指针呢?
其实这里是把a的修改交给了pa来操作,这样对a的修改,就多了⼀种的途径,写代码就会更加灵活,后期就能理解了。

2.3指针变量的大小

如果指针变量是用来存放地址的,那么指针变量的大小就得是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位操作系统下运行结果 64位操作系统下运行结果
结论:

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

3.指针变量类型的意义

3.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个字节。
(int跳过一个整形变量所以是四个字节)
结论:指针的类型决定了指针向前或者向后走⼀步有多大(距离)

3.3void* 指针

在指针类型中有⼀种特殊的类型是void * 类型的,可以理解为无具体类型的指针,

void*类型的指针不能直接进行指针的+ - 整数和解引用的运算。

例:

#include <stdio.h> int main() { int a = 10; int* pa = &a; char* pc = &a; return 0; }
在上⾯的代码中,将⼀个int类型的变量的地址赋值给⼀个char*类型的指针变量。编译器给出了⼀个警告(如下图),是因为类型不兼容。而使用void*类型不会出现这样的问题。
使用void*类型的指针接收地址:
#include <stdio.h> int main() { int a = 10; void* pa = &a; void* pc = &a; *pa = 10; *pc = 0; return 0; }
通过编译我们可以看到,void*类型的指针可以接收不同类型的地址,但是无法直接进行指针运算。
⼀般void*类型的指针是使用在函数参数的部分,来接收不同类型数据的地址,可以实现泛型编程的效果。使得⼀个函数来处理多种类型的数据,在后文中会深入理解。

4.指针运算

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

4.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') p++; return p - s; } int main() { printf("%d\n", my_strlen("abc")); 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; }

———————————————————————————————————————————

JohnWick

2026.1.19

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/13 15:54:01

一键启动通义千问2.5-0.5B:Docker快速部署指南

一键启动通义千问2.5-0.5B&#xff1a;Docker快速部署指南 1. 引言 随着大语言模型在边缘设备上的应用需求不断增长&#xff0c;轻量级、高性能的小参数模型正成为开发者关注的焦点。Qwen2.5-0.5B-Instruct 作为阿里 Qwen2.5 系列中最小的指令微调模型&#xff0c;仅约 5 亿参…

作者头像 李华
网站建设 2026/4/16 21:20:16

NewBie-image-Exp0.1跨平台攻略:iPad+云端GPU移动创作方案

NewBie-image-Exp0.1跨平台攻略&#xff1a;iPad云端GPU移动创作方案 你是不是也经常在iPad上用Procreate画得正起劲&#xff0c;突然想给角色换个风格、加个特效&#xff0c;或者生成一个全新的背景场景&#xff1f;但手绘太耗时间&#xff0c;AI工具又大多只能在电脑上跑——…

作者头像 李华
网站建设 2026/4/16 15:40:54

Gopher360:3分钟用手柄掌控电脑的免费神器

Gopher360&#xff1a;3分钟用手柄掌控电脑的免费神器 【免费下载链接】Gopher360 Gopher360 is a free zero-config app that instantly turns your Xbox 360, Xbox One, or even DualShock controller into a mouse and keyboard. Just download, run, and relax. 项目地址…

作者头像 李华
网站建设 2026/4/15 12:04:27

亲测gpt-oss-20b-WEBUI,网页推理效果超出预期

亲测gpt-oss-20b-WEBUI&#xff0c;网页推理效果超出预期 在当前大模型技术快速演进的背景下&#xff0c;如何以低成本、高效率的方式实现本地化AI推理&#xff0c;成为开发者和企业关注的核心问题。闭源模型虽功能强大&#xff0c;但存在API费用高、数据外泄风险等问题&#…

作者头像 李华
网站建设 2026/3/21 16:14:05

高速PCB设计中信号完整性的深度剖析

高速PCB设计&#xff1a;当信号开始“打架”&#xff0c;我们该如何驯服它&#xff1f;你有没有遇到过这样的情况——电路板焊接完毕&#xff0c;上电后功能看似正常&#xff0c;但高速数据传输时误码频发&#xff0c;示波器一抓眼图&#xff0c;满屏振铃、毛刺横飞&#xff1f…

作者头像 李华
网站建设 2026/4/11 5:31:59

Mac菜单栏终极整理方案:用Ice打造清爽高效的工作空间

Mac菜单栏终极整理方案&#xff1a;用Ice打造清爽高效的工作空间 【免费下载链接】Ice Powerful menu bar manager for macOS 项目地址: https://gitcode.com/GitHub_Trending/ice/Ice 你是否曾经因为Mac菜单栏上拥挤不堪的图标而感到困扰&#xff1f;Wi-Fi信号、电池状…

作者头像 李华