C语言学习笔记——指针(初阶)
前言
指针可以说是C语言基础语法中最难的理解的知识之一,很多新手(包括我)刚接触指针时都觉得很难。在我之前发布的笔记中都穿插运用了指针,但是我一直没有专门出一期指针的笔记,这是因为我确实还有些细节至今还不太清楚。本篇将分享我对指针的理解,欢迎各位大佬批评指正。
一、指针是什么?
我们平常所说的指针其实就是指针变量,是一种用来存放地址的变量。地址就是某一变量或函数的地址,当我们需要调用某一变量或函数时,可以通过该变量或函数的地址找到并调用。因此,当指针变量中存放了一个变量的地址时,我们就可以通过该指针找到其所指向的变量。
就像在现实当中,我们知道一个朋友家的地址,才能找到这个朋友的家。
在32位系统上,所有指针变量的大小均为4字节。在64位系统上为8字节。
二、常见的指针类型
常见指针类型可以和常见的数据类型一一对应,例如整型指针对应整型,浮点型指针对应浮点型。需要注意的是,结构体变量的数据类型为“struct + 结构体名”,定义结构体指针时需要将类型写全。
int* pi = NULL; //整型指针
char* pch = NULL; //字符型指针
float* pf = NULL; //単精度浮点型指针
double* plf = NULL; //双精度浮点型指针
sturct stru* ps = NULL; //结构体指针
FILE* pF = NULL;//文件指针
void (*test)() ptest = NULL; //函数指针
上图即各种常见的指针类型的定义方式,例如 " pi " 为 " int* " 类型的指针(变量pi的数据类型为" int* "),即整型指针、" ps " 为 " struct stru* " 类型的指针,即该结构体类型的指针,而 " ptest " 为 " void (*)() " 类型的函数指针。
图中的所有的指针均被初始化为NULL。NULL为空指针,其数值为0。
三、野指针
野指针就是指向未知地址的指针。
当我们定义了一个指针变量后,如果不直接初始化为所需存放的地址,则应初始化为空指针NULL。否则该指针将会成为野指针。
野指针有什么危害呢?当我们创建一个变量时,编译器会向内存申请一块空间来存放该变量,这块空间为合法空间,我们使用指针访问该空间即为合法访问。而野指针指向的随机地址可能并非合法空间,当我们使用野指针时就会产生非法访问。
因此,当我们创建一个指针变量后,如果不要立即使用,则最好将其初始化为空指针,以避免造成非法访问。
四、指针的基本用法
1. 指针的赋值和解引用
当我们创建一个指针变量后,我们应该如何使用该指针变量来存储一个对应数据类型的数据呢?又该如何使用该指针来找到其所指向的数据呢?这里以整型指针为例。我们来看看以下代码,printf函数的打印值为多少呢?
int main()
{int a = 10;int* pa = &a;int b = *pa;printf("%d\n",b);return 0;
}
首先介绍一下上方代码出现的两种操作符:
1、取地址操作符 "&" :用来取出变量的地址,例如&a的值就是a的地址。
2、解引用操作符 " * " :用来解引用指针变量,使用指针所指向的数据,例如*pa的值即为a的值。这里需要注意区分 " int* " 中的 * 和解引用操作符 " * ",前者" int* "为一个整体,代表一种数据类型,而后者为一种操作符。
我们来逐条分析上方代码。
第一行,定义变量a并初始化为10。第二行,定义指针变量pa,并初始化为a的地址。第三行,定义变量b,并初始化为pa所指向的变量,即b被初始化为10。因此printf函数打印的值为10。
2. 函数传参
函数传参分为传值调用和传址调用两种。传值调用指直接将变量传给函数,而传址调用则是将变量的地址传给函数。这里我通过一个简单的函数来介绍这两种传参方式的区别。
2.1 传值调用

如图为一段传值调用的代码,我们将x初始化为0,并将x,10作为参数x,y传入test函数,在test函数中,x被赋值为y,那么为什么最后printf函数打印出来的x值为0呢?
首先我们要明白一点,main函数中的x与test函数中的x不是同一个变量,因此test函数中的x被赋值为10并不会影响main函数中的x的值,main函数中的x也就还是0。
如果我们希望使用传值调用实现上述逻辑,应对代码进行如下修改。

通过函数返回值的方式对main函数中的x进行赋值即可。
2.2 传址调用

这段代码与传值调用的第一段代码类似,将test函数参数中的(int)x换成了(int*)px。在test函数中,通过解引用px的方式找到x,并进行赋值操作,这样操作又可以实现上述逻辑,这是为什么呢?
首先我们要搞清楚一点,每个变量被创建出来时都会占用一部分内存空间,在该变量被销毁之前,其占用的空间是不变的。当我们拥有该变量的地址时,我们可以在它未被销毁的任何位置通过其地址找到该变量。
在上面这段代码中,main函数中的x在main函数结束时才被销毁,那么在main函数调用test函数时,x并未被销毁,因此在test函数中,我们可以通过x的地址px找到并给x赋值。
2.3 用法总结
传值调用和传址调用不分绝对的好坏,需要根据实际情况选用不同的方式。
当不需要改变参数值,只需要调用参数参与函数运算时,多使用传值调用。
当需要改变参数值时,多使用传址调用。
五、指针运算
指针运算的知识多用于与数组结合的问题。
1. 指针 +(-) 整数

这段代码分别打印了p-1、p和p+1(地址的格式符为%p,打印值为十六进制)。我们可以发现,指针通过加减整数得到的值仍然为指针。
在此图中,指针+1,地址+4。这是因为图中的指针为整型指针(int*),一个整型的大小为4个字节,指针+1的含义是跳过一个整型,也就是跳过4个字节,即地址+4。同理,如果是一个字符指针(char*)+1,则跳过一个字节,地址+1;如果是双精度浮点型指针(double*)+1,则跳过八个字节,地址+8。


2. 指针 - 指针

根据上述指针+(-)整数的知识,我们可以推出,指针-指针的值应该为整数。
这里我通过字符指针为例(字符指针每次+1跳过一个字节,更加直观)。上图中,pa为低地址,pb为高地址,差值为32。pa-pb为低地址-高地址,结果为负的差值,即-32,同理,pb-pa则为32。
六、二级指针
我们知道,一个整型指针(int*)可以存储一个整型(int)变量的地址。那么作为一个指针变量,我们同样可以使用一个指针来存储它的地址。

我们来逐一分析上方代码。首先pa为指向a的指针,它的类型为整型指针(int*),而ppa为指向pa的指针,它的类型为整型指针指针(int**)。这就是所谓的二级指针。我们同样可以通过二级指针找到最终的变量值。首先进行一次解引用找到其所指向的一级指针,再次解引用即可得到变量值,如图中" **ppa "。
当然,有二级指针,同样也有三级,四级甚至更高级数的指针,它们的底层逻辑与二级指针相同,这里就不过多解释了。
结束语
以上就是有关于指针的基础内容了,希望能够帮助到正在学习C语言的同学们。如果文章内容有错误或知识点有遗漏,望各位大佬批评或补充在评论区或私信。
相关文章:
C语言学习笔记——指针(初阶)
前言 指针可以说是C语言基础语法中最难的理解的知识之一,很多新手(包括我)刚接触指针时都觉得很难。在我之前发布的笔记中都穿插运用了指针,但是我一直没有专门出一期指针的笔记,这是因为我确实还有些细节至今还不太清…...
阿赵的MaxScript学习笔记分享十二《获取和导出各种数据》
大家好,我是阿赵,周日的早上继续分享MaxScript学习笔记,这是第十二篇,获取和导出各种数据 1、导出数据的目的 使用3DsMax建立3D模型后,很多时候需要输出模型到别的引擎去使用,常用的格式有Obj、FBX、SLT等…...
react-draggable实现拖拽详解
react-draggable属性常用属性属性列表事件列表举例首先安装 react-draggable实现移动希望小编写的能够帮助到你😘属性 常用属性 属性默认值介绍axisxhandle拖动的方向,可选值 x ,y,bothhandle无指定拖动handle的classposition无handle的位置࿰…...
01.进程和线程的区别
进程和线程的区别进程和线程是计算机中的两个核心概念,它们都是用来实现并发执行的方式,但是它们在实现并发的方式和资源管理方面有一些重要的区别。进程是一个程序的运行实例。每个进程都有自己的内存空间、代码、数据和系统资源(如文件描述…...
逻辑优化-rewrite
简介 逻辑综合中的rewrite算法是一种常见的优化算法,其主要作用是通过对逻辑电路的布尔函数进行等效变换,从而达到优化电路面积、时序和功耗等目的。本文将对rewrite算法进行详细介绍,并附带Verilog代码示例。 一、算法原理 rewrite算法的…...
文件传输与聊天系统设计
技术:Java等摘要:本文介绍了一种基于TCP/IP协议使用Socket技术实现的聊天室系统,包括私聊功能和文件传输功能,对系统的主要模块进行了分析,并对系统实现过程中遇到的关键性技术进行了阐述,最后对系统进行了…...
蓝桥杯第十四届校内赛(第三期) C/C++ B组
一、填空题 (一)最小的十六进制 问题描述 请找到一个大于 2022 的最小数,这个数转换成十六进制之后,所有的数位(不含前导 0)都为字母(A 到 F)。 请将这个数的十进制形式作…...
有关平方或高次方的公式整理一元高次方程的求解
Part.I Introduction 这篇博文记录一下数学中常用的有关平方或高次方的一些公式。 Chap.I 一些结论 下面一部分汇总了一些重要的结论 完全平方公式:(ab)2a22abb2(ab)^2a^22abb^2(ab)2a22abb2平方差公式:a2−b2(ab)(a−b)a^2-b^2(ab)(a-b)a2−b2(ab)(…...
Java笔记3
ArrayListArrayList<String> list new Arraylist<>();<>是泛型表示存放的数据类型,注意不能是基本数据类型;增删改查增:add 返回值为true删:remove 1.直接删元素2.根据索引删元素改:set(…...
Leetcode.2202 K 次操作后最大化顶端元素
题目链接 Leetcode.2202 K 次操作后最大化顶端元素 Rating : 1717 题目描述 给你一个下标从 0开始的整数数组 nums,它表示一个 栈 ,其中 nums[0]是栈顶的元素。 每一次操作中,你可以执行以下操作 之一 : 如果栈非空…...
JAVA知识点全面总结3:String类的学习
三.String类学习 1.String,StringBuffer,StringBuilder的区别? 2.字符串拼接用加号的原理 ? 3.字符串常量池如何理解? 4.String的intern方法理解? 5.String的equals方法和compareTo方法的使用…...
Eureka注册中心和Nacos注册中心详解以及Nacos与Eureka有什么区别?
目录:前言Eureka注册中心Nacos注册中心Nacos与Eureka有什么区别?前言提供接口给其它微服务调用的微服务叫做服务提供者,而调用其它微服务提供的接口的微服务则是服务消费者。如果服务A调用了服务B,而服务B又调用了服务C࿰…...
Web3D发展趋势以及Web3D应用场景
1,Web3D发展趋势随着互联网的快速发展,Web3D技术也日渐成熟,未来发展趋势也值得关注。以下是Web3D未来发展趋势的七个方面:可视化和可交互性的增强:Web3D可以为三维数据提供可视化和可交互性的增强,将极大地…...
2023-3-4 刷题情况
按位与为零的三元组 题目描述 给你一个整数数组 nums ,返回其中 按位与三元组 的数目。 按位与三元组 是由下标 (i, j, k) 组成的三元组,并满足下述全部条件: 0 < i < nums.length 0 < j < nums.length 0 < k < nums.l…...
前端面试总结
1.引言 最近参加了大量的招聘会,投递了大量的简历,整整体会了从“随便找个厂上一下”——“还是的找个大厂”——“没人要”——“急了急了,海投一波”——“工资有点尬”——“海投中…”。简单说一下自己的一些感受吧,现在的前端属实有点尴…...
Geospatial Data Science (6): Spatial clustering
Geospatial Data Science (6): Spatial clustering 1.Clustering, spatial clustering, and geodemographics 本节涉及空间观测的统计聚类。许多问题和主题都是复杂的现象,涉及多个维度,难以归纳为一个单一的变量。在统计学术语中,我们把这一类问题称为多变量,而不是在…...
蚁群算法优化问题
%%%%%%%%%%%%蚁群算法解决 TSP 问题%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%初始化%%%%%%%%%%%%%%%%%%% clear all; %清除所有变量 close all; %清图 clc; %清屏 m 50; %蚂蚁个数 Alpha 1; %信息素重要程度参数 Beta 5; %启发式因子重要程度参数 Rho 0.1; %信息素蒸发系数 G 20…...
为啥一个 main 方法就能启动项目
在 Spring Boot 出现之前,我们要运行一个 Java Web 应用,首先需要有一个 Web 容器(例如 Tomcat 或 Jetty),然后将我们的 Web 应用打包后放到容器的相应目录下,最后再启动容器。 在 IDE 中也需要对 Web 容器…...
洛谷:P1554 梦中的统计 JAVA
思路:定义一个长度为10的数组,数组下标代表数组元素的数字,比如arr[0]代表数字0.用一个for循环,对每个数先取余再取整,知道取整得到的数为0,说明该数字已经被拆解完了。今天又学了一个输入,原来…...
C++初学笔记整理
目录 1. C关键字 2. 命名空间 1)命名空间的引入和概述 2)命名空间的定义 3)std与命名空间的使用 4).相关特性 3. C输入&输出 4. 缺省参数 1 )缺省参数概念 2)使用及分类 a.全缺省 b.部分缺省 5. 函数…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
从面试角度回答Android中ContentProvider启动原理
Android中ContentProvider原理的面试角度解析,分为已启动和未启动两种场景: 一、ContentProvider已启动的情况 1. 核心流程 触发条件:当其他组件(如Activity、Service)通过ContentR…...
