【C语言】初阶指针详解
大家好,我是苏貝,本篇博客带大家了解C语言中令人头疼的指针,如果大家觉得我写的不错的话,可以给我一个赞👍吗,感谢❤️
使用的是VS2019编译器,默认为32位平台
文章目录
- ①指针是什么
- ②指针定义与&和*操作符
- 1.指针定义
- 2.&和*操作符
- ③指针类型
- ④ 野指针
- 1.野指针成因
- 2.如何规避野指针
- ⑤指针运算
- 1.指针 + - 整数 = 指针
- 2.指针 - 指针
- 3.指针的关系运算
- ⑥二级指针
- ⑦指针和数组
- ⑧指针数组
①指针是什么
指针理解的2个要点:
- 指针是内存中一个最小单元的编号,也就是地址
单元编号 == 地址 ==C语言中也叫: 指针 - 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量
内存:

指针变量:
我们可以通过&(取地址操作符)取出变量的内存起始地址,把地址可以存放到一个变量中,这个变量就是指针变量
要知道
1.内存被划分为一个个的内存单元,每个内存单元的大小是一个字节
2.每个字节的内存单元都有一个编号,这个编号就是地址,地址在C语言中被称为指针
3.每个内存单元都有唯一的地址来标识
4.地址要存储的话,存放在指针变量中
5.在32位机器上,地址的大小为4个字节,所以指针变量的大小也为4个字节
在64位机器上,地址的大小为8个字节,所以指针变量的大小也为8个字节
对第5点进行解释
对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0);
那么32根地址线产生的地址就会是:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
…
11111111 11111111 11111111 11111111
每个地址有32个比特位,即32/8=4个字节
同理:对于64位的机器,有8个字节
那32和64位机器能编址多大空间呢?
由上方解释可知,32位机器就有2的32次方个地址。每个地址标识一个字节,那我们就可以给 (2^ 32Byte = 2^ 32/1024KB =2^ 32/1024/1024MB=2^32/1024/1024/1024GB = 4GB) 4G的空闲进行编址。
同理,64位机器就可以给 2^ 64Byte 的空闲进行编址。
②指针定义与&和*操作符
1.指针定义
这里我们在讨论一下:指针的类型
我们都知道,变量有不同的类型,整形,浮点型等。那指针有没有类型呢?
准确的说:有的。当有这样的代码:
(1) int* p;
(2) char* p;
(3) int** p;
(1)* 代表p是指针变量,int* 是指针变量p的类型,int 是p所指向的类型,即p所指向的是int类型的变量
(2)* 代表p是指针变量,char* 是指针变量p的类型,int 是p所指向的类型
(3)离p最近的 * 代表p是指针变量,int* * 是指针变量p的类型,int* 是p所指向的类型
2.&和*操作符
这里的&是取地址操作符,*是间接访问操作符
int a=10;
int* p=&a;
p=&a的意思是:用&操作符取出a的地址,放在指针变量p中,指针变量的类型是 a的类型 + 一个 * 号,例如:a是int类型的,p的类型为int * ; a是char类型的,p的类型为char * ……
int a=10;
int *p=&a;
*p=0;
*p=0;意思是通过 *间接访问操作符解引用找到p指向的那个变量并将之赋值为0(即将0赋值给a)*p==a
int main()
{int a = 10;//在内存中开辟一块空间存储aint* p = &a;//用&操作符取出a的地址,放在指针变量p中*p = 20;//p通过*解引用找到a并将之赋值为20,*p==aprintf("a=%d\n", a);return 0;
}
//a=20
③指针类型
先看下面代码的结果,正如我们上面所说的,在32位平台下地址的大小为4个字节,那既然大家字节数都一样,为什么还要区分char* ,int* 等类型呢?直接用一个笼统的类型如all*类型不可以吗?

答案是不可以。为什么呢?
因为指针类型是有意义的,指针类型决定了指针进行解引用操作时访问几个字节
示例1:
因为下图的p是整型指针,指向的是一个int类型的变量,所以解引用时访问4个字节,所以在进行*p=0操作后,0x11223344全部变成0


示例2:
将上图的int* p=&a;改为char* p=&a;
因为下图的p是 char* 指针,指向的是一个char类型的变量,所以解引用时访问1个字节,所以在进行*p=0操作后,0x11223344全部变成0x11223300

示例3:
指针类型决定了指针 +1 / -1跳过几个字节(与指针类型进行解引用操作时访问的字节数相同)

总结
指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
比如: char* 的指针解引用就只能访问1个字节,而 int* 的指针的解引用就能访问4个字节,double* 的指针解引用就只能访问8个字节……
④ 野指针
概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
1.野指针成因
(1). 指针未初始化:
指针未初始化,默认为随机值
int main()
{int* p;//局部变量指针未初始化,默认为随机值*p = 20;return 0;
}
(2).指针越界访问:
数组arr只有10个元素,但却循环了11次,循环第11次时,针指向的范围超出数组arr的范围时,p成为野指针
解释*p++ = i ;
++(后缀自增操作符)的优先级高于*(间接访问操作符),所以p先后置++,再与 * 结合,但由于后置++是先使用再自增,所以执行*p=i操作后再自增,所以数组首元素被赋值为0后p自增1,使得p指向数组的第二个元素(跳了4个字节,原因在上面指针类型)
int main()
{int arr[10] = { 0 };int* p = arr;//p指向arr的首元素int i = 0;for (i = 0; i <= 10; i++){//当指针指向的范围超出数组arr的范围时,p就是野指针*p++ = i;}return 0;
}
(3).指针指向的空间释放:
a是函数内的局部变量,在函数调用结束后,a所开辟的内存空间会被释放,即使在释放前将a的地址传了出去,但p接收地址的时候a所开辟的内存空间已被释放,此时再用* 对p进行解引用,即使找到了该地址也属于非法访问
int* text()
{int a = 10;return &a;
}int main()
{int* p = text();//p就是野指针printf("*p=%d", *p);return 0;
}
2.如何规避野指针
- 指针初始化(若一开始不知道指针该指向哪,就先指向NULL)
NULL就是0,当0作为地址时,用户程序是不能访问的

- 小心指针越界
- 指针指向的空间释放,那就使之指向NULL
- 避免返回局部变量的地址
- 指针使用之前检查有效性
int main()
{int* p = NULL;//1//....int a = 10;p = &a;if (p != NULL)//5{*p = 20;}return 0;
}
⑤指针运算
1.指针 + - 整数 = 指针
int main()
{int arr[9] = { 1,2,3,4,5,6,7,8,9 };//使用指针打印数组的内容int* p = arr;//arr是首元素地址,所以p指向数组首元素int i = 0;for (i = 0; i < 9; i++){printf("%d ", *(p + i));//p指向数组首元素,即下标为0的元素//p+i指向数组下标为i的元素//*(p+i)是通过*解引用找到下标为i的元素//p+i 与p相比,跳过了i*sizeof(int)个字节}return 0;
}
//1 2 3 4 5 6 7 8 9
上面arr是首元素地址,指针变量p里面存的也是首元素地址,所以arr==p
因此arr+i == p+i, arr[i] == p[i](下标为i的元素的地址)
*(arr+i) == *(p+i) = arr[i]
下面表达式中,左边数组的这种形式在编译器处理时会转化为右边的表达式,又因为[ ] 和+ 一样只是一个操作符,所以i写在[ ]里面或外面都可以
arr[ i ] == *(arr+i) //当然,更建议写成 arr[ i ] 这种形式
i [ arr] == *(i+arr)

拓展:
数组名是数组首元素地址,除了以下2种情况:
(1)sizeof(数组名),此时的数组名代表整个数组,所以计算结果是整个数组的大小
(2)&数组名,此时的数组名也代表整个数组,取出的是整个数组的地址,返回的是数组首元素的地址,但绝不代表&数组名==arr(首元素地址),如下:
arr和&arr[0]等价,都是首元素地址,类型是int*,所以+1跳过4个字节
&arr是取出了整个数组的地址,但返回首元素地址,所以+1跳过整个数组即10* 4=40个字节
sizeof(arr)计算结果是整个数组的大小即10* 4=40个字节

2.指针 - 指针
指针-指针的前提:两个指针指向同一块区域,指针类型相同
指针-指针差值的绝对值是:指针和指针之间的元素个数


了解了这些之后,我们是不是又多了一种计算字符个数的功能的自定义函数my_strlen()实现的方法
点击链接了解:自定义实现strlen函数的3种方法
3.指针的关系运算
请看下面代码:
int main()
{int arr[5];int* vp = NULL;for (vp = &arr[5]; vp > &arr[0];){*--vp = 0;}return 0;
}

若不想一开始就越界,有人可能会修改成这样的代码:
int main()
{int arr[5];int* vp = NULL;for (vp = &arr[4]; vp >= &arr[0];vp--){*vp = 0;}return 0;
}

那这两种方法哪个更好呢?答案是第一种,第二种在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准并不保证它可行。
标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较
⑥二级指针
指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?
存放在 二级指针 中

*pp 通过对pp中的地址进行解引用,这样找到的是 p , *pp 其实访问的就是 p
**pp 先通过 *pp 找到 p ,然后对 p 进行解引用操作: *p ,那找到的是 a
int main()
{int a = 10;int* p = NULL;int** pp = NULL;*pp = &a;//等价于 p = &b;**pp = 30;//等价于*p = 30;//等价于a = 30;return 0;
}
⑦指针和数组
指针就是指针,指针变量就是一个变量,存放的是地址,指针变量的大小取决与32位平台还是64位平台
数组就是数组,可以存放一组相同类型的数,数组的大小取决于元素的类型和个数
数组的数组名是首元素地址,通过指针可以访问一个数组的每一个元素
int main()
{int arr[5] = { 1,2,3,4,5 };int* p = arr;//p=arr//arr[i]=p[i]=*(arr+i)=*(p+i)都是下标为i的元素int i = 0;for (i = 0; i < 5; i++){printf("%d ", p[i]);//arr[i],*(arr+i),*(p+i)}return 0;
}
//1 2 3 4 5
⑧指针数组
指针数组是指针还是数组?我们知道,整型数组是数组,存放的是int 类型的元素;字符数组是数组,存放的是char类型的元素……
指针数组是数组,是存放指针的数组
例如:int* arr[5];
arr是数组名,5代表数组有5个元素,int* 代表每个元素都是一个整型指针
好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞👍吗,感谢看到这里,我们下篇博客见❤️
相关文章:
【C语言】初阶指针详解
大家好,我是苏貝,本篇博客带大家了解C语言中令人头疼的指针,如果大家觉得我写的不错的话,可以给我一个赞👍吗,感谢❤️ 使用的是VS2019编译器,默认为32位平台 文章目录 ①指针是什么②指针定义与…...
ElasticSearch:项目实战(1)
es环境搭建参考:ElasticSearch:环境搭建步骤_Success___的博客-CSDN博客 需求: 用户输入关键可搜索文章列表 关键词高亮显示 文章列表展示与home展示一样,当用户点击某一篇文章,可查看文章详情 思路: …...
React 实现文件分片上传和下载
React 实现文件分片上传和下载 在开发中,文件的上传和下载是常见的需求。然而,当面对大型文件时,直接的上传和下载方式可能会遇到一些问题,比如网络传输不稳定、文件过大导致传输时间过长等等。为了解决这些问题,我们…...
2023.8.13
atcoder_abc\AtCoder Beginner Contest 310\E_NAND_repeatedly //题意:给定一个n长度的01串,计算f(l,r)(l<r,l在1~n,r在1~n)的和,f的计算(ai,a(i1))运算,有0就为1,11为0 //若f(l,r)1,则f(l,r-1)为0或sr为0,即只取决于上一位的情况和当前位ÿ…...
kvm not all arguments converted during string
kylin virt-manager 远程镜像制作问题记录(not all arguments ) 项目场景: 服务器端安装的OS版本:Kylin-Server-10-SP1-Release-Build20-20210518-arm64-2021-05-18 客户端安装的OS版本:Kylin-Server-10-SP1-Release-Build20-20210518-x86_…...
JVM 基础
巩固基础,砥砺前行 。 只有不断重复,才能做到超越自己。 能坚持把简单的事情做到极致,也是不容易的。 JVM 类加载机制 JVM 类加载机制分为五个部分:加载,验证,准备,解析,初始化&am…...
智谷星图赵俊:让人才和区块链产业“双向奔赴”丨对话MVP
区块链产业需要什么样的人才?赵俊很有发言权。 赵俊是北京智谷星图科技有限公司的技术总监,也是FISCO BCOS官方认证讲师。他2017年接触区块链,随后选择人才培育领域深耕。“为区块链行业引进更多人才这件事很有价值,跟我的职业理…...
C# Equals()方法报错:NullReferenceException was unhandled
下面是一个C# Equals()方法的例子,执行时报错了 static void Main(string[] args) {string name "sandeep";string myName null;Console.WriteLine(" operator result is {0}", name myName);Console.WriteLine("Equals method result…...
Linux下C语言调用libcurl库获取天气预报信息
一、概述 当前文章介绍如何在Linux(Ubuntu)下使用C语言调用libcurl库获取天气预报的方法。通过HTTP GET请求访问百度天气API,并解析返回的JSON数据,可以获取指定城市未来7天的天气预报信息。 二、设计思路 【1】使用libcurl库进…...
“深入解析JVM:Java虚拟机原理和内部结构“
标题:深入解析JVM:Java虚拟机原理和内部结构 摘要:本文将深入解析JVM(Java虚拟机)的原理和内部结构。我们将从JVM的基础概念开始,逐步介绍其组成部分,包括类加载器、运行时数据区、字节码解释器…...
Arrays.asList() 返回的list不能add,remove
一.Arrays.asList() 返回的list不能add,remove Arrays.asList()返回的是List,而且是一个定长的List,所以不能转换为ArrayList,只能转换为AbstractList 原因在于asList()方法返回的是某个数组的列表形式,返回的列表只是数组的另一个视图,而数组本身并没…...
命令执行漏洞
1、命令执行漏洞 1.1、简介 Django是用Python开发的一个免费开源的Web结构,几乎包括了Web使用方方面面,能够用于快速建立高性能、文雅的网站,Diango提供了许多网站后台开发常常用到的模块,使开发者可以专注于业务部分。 1.2、漏…...
Hive 中 sort by 和 order by 的区别
文章目录 数据量大小区别作用范围 在 Hive 中, SORT BY 和 ORDER BY 都用于对查询结果进行排序,但它们在实现方式和适用场景上有一些区别。 数据量大小区别 SORT BY: SORT BY 用于在 Hive 中对查询结果进行排序,它的主要特点是在…...
网络资源利用最大化:爬虫带宽优化解决方案
大家好,作为一名专业的爬虫程序员,我们都知道在爬取大量数据的过程中,网络带宽是一个十分宝贵的资源。如果我们不合理地利用网络带宽,可能会导致爬虫任务的效率低下或者不稳定。今天,我将和大家分享一些优化爬虫带宽利…...
STDF - 基于 Svelte 和 Tailwind CSS 打造的移动 web UI 组件库,Svelte 生态里不可多得的优秀项目
Svelte 是一个新兴的前端框架,组件库不多,今天介绍一款 Svelte 移动端的组件库。 关于 STDF STDF 是一个移动端的 UI 组件库,主要用来开发移动端 web 应用。和我之前介绍的很多 Vue 组件库不一样,STDF 是基于近来新晋 js 框架 S…...
C语言一些有趣的冷门知识
文章目录 概要1.访问数组元素的方法运行结果 2.中括号的特殊用法运行结果 3.大括号的特殊用法运行结果 4.sizeof的用法运行结果 5.渐进运算符运行结果 小结 概要 本文章只是介绍一些有趣的C语言知识,纯属娱乐。这里所有的演示代码我是使用的编译器是Visual Studio …...
Oracle数据库审计
1.什么是审计 审计是用来监控和记录用户的数据库操作的 2.审计级别 语句审计权限审计对象审计 3.查看审计功能是否开启: show parameter audit;相关参数: audit_file_destOS中审计信息存放位置audit_sys_operations默认值为FALSE,即不审…...
Node.js新手在哪儿找小项目练手?
前言 可以参考一下下面的nodejs相关的项目,希望对你的学习有所帮助,废话少说,让我们直接进入正题>> 1、 NodeBB Star: 13.3k 一个基于Node.js的现代化社区论坛软件,具有快速、可扩展、易于使用和灵活的特点。它支持多种数…...
全国各城市-货物进出口总额和利用外资-外商直接投资额实际使用额(1999-2020年)
最新数据显示,全国各城市外商直接投资额实际使用额在过去一年中呈现了稳步增长的趋势。这一数据为研究者提供了对中国外商投资活动的全面了解,并对未来投资趋势和政策制定提供了重要参考。 首先,这一数据反映了中国各城市作为外商投资的热门目…...
CentOS 7查看磁盘空间
CentOS如何查看硬盘大小 CentOS是一种基于Linux的操作系统,主要用于服务器端应用。在服务器管理中,硬盘大小是一个非常重要的指标,查看硬盘大小可以帮助系统管理员有效地管理硬盘空间和避免硬盘满了的情况。 方法一:使用df命令 …...
R语言实战:用RMST分析肝硬化患者生存数据,告别风险比依赖
R语言实战:用RMST解锁肝硬化患者生存分析新视角 当临床医生面对肝硬化患者的生存数据时,传统风险比分析常让人陷入解释困境——特别是当生存曲线交叉或删失严重时。限制平均生存时间(RMST)提供了一种直观的解决方案:它直接回答"治疗组患…...
IIT海德拉巴与微软研究院联手揭开多模态推理模型的隐秘缺陷
这项由印度理工学院海德拉巴分校计算机科学与工程系与微软研究院(班加罗尔)联合开展的研究,以预印本形式于2026年4月9日发布在arXiv平台,编号为arXiv:2604.08476。感兴趣的读者可通过该编号检索完整论文。一、答对了,但…...
Pixel Aurora EngineGPU利用率提升教程:diffusers流水线并行优化
Pixel Aurora Engine GPU利用率提升教程:diffusers流水线并行优化 1. 认识Pixel Aurora Engine Pixel Aurora Engine是一款基于AI扩散模型的高端绘图工作站,采用独特的8-bit像素风格界面设计。这款"虚拟游戏机"能将文字描述转化为极具视觉冲…...
超级结MOSFET的特性与PCB设计
Q1:什么是超级结 MOSFET?相比传统 MOSFET,它有哪些核心优势?超级结 MOSFET(Super Junction MOSFET,简称 SJ-MOSFET)是一种突破传统硅基功率器件 “耐压 - 导通电阻” trade-off(硅极…...
从零手搓一个DES-CBC加密库:用C语言一步步还原经典算法(附完整源码)
从零手搓一个DES-CBC加密库:用C语言一步步还原经典算法(附完整源码) 在嵌入式系统和教学场景中,理解加密算法的底层实现往往比单纯调用现成库更有价值。本文将带你从零开始实现DES-CBC加密算法,不仅剖析每个核心组件的…...
微信小程序saveFile报错?别慌,手把手教你排查‘tempFilePath file not exist‘的三大元凶
微信小程序saveFile报错深度排查指南:从tempFilePath file not exist到完美解决 最近在开发微信小程序时,不少开发者都遇到了一个令人头疼的问题:saveFile:fail tempFilePath file not exist。这个报错看似简单,背后却隐藏着多种可…...
解锁C语言中的多返回值技巧
在C语言编程中,常常会遇到需要从函数中返回多个值的情况。虽然C语言不直接支持多返回值,但我们可以通过一些技巧来实现这一目的。本文将详细探讨如何在C语言中返回多个值,并通过实例说明。 一、背景介绍 在C语言中,函数默认只能返回一个值。这对于需要处理多个结果的情况…...
STM32 DAP 烧录报错-最终解决方法的原理和操作逻辑
STM32 DAP 烧录报错(SWD/JTAG Communication Failure / Flash Download failed)最终解决方法的原理和操作逻辑针对遇到的 SWD/JTAG Communication Failure、Flash Download failed - Target DLL has been cancelled、Flash Download failed - "Cort…...
DistroAV终极指南:如何在OBS中实现专业级网络视频传输
DistroAV终极指南:如何在OBS中实现专业级网络视频传输 【免费下载链接】obs-ndi DistroAV (formerly OBS-NDI): NDI integration for OBS Studio 项目地址: https://gitcode.com/gh_mirrors/ob/obs-ndi DistroAV(原OBS-NDI)是专为OBS …...
如何从Android手机中删除不需要的应用程序
不需要的应用程序会让您的Android手机变得杂乱无章,占用存储空间,从而可能降低设备速度并影响性能。这里有一份指南教您如何有效地卸载它们。在无数个应用程序中寻找真正需要的应用程序,这常常令人沮丧。在本文中,我们将向您展示如…...

