程序诗篇里的灵动笔触:指针绘就数据的梦幻蓝图(水文,勿三)
大家好啊,我是小象٩(๑òωó๑)۶
我的博客:Xiao Xiangζั͡ޓއއ
很高兴见到大家,希望能够和大家一起交流学习,共同进步。
这一节我们来学习指针的相关知识,学习内存和地址,指针变量和地址,包括取地址操作符,指针变量和解引用操作符,指针变量类型的意义,指针变量的大小,指针的解引用,指针±整数,void指针
文章目录
- 一、内存和地址
- 1.1 内存
- 1.2 如何理解编址
- 二、指针变量和地址
- 2.1 取地址操作符(&)
- 2.2 指针变量和解引用操作符(*)
- 2.2.1 指针变量
- 2.2.2 如何拆解指针类型
- 2.2.3 解引用操作符
- 2.3 指针变量的大小
- 三、指针变量类型的意义
- 3.1 指针的解引用
- 3.2 指针+-整数
- 3.3 void指针
- 四、结尾
一、内存和地址
1.1 内存
在 C 语言中,内存是程序运行的基础,用于存储程序中的数据和代码。
我们来举一个生活中的例子:假设有⼀栋宿舍楼,把你放在楼里,楼上有100个房间,但是房间没有编号,你的一个朋友来找你玩,如果想找到你,就得挨个房子去找,这样效率很低,但是我们如果根据楼层和楼层的房间的情况,给每个房间编上号,如:
⼀楼:101,102,103...
⼆楼:201,202,203...
...
有了房间号,如果你的朋友得到房间号,就可以快速的找房间,找到你。
同理,我们在买电脑的时候也会发现电脑的内存有8GB、16GB、32GB等,那这些内存空间如何高效的管理呢?其实一样也是把内存划分为一个个的内存单元,每个内存单元的大小取1个字节。
PS:计算机中的常见单位:一个比特位可以存储一个2进制的位1或者0
bit - ⽐特位
Byte - 字节
KB
MB
GB
TB
PB
1Byte = 8bit
1KB = 1024Byte
1MB = 1024KB
1GB = 1024MB
1TB = 1024GB
1PB = 1024TB
其中,每个内存单元,相当于一个学生宿舍,一个字节空间里面能放8个比特位,就好比同学们住的八人间,每个人是一个比特位。每个内存单元也都有一个编号(这个编号就相当于宿舍房间的门牌号),有了这个内存单元的编号,CPU就可以快速找到一个内存空间。生活中我们把门牌号也叫地址,在计算机中我们
把内存单元的编号也称为地址。C语言中给地址起了新的名字叫做:指针。
所以我们可以理解为:
内存单元的编号=地址=指针
1.2 如何理解编址
编址是计算机系统中一个关键的概念,它涉及为计算机中的各种存储单元或设备分配唯一标识符,以便能够对它们进行准确的访问和管理。
CPU访问内存中的某个字节空间,必须知道这个字节空间在内存的什么位置,⽽因为内存中字节很多,所以需要给内存进而编址(就如同宿舍很多,需要给宿舍编号一样)。计算机中的编址,并不是把每个字节的地址记录下来,而是通过硬件设计完成的。钢琴、吉他上面没有写上“剁、来、咪、发、唆、拉、西”这样的信息,但演奏者照样能够准确找到每一个琴弦的每⼀个位置,这是为何?因为制造商已经在乐器硬件层面上设计好了,并且所有的演奏者都知道。本质是一种约定出来的共识!
首先,必须理解,计算机内是有很多的硬件单元,而硬件单元是要互相协工作的。所谓的协同,至少相互之间要能够进行数据传递。但是硬件与硬件之间是互相独立的,那么如何通信呢?答案很简单,用"线"连起来。而CPU和内存之间也是有大量的数据交互的,所以,两者必须也用线连起来。不过,我们今天关心一组线,叫做地址总线。硬件编址也是如此我们可以简单理解,32位机器有32根地址总线,每根线只有两态,表示0,1【电脉冲有无】,那么一根线,就能表示2种含义,2根线就能表示4种含义,依次类推。32根地址线,就能表示2^32种含义,每⼀种含义都代表⼀个地址。地址信息被下达给内存,在内存上,就可以找到该地址对应的数据,将数据在通过数据总线传入CPU内寄存器。
举个例子,如果我们想要访问某个地址,首先控制总线会发出指令,如何根据地址总线找到内存中对应的位置,接着在通过数据总线传递回来。
二、指针变量和地址
2.1 取地址操作符(&)
在 C 语言中,取地址操作符是“&”。它用于获取一个变量的内存地址。例如,如果有一个变量 int a; ,那么 &a 就表示变量 a 的地址。
PS:变量创建的本质其实是:在内存中申请空间,向内存申请4个字节的空间,存放10
比如,上述的代码就是创建了整型变量a,内存中申请4个字节,用于存放整数10,其中每个字节都有地址,上图中4个字节的地址分别是:
0x004FF9D4
0x004FF9D5
0x004FF9D6
0x004FF9D7
那我们如何能得到a的地址呢?
这里就得学习一个操作符(&)——取地址操作符
#include<stdio.h>
int main ()
{int a = 10;printf("%p\n", &a);return 0;
}
注意:&a取出的是a所占4个字节中地址较小的字节的地址。
实际上,地址也是二进制的,只是为了在vs容易表示写成了16进制
虽然整型变量占用4个字节,我们只要知道了第一个字节地址,顺藤摸瓜访问到4个字节的数据也是可行的。
2.2 指针变量和解引用操作符(*)
2.2.1 指针变量
在C语言中,指针变量是一种特殊的变量,它存储的是内存地址,而不是普通的数据值。
我们通过取地址操作符(&)拿到的地址是一个数值,比如:0x004FF9D4,这个数值有时候也是需要存储起来,方便后期再使用的,那我们把这样的地址值存放在哪里呢?答案是:指针变量中。
#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类型的指针变量中。
2.2.3 解引用操作符
在现实生活中,我们使用地址要找到一个房间,在房间里可以拿去或者存放物品。
C语言中其实也是⼀样的,我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针)
指向的对象,这里必须学习一个操作符叫解引用操作符(*)。
解引用操作符用于访问指针所指向的内存位置的值。也就是说,当你有一个指针变量,它存储了某个变量的内存地址,通过解引用操作符,你可以获取或修改该内存地址中存储的值。
举个例子:
#include<stdio.h>
int main()
{int a = 100;int* pa = &a;*pa = 0;return 0;
}
第五行中定义了一个指向整型的指针变量 pa。int* 表示指针的类型,即该指针指向的是一个整型变量。& 是取地址运算符,&a 表示获取变量 a 的内存地址。因此,这行代码将变量 a 的地址赋值给指针 pa,使得 pa 指向了变量 a。
而第六行就有了解引用操作符的使用,*pa 表示访问 pa 所指向的变量,也就是变量 a。这行代码将 0 赋值给 *pa,实际上就是将 0 赋值给变量 a,从而修改了变量 a 的值。
有同学肯定在想,这里如果目的就是把a改成0的话,写成 a = 0;不就完了,为啥非要使用指针呢?
其实这里是把a的修改交给了pa来操作,这样对a的修改,就多了一种的途径,写代码就会更加灵活,
后期慢慢就能理解了。
2.3 指针变量的大小
前面的内容我们了解到,32位机器假设有32根地址总线,每根地址线出来的电信号转换成数字信号后
是1或者0,那我们把32根地址线产生的2进制序列当做一个地址,那么一个地址就是32个bit位,需要4
个字节才能存储。
如果指针变量是用来存放地址的,那么指针变的大小就得是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个字节
• 注意指针变量的大小和类型是无关的,只要指针类型的变量,在相同的平台下,大小都是相同的
三、指针变量类型的意义
指针变量的大小和类型无关,只要是指针变量,在同⼀个平台下,大小都是⼀样的,为什么还要有各
种各样的指针类型呢?
其实指针类型是有特殊意义的,我们接下来继续学习。
3.1 指针的解引用
C 语言指针解引用是通过指针访问其指向内存地址中存储值的操作,使用星号 * 作为解引用操作符。它主要用于访问和修改数据,以及对动态分配的内存进行读写。 代码应用场景包括基本指针解引用、指针与数组结合的解引用和多级指针的解引用。使用时要注意进行空指针检查,避免对 NULL 指针解引用导致程序崩溃,同时防止使用未正确初始化或指向已释放内存的野指针,以免引发未定义行为。
对比下面两段代码:
//代码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 *。它可以指向任意类型的数据,也就是说,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* 类型的指针到底有什么用呢?
一般 void * 类型的指针是使用在函数参数的部分,用来接收不同类型数据的地址,这样的设计可以实现泛型编程的效果,后面我们会继续讲解viod指针。
四、结尾
这一课的内容就到这里了,下节课继续学习操作符的其他一些知识
如果内容有什么问题的话欢迎指正,有什么问题也可以问我!
相关文章:

程序诗篇里的灵动笔触:指针绘就数据的梦幻蓝图(水文,勿三)
大家好啊,我是小象٩(๑ω๑)۶ 我的博客:Xiao Xiangζั͡ޓއއ 很高兴见到大家,希望能够和大家一起交流学习,共同进步。 这一节我们来学习指针的相关知识,学习内存和地址,指针变量和地址,包…...
在 UniApp 中实现中间凸起 TabBar 的完整指南
如何在 UniApp 中设置中间 TabBar 凸起效果 在移动应用开发中,TabBar 是常见的导航组件,而中间凸起的 TabBar 按钮则是一种流行的设计风格,常用于突出重要功能(如发布、拍照等)。UniApp 提供了 midButton 属性&#x…...
Redis大key
Redis大key基本概念,影响 Redis 大 key 指在 Redis 中存储了大量数据的键,它会对 Redis 的性能和内存管理产生影响。 大key的定义与value的大小和元素数量有关,但这个定义并不是绝对的,而是相对的,具体取决于系统的使用…...

WPF高级 | WPF 与数据库交互:连接、查询与数据更新
WPF高级 | WPF 与数据库交互:连接、查询与数据更新 前言一、数据库交互基础概念1.1 数据库简介1.2 数据访问技术 二、WPF 与数据库连接2.1 连接字符串2.2 建立连接 三、WPF 中的数据查询3.1 使用ADO.NET进行数据查询3.2 使用 Entity Framework 进行数据查询3.3 使用…...

CogBlobTool工具
CogBlobTool是一款专用于图像斑点检测于分析的 工具,通过灰度值阈值分割和特征过滤,帮助在复杂背景中提取目标区域,并计算几何属性。 效果图 注意:在这里只有一张图像可以不使用模板匹配工具 CogBlobTool工具的功能 斑点检测于…...

C# WinForm程序中如何调试dll接口
公司的SF系统是自主开发的。不同的机种会有不同数据记录保存的需求,尤其是客户SQE更是各种奇思妙想......于是做了一个接口,实践之下效果还不错呢。 每每总是忘记怎么调试接口,特记录下备查。首先要将, 1 DLL项目与WinForms项目…...
自然语言处理:词频-逆文档频率
介绍 大家好,博主又来给大家分享知识了。本来博主计划完成稠密向量表示的内容分享后,就开启自然语言处理中文本表示的讲解。可在整理分享资料的时候,博主发现还有个知识点,必须得单独拎出来好好说道说道。 这就是TF-IDF…...

【银河麒麟高级服务器操作系统】服务器测试业务耗时问题分析及处理全流程分享
更多银河麒麟操作系统产品及技术讨论,欢迎加入银河麒麟操作系统官方论坛 https://forum.kylinos.cn 了解更多银河麒麟操作系统全新产品,请点击访问 麒麟软件产品专区:https://product.kylinos.cn 开发者专区:https://developer…...

基于大数据的民宿旅馆消费数据分析系统
【大数据】基于大数据的民宿旅馆消费数据分析系统(完整系统源码开发笔记详细部署教程)✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 该系统可以揭示民宿市场的消费模式和价格分布情况,帮助理解消费者偏好、价格走势及…...
Spring-AI搭建企业专属知识库 一
环境介绍:Spring3.3.2 JDK 21 POM文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation&…...

极简本地体验deepseek大模型教程
一 题外随感:时代之问 就像狄更斯在双城记中所述,“这是最好的时代,这是最坏的时代”。每一代人都有其所处的时代,每一个时代都有其所谓好的一面和不那么好的一面。很多时候随口的一句大环境不好,就似乎给了自己一个最…...
RabbitMQ系列(五)基本概念之Queue
在 RabbitMQ 中,Queue(队列) 是存储消息的容器,也是消息传递的核心载体。以下是其核心特性与作用的全方位解析: 一、Queue 的定义与核心作用 消息存储容器 Queue 是 RabbitMQ 中实际存储消息的实体,生产者…...
【记录】成为创作者的第 730 天(两年)
收获 还是总在感叹走到今天收获的一切,都是自己曾经不敢想的。 无论是靠自己努力拿到的 Offer,还是在 CSDN 网站上结交的网友和前辈们,都是我莫大的荣幸和财富,感恩一切、感恩自己。 过去一年的收获真的数不胜数,抛…...

深度剖析数据分析职业成长阶梯
一、数据分析岗位剖析 目前,数据分析领域主要有以下几类岗位:业务数据分析师、商业数据分析师、数据运营、数据产品经理、数据工程师、数据科学家等,按照工作侧重点不同,本文将上述岗位分为偏业务和偏技术两大类,并对…...

【XSS】DVWA靶场XSS攻击
一、XSS攻击 1.1. XSS 攻击简介 XSS(Cross-Site Scripting,跨站脚本攻击)是一种常见的Web安全漏洞,它允许攻击者在受害者的浏览器中执行恶意脚本。攻击者通常通过在Web应用程序中注入恶意脚本代码(如JavaScript&…...

Fiddler在Windows下抓包Https
文章目录 1.Fiddler Classic 配置2.配置浏览器代理自动代理手动配置浏览器代理 3.抓取移动端 HTTPS 流量(可选)解决抓取 HTTPS 失败问题1.Fiddler证书过期了 默认情况下,Fiddler 无法直接解密 HTTPS 流量。需要开启 HTTPS 解密: 1…...
04 路由表的IP分组传输过程
目录 1、路由表的核心结构 2、IP分组传输过程和数据包转发过程 2.1、IP分组传输过程 2.2、数据包转发过程 2.3、IP分组传输过程和数据包转发的区别 3、数据包的变化 3.1、拓扑结构 3.2、传输过程详解(主机A → 主机B) 3.2.1、主机A发送数据 3.2…...
AI Agent 定义与核心要素详解
AI Agent(人工智能代理)是一种能够感知环境、自主决策并执行任务以达成目标的软件实体。它结合了感知、推理、学习和行动能力,能够在复杂环境中独立或协作工作。以下是其核心要素: 1. 感知 AI Agent 通过传感器或数据输入感知环…...

记忆化搜索与动态规划:原理、实现与比较
记忆化搜索和动态规划是解决优化问题的两种重要方法,尤其在处理具有重叠子问题和最优子结构性质的问题时非常有效。 目录 1. 记忆化搜索(Memoization) 定义: 实现步骤: 示例代码(斐波那契数列࿰…...

在 Mac mini M2 上本地部署 DeepSeek-R1:14B:使用 Ollama 和 Chatbox 的完整指南
随着人工智能技术的飞速发展,本地部署大型语言模型(LLM)已成为许多技术爱好者的热门选择。本地部署不仅能够保护隐私,还能提供更灵活的使用体验。本文将详细介绍如何在 Mac mini M2(24GB 内存)上部署 DeepS…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...

宇树科技,改名了!
提到国内具身智能和机器人领域的代表企业,那宇树科技(Unitree)必须名列其榜。 最近,宇树科技的一项新变动消息在业界引发了不少关注和讨论,即: 宇树向其合作伙伴发布了一封公司名称变更函称,因…...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...