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. 函数…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...
VisualXML全新升级 | 新增数据库编辑功能
VisualXML是一个功能强大的网络总线设计工具,专注于简化汽车电子系统中复杂的网络数据设计操作。它支持多种主流总线网络格式的数据编辑(如DBC、LDF、ARXML、HEX等),并能够基于Excel表格的方式生成和转换多种数据库文件。由此&…...
C++_哈希表
本篇文章是对C学习的哈希表部分的学习分享 相信一定会对你有所帮助~ 那咱们废话不多说,直接开始吧! 一、基础概念 1. 哈希核心思想: 哈希函数的作用:通过此函数建立一个Key与存储位置之间的映射关系。理想目标:实现…...
算术操作符与类型转换:从基础到精通
目录 前言:从基础到实践——探索运算符与类型转换的奥秘 算术操作符超级详解 算术操作符:、-、*、/、% 赋值操作符:和复合赋值 单⽬操作符:、--、、- 前言:从基础到实践——探索运算符与类型转换的奥秘 在先前的文…...
