C语言入门系列:指针入门(超详细)
文章目录
- 一,什么是指针
- 1,内存
- 2,指针是什么?
- 二,指针的声明
- 1,声明指针类型变量
- 2,二级指针
- 三,指针的计算
- 1,两个指针运算符
- 1.1 *运算符
- 1.2 & 运算符
- 1.3 &运算符与*运算符的关系
- 2,指针变量的初始化
- 2.1 指针变量的大坑
- 2.2 指针变量初始化
- 2.3 指针变量初始化最佳实践
- 三,指针的运算
- 1,指针与整数值的加减运算
- 2,指针与指针的加法运算
- 3,指针与指针的减法
- 4,指针与指针的比较运算
指针是 C 语言的重点,也是难点,这篇文章主要讲解指针是什么以及如何使用。
一,什么是指针
1,内存
指针与内存是息息相关的,在学习指针之前,先回忆下内存相关的知识。
内存是程序运行期间存储数据的硬件设备,为了方便管理,计算机将内存划分为一个个小的单元,每个单元的大小是一个字节。
如果把内存比作一栋酒店大楼,内存单元就像是一个个小的房间,数据就住在小房间里。
我们知道,为了客人能准确找到属于自己的房间,酒店房间是有房号的。
同样,内存单元也是有编号的,这个编号在计算机中称之为“内存地址
”。
2,指针是什么?
指针就是内存单元的编号,本质上是一个内存地址,相当于房卡上的房间号。
从形式上看,指针和整型数据并没有什么区别,都是数字。区别在于,指针是内存地址,不用于与其他数据进行加减乘除等运算,也不会展示给用户。
二,指针的声明
1,声明指针类型变量
在编写代码过程中,通常会声明一个变量,然后对变量进行赋值或者其他各种运算。
要使用指针,也需要声明一个指针类型的变量。
一定要牢记:指针变量就是一个普通变量,只不过它的值是内存地址而已。
指针类型由两部分构成:
- ①指针标识符,C语言用字符
*
表示指针 - ②指针类型,指针不能单独存在,必须和数据类型一起出现,表明这个指针是某种数据类型的指针
比如,char*
表示一个指向字符的指针,float*
表示一个指向float类型的值的指针。
int* intPtr;
上面示例声明了一个变量intPtr,它是一个指针,指向的内存地址存放的是一个整数。
星号*可以放在变量名与类型关键字之间的任何地方,下面的写法都是正确的。
int *intPtr;
int * intPtr;
int* intPtr;
推荐使用星号紧跟在类型关键字后面的写法,即int* intPtr;
。
声明指针变量时需要注意,如果要在一行声明多个指针变量,每个变量前都要携带字符*
。
// 正确
int * foo, * bar;// 错误
int* foo, bar;
上面示例中,第二行实际上仅仅声明了一个指针变量,foo
是整数指针变量,而bar
是整数变量,即*只对第一个变量生效。
2,二级指针
一个指针指向的可能还是指针,这时就要用两个星号**
表示,这种指针通常称为二级指针
。
int** foo;
上面示例表示变量foo是一个指针,即变量foo存储的还是一个内存地址,这个内存地址指向的内存中存储的则是一个整数。
int a = 10;
// &a表示a变量的内存地址
int* pa = &a;
// &a表示指针变量pa的内存地址
int** ppa = &pa;
三,指针的计算
1,两个指针运算符
1.1 *运算符
*
这个字符除了声明变量时代表指针外,还可以作为运算符,用来获取指针指向的内存中的值。
void plus1(int* p) {*p = *p + 1;
}
上面代码中,函数plus1的参数是一个整数指针p。
函数体里面,*p就表示指针p所指向的那个整数值。
对*p赋值,就是改变指针p指向的内存中的值。
这有点绕,和普通变量对比更容易理解。
int a = 10;
int b = 100;
// 将b的地址赋于指针pb
int* pb = &b;*pb = *pb +1;
a = a + 1;
对于上述代码的最后两行:
*pb = *pb +1
,这个表达式可以拆解为4步,①计算机首先从指针变量pb中取出地址0xffeecc
,②再去这个地址指向的内存单元中获取整数100
,③然后执行运算100+1
,执行完成后,④0xffeecc
这个内存单元的值就变成101。a = a + 1
,相当于上面的表达式,执行过程更简单。①计算机从变量a
对应的内存直接取出整数10
,②然后执行运算10+1
,③执行完成后,a变量对应的内存的数据更新为11
。
1.2 & 运算符
&运算符用来取出一个变量所在的内存地址。
int x = 1;
printf("x's address is %p\n", &x);
上面示例中,x是一个整数变量,&x就是x的值所在的内存地址。printf()的%p是内存地址的占位符,可以打印出内存地址。
上一小节中,参数变量加1的函数,可以像下面这样使用。
void plus1(int* p) {*p = *p + 1;
}int x = 1;
plus1(&x);
printf("%d\n", x); // 2
注意,调用plus1()函数以后,打印变量x的值,发现结果是2,但是我们并没有对x进行显示的重新赋值,原因调用plus1函数时,将变量c的地址作为参数进行传递,plus1直接根据地址取出初始值,执行加1的运算,然后更新内存中的值为2,不必使用变量x就可以修改x变量的值。
1.3 &运算符与*运算符的关系
&运算符与*运算符互为逆运算,下面的表达式,是成立的。
int i = 5;if (i == *(&i)) // 正确
2,指针变量的初始化
2.1 指针变量的大坑
声明指针变量之后,编译器会为指针变量本身分配一个内存空间,这个内存空间可能还保存着历史数据。
也就是说,这个指针变量可能指向一个随机的地址。
如果此时就去读写这个地址对应的内存,可能出现非常严重的后果,必然这个地址指向的是账户余额,有可能导致账户虚增或者虚减。
int* p;
*p = 1; // 错误
上述代码是必须避免的,因为指针p指向的内存单元是随机的。
2.2 指针变量初始化
正确写法是声明指针变量声明,立即指向一个明确的地址,这就是指针变量的初始化,初始化之后再进行读写。
int* p;
int i;p = &i;
*p = 13;
上面示例中,p是指针变量,声明这个变量后,p会指向一个随机的内存地址。
这时要将它指向一个已经分配好的内存地址,上例就是再声明一个整数变量i,编译器会为i分配内存地址,然后让p指向i的内存地址(p = &i;)。
完成初始化之后,就可以对p指向的内存地址进行赋值了(*p = 13;)。
2.3 指针变量初始化最佳实践
强烈推荐,声明指针变量的同时,将指针变量的值设为NULL。
int* p = NULL;
NULL在 C 语言中是一个常量,表示地址为0的内存空间,这个地址是无法使用的,读写该地址会报错。
这样即使之后我们忘记了把指针变量p指向预期的内存地址,在程序运行过程中会报错,而不是以可怕的、随机的方式运行。
三,指针的运算
我们现在知道了,指针虽然代表的是内存地址,但其本质上是一个无符号整数。
C语言允许指针参与运算,但是指针的运算规则和整数的运算规则是相差很大的。
1,指针与整数值的加减运算
指针与整数值的运算,表示指针的移动。
short* j;
j = (short*)0x1234;
j = j + 1; // 0x1236
上面示例中,j是一个指针,指向内存地址0x1234
。
由于0x1234本身是整数类型(int),跟j的类型(short*)并不兼容,所以强制使用类型投射,将0x1234转成short*。
表明上看,j + 1应该等于0x1235,但正确答案是0x1236。
原因是j + 1表示指针向内存地址的高位移动一个单位,而一个单位的short类型占据两个字节的宽度,所以相当于向高位移动两个字节。同样的,j - 1得到的结果是0x1232。
指针移动的单位,与指针指向的数据类型有关。数据类型占据多少个字节,每单位就移动多少个字节。
2,指针与指针的加法运算
指针只能与整数值进行加减运算,两个指针进行加法是非法的。
unsigned short* j;
unsigned short* k;
x = j + k; // 非法
上面示例是两个指针相加,这是非法的。
3,指针与指针的减法
相同类型的指针允许进行减法运算,返回它们之间的距离,即相隔多少个数据单位。
高位地址减去低位地址,返回的是正值;低位地址减去高位地址,返回的是负值。
这时,减法返回的值属于ptrdiff_t
类型,这是一个带符号的整数类型别名,具体类型根据系统不同而不同。这个类型的原型定义在头文件stddef.h里面。
short* j1;
short* j2;j1 = (short*)0x1234;
j2 = (short*)0x1236;ptrdiff_t dist = j2 - j1;
printf("%td\n", dist); // 1
上面示例中,j1和j2是两个指向 short 类型的指针,变量dist是它们之间的距离,类型为ptrdiff_t,值为1,因为相差2个字节正好存放一个 short 类型的值。
4,指针与指针的比较运算
指针之间的比较运算,比较的是各自的内存地址哪一个更大,返回值是整数1(true)或0(false)。
相关文章:
![](https://img-blog.csdnimg.cn/direct/adfb609046044dfab4766f82aa51a8a3.png)
C语言入门系列:指针入门(超详细)
文章目录 一,什么是指针1,内存2,指针是什么? 二,指针的声明1,声明指针类型变量2,二级指针 三,指针的计算1,两个指针运算符1.1 *运算符1.2 & 运算符1.3 &运算符与…...
![](https://www.ngui.cc/images/no-images.jpg)
打印水仙花数
题目:打印出所有的“水仙花数”,所谓“水仙花数”是指一个三位数,其各位数字立方和等于该数本身。 例如:153是一个“水仙花数”,因为153 1的三次方 +5的三次方+3的三次方。 程序分析ÿ…...
![](https://img-blog.csdnimg.cn/direct/d7e301ece52a4ad9b945018896fd4cf3.png)
【SCAU数据挖掘】数据挖掘期末总复习题库简答题及解析——下
1.从某超市顾客中随机抽取5名,他们的购物篮数据的二元0/1表示如下: 顾客号 面包 牛奶 尿布 啤酒 鸡蛋 可乐 1 1 1 0 0 0 0 2 1 0 1 1 1 0 3 0 1 1 1 0 1 4 1 1 1 1 0 0 5 1 1 1 0 0 1 某学生依据这些数据做…...
![](https://www.ngui.cc/images/no-images.jpg)
PyQt学习之简介
1.Python图形界面称为程序的用户交互界面,英文称之为 UI (user interface) Tkinter 基于Tk的Python库,Python官方采用的标准库,优点是作为Python标准库、稳定、发布程序较小,缺点是控件相对较少。 wxPython 基于wxWidgets的Py…...
![](https://img-blog.csdnimg.cn/img_convert/d6d67e4bf6b18545ca13ec8002e5715b.webp?x-oss-process=image/format,png)
深入理解前端缓存
前端缓存是所有前端程序员在成长历程中必须要面临的问题,它会让我们的项目得到非常大的优化提升,同样也会带来一些其它方面的困扰。大部分前端程序员也了解一些缓存相关的知识,比如:强缓存、协商缓存、cookie等,但是我…...
![](https://www.ngui.cc/images/no-images.jpg)
K-means聚类算法详解与实战
一、引言 K-means聚类算法是一种无监督学习算法,旨在将数据点划分为K个不同的聚类或群组,使得同一聚类内的数据点尽可能相似,而不同聚类间的数据点尽可能不同。在图像处理、数据挖掘、客户细分等领域有着广泛的应用。本文将通过图文结合的方…...
![](https://img-blog.csdnimg.cn/direct/62757f1b0b0d465590252fd1fc0a9e07.png)
python数据分析-糖尿病数据集数据分析预测
一、研究背景和意义 糖尿病是美国最普遍的慢性病之一,每年影响数百万美国人,并对经济造成重大的经济负担。糖尿病是一种严重的慢性疾病,其中个体失去有效调节血液中葡萄糖水平的能力,并可能导致生活质量和预期寿命下降。。。。 …...
![](https://img-blog.csdnimg.cn/direct/cb4c006d939844be8fc9d9010ce51fbe.png)
【前端】 nvm安装管理多版本node、 npm install失败解决方式
【问题】If you believe this might be a permissions issue, please double-check the npm ERR! permissio或者Error: EPERM: operation not permitted, VScode中npm install或cnpm install报错 简单总结,我们运行npm install 无法安装吧包,提示权限问题…...
![](https://www.ngui.cc/images/no-images.jpg)
第11天:API开发与REST framework
第11天:API开发与REST framework 目标 使用Django REST framework构建RESTful API。 任务概览 学习序列化器的概念和使用方法。创建API视图和路由。实现API的权限和认证。 详细步骤 1. 学习序列化器 序列化器是Django REST framework中用于数据转换的组件&am…...
![](https://img-blog.csdnimg.cn/img_convert/016355a99d00dafa116f4278a4dfe184.png)
2024 年解锁 Android 手机的 7 种简便方法
您是否忘记了 Android 手机的 Android 锁屏密码,并且您的手机已被锁定?您需要使用锁屏解锁 Android 手机?别担心,您不是唯一一个忘记密码的人。我将向您展示如何解锁 Android 手机的锁屏。 密码 PIN 可保护您的 Android 手机和 G…...
![](https://img-blog.csdnimg.cn/img_convert/9cc738873f78c2b774f26b927bcfe623.jpeg)
利用机器学习重构视频中的人脸
引言 中国与英国的研究团队携手合作,开创了一种创新的视频面孔重塑技术。这项技术能够以极高的一致性对视频中的面部结构进行逼真的放大和缩小,且避免了常见伪影的产生。 从研究人员选取的YouTube视频样例中可见,经过处理后,女演…...
![](https://img-blog.csdnimg.cn/img_convert/69ee288143903e272b2a74308a2d0bd7.png)
2021数学建模C题目– 生产企业原材料的订购与运输
C 题——生产企业原材料的订购与运输 思路:该题主要是通过对供应商的供货能力和运送商的运货能力进行估计,给出合适的材料订购方案 程序获取 第一题问题思路与结果: 对 402 家供应商的供货特征进行量化分析,建立反映保障企业生…...
![](https://www.ngui.cc/images/no-images.jpg)
C# OpenCvSharp 图像复制-clone、copyTo
在C#中使用OpenCvSharp库处理图像时,clone和copyTo是两个非常常用的函数。理解和合理使用这些函数可以帮助你在图像处理项目中更高效地操作图像数据。本文将详细介绍这两个函数的使用方法,并通过具体的示例来说明它们的实际应用。 1. clone 函数 定义 …...
![](https://www.ngui.cc/images/no-images.jpg)
中国投入到终止遗传性疾病的战斗
中国投入到终止遗传性疾病的战斗 编译 李升伟 于2006年6月在澳大利亚的墨尔本会议上启动的人类变异组计划(Human Variome Project,简称HVP),旨在全球范围内广泛收集所有基因和蛋白质序列变异和多态性的数据,采用全基…...
![](https://www.ngui.cc/images/no-images.jpg)
PCL common中常见的基础功能函数
文章目录 一、common模块中的头文件二、common模块中的基本函数1、angles.h2、centroid.h1)计算给定一群点的3D中心点,并且返回一个三维向量2)计算给定的三维点云的协方差矩阵。3)计算正则化的3*3的协方差矩阵以及给定点云数据的中心点4)利用一组点的指数对其进行一般的、…...
![](https://img-blog.csdnimg.cn/direct/471f207c3cd9415581a09a7b3dedbd0f.jpeg)
力扣每日一题 6/22 字符串/贪心
博客主页:誓则盟约系列专栏:IT竞赛 专栏关注博主,后期持续更新系列文章如果有错误感谢请大家批评指出,及时修改感谢大家点赞👍收藏⭐评论✍ 2663.字典序最小的美丽字符串【困难】 题目: 如果一个字符串满…...
![](https://img-blog.csdnimg.cn/direct/b9bfc91d395a4a29987dbde86e32992c.png)
MCT Self-Refine:创新集成蒙特卡洛树搜索 (MCTS)提高复杂数学推理任务的性能,超GPT4,使用 LLaMa-3 8B 进行自我优化
📜 文献卡 题目: Accessing GPT-4 level Mathematical Olympiad Solutions via Monte Carlo Tree Self-refine with LLaMa-3 8B作者: Di Zhang; Xiaoshui Huang; Dongzhan Zhou; Yuqiang Li; Wanli OuyangDOI: 10.48550/arXiv.2406.07394摘要: This pape…...
![](https://img-blog.csdnimg.cn/direct/0760656619794218aba8e42f5cc03111.gif)
自制HTML5游戏《开心消消乐》
1. 引言 游戏介绍 《开心消消乐》是一款基于HTML5技术开发的网页游戏,以其简单的操作方式、轻松的游戏体验和高度的互动性,迅速在社交平台上获得了广泛的关注和传播。玩家通过消除相同类型的元素来获得分数,游戏设计巧妙,易于上手…...
![](https://img-blog.csdnimg.cn/direct/92f8d01c00f044c1b06891d154b350b2.png)
【C++】平衡二叉树(AVL树)的实现
目录 一、AVL树的概念二、AVL树的实现1、AVL树的定义2. 平衡二叉树的插入2.1 按照二叉排序树的方式插入并更新平衡因子2.2 AVL树的旋转2.2.1 新节点插入较高左子树的左侧(LL平衡旋转)2.2.2 新节点插入较高右子树的右侧(RR平衡旋转)…...
![](https://www.ngui.cc/images/no-images.jpg)
第一百一十八节 Java面向对象设计 - Java接口
Java面向对象设计 - Java接口 什么是接口? Java中的接口定义了一个引用类型来创建抽象概念。接口由类实现以提供概念的实现。 在Java 8之前,一个接口只能包含抽象方法。 Java 8允许接口具有实现的静态和默认方法。 接口通过抽象概念定义不相关类之间…...
![](https://www.ngui.cc/images/no-images.jpg)
Flink nc -l -p 监听端口测试
1、9999端口未占用 netstat -apn|grep 99992、消息发送端 nc -l -k -p 9999 {"user":"ming","url":"www.baidu1.com", "timestamp":1200L, "score":1} {"user":"xiaohu","url":…...
![](https://www.ngui.cc/images/no-images.jpg)
在IntelliJ IDEA中使用Spring Boot:快速配置
使用IntelliJ IDEA开发Spring Boot应用程序可以极大地提高开发效率,因为IDEA提供了许多便捷的功能,比如自动补全、代码分析、热部署等。以下是一篇可能的CSDN博客文章草稿,介绍如何在IntelliJ IDEA中使用Spring Boot: 在IntelliJ …...
![](https://www.ngui.cc/images/no-images.jpg)
django filter 批量修改
django filter 批量修改 在Django中,如果你想要批量修改记录,可以使用update()方法。这个方法允许你在一个查询集上执行批量更新,而不需要为每条记录生成单独的数据库事务。 以下是一个使用update()方法批量修改记录的例子: fro…...
![](https://img-blog.csdnimg.cn/direct/85bc15800ba9419b8aa1e26c172c537f.png)
maven:中央仓库验证方式改变:401 Content access is protected by token
前几天向maven中央仓库发布版本,执行上传命令mvn release:perform时报错了: [ERROR] Failed to execute goal org.sonatype.plugins:nexus-staging-maven-plugin:1.6.13:deploy (injected-nexus-deploy) on project xxxxx: Failed to deploy artifacts: …...
![](https://www.ngui.cc/images/no-images.jpg)
【面试】http
一、定义 HTTP(超文本传输协议),是一种用于分布式、协作式、超媒体信息系统的应用层协议,它是万维网数据通信的基础。主要特点是无状态(服务器不会保存之前请求的状态)、无连接(服务器处理完请…...
![](https://img-blog.csdnimg.cn/img_convert/394077c6aa627081bcb19a2ffc872334.png)
获取泛型,泛型擦除,TypeReference 原理分析
说明 author blog.jellyfishmix.com / JellyfishMIX - githubLICENSE GPL-2.0 获取泛型,泛型擦除 下图中示例代码是一个工具类用于生成 csv 文件,需要拿到数据的类型,使用反射感知数据类型的字段,来填充表字段名。可以看到泛型…...
![](https://img-blog.csdnimg.cn/direct/5258b2ca838f48d5be951309184e249c.png)
springboot 3.x 之 集成rabbitmq实现动态发送消息给不同的队列
背景 实际项目中遇到针对不同类型的消息,发送消息到不同的队列,而且队列可能还不存在,需要动态创建,于是写了如下代码,实践发现没啥问题,这里分享下。 环境 springboot 3.2 JDK 17 rabbitMQ模型介绍 图片…...
![](https://www.ngui.cc/images/no-images.jpg)
C++ 代码实现鼠标右键注册菜单,一级目录和二级目录方法
最近做的一个项目, 在使用windows的时候,我希望在右键菜单中添加一个自定义的选项, 该选项下有我经常使用的多个程序快捷方式, 直接上代码 头文件 #pragma once #include <Windows.h> #include <iostream> #include <string> using namespace std; …...
![](https://img-blog.csdnimg.cn/direct/64d4dcf8752a4e9e83283f758be08596.png)
SQLite 3 优化批量数据存储操作---事务transaction机制
0、事务操作 事务的目的是为了保证数据的一致性和完整性。 事务(Transaction)具有以下四个标准属性,通常根据首字母缩写为 ACID: 原子性(Atomicity):确保工作单位内的所有操作都成功完成&…...
![](https://www.ngui.cc/images/no-images.jpg)
[程序员] 表达的能力
之前看CSDN的问答区,很多时候,感觉问题的描述所要表达的意思非常模糊,或者说描述不清。如果是想回答问题的人想回答问题,首先要搞清楚是什么问题,就需要再问问题主很多细节的东西。三来四去,才能搞清楚具体…...
![](https://img-blog.csdnimg.cn/4a306a138fc5498fb8be80c8bf4edf92.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQnJ1Y2Ut5bWM5YWl5byP6L2v5Lu2,size_8,color_FFFFFF,t_70,g_se,x_16)
wordpress手赚推广/google官方下载
#include<iostream> #include<string> using namespace std;class Person { public://构造函数;调用对象前调用,用于初始化对象;//无参构造;默认构造Person(){cout << "无参构造函数" << endl;…...
![](/images/no-images.jpg)
成都优化网站哪家公司好/手机制作网站的软件
远程服务器返回错误: 404错误、远程服务器返回错误:500错误、 HttpWebResponse远程服务器返回错误:(404、500) 错误。 现象 我们编码实现请求一个页面时,请求的代码类似如下代码: HttpWebRequest req (HttpWebRequest)WebRequest.Create(strUrl);req.Us…...
![](https://img-blog.csdnimg.cn/369bc7fae6f14eae93112e9b66e7ff5c.png)
跨境电商东莞网站建设/什么是网站推广
English Learning - L1-6 从此口语变得简约(下)2022.12.22 周四引言6.2.2 分词非谓语动词作后置定语的三种被动结构1. to be done 将来的动作2. being done 正在进行的3. done 已经完成的6.2.3 分词形容词挑错其它1. 形容词 名词 ed2. 数词 名词 ed答…...
![](/images/no-images.jpg)
犬舍网站怎么做/ks免费刷粉网站推广
// // ViewController.m // UI-AutoLayout // // Created by Bruce on 15/9/6. // Copyright (c) 2015年 Bruce. All rights reserved. // /* frame 原点 自身的尺寸 来确定 自身位置 autoLayout 根据参照视图的位置 来定义自己的位置 autoLayout相对布局 约束视图和视…...
![](https://images2015.cnblogs.com/blog/866948/201601/866948-20160106122956778-422944630.jpg)
wordpress 模版制作/郑州建网站的公司
六、克隆GitHub仓库 1、创建仓库目录,目录位置没有要求,比如D:\learngit。 2、配置ssh(如果不配置会每次都输入用户名和密码) 使用TortoiseGit生成ssh-key:开始菜单找到“”-->“PuTTYgen” 生成Key:并保…...
![](https://img-blog.csdnimg.cn/2021081023025154.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MDkzNTc1,size_16,color_FFFFFF,t_70)
网站源码系统/百度竞价广告投放
一、什么是rpm rpm用于互联网下载包的打包及安装工具,它包含在某些Linux分发版中。它生成具有.RPM扩展名的文●件. RPM是RedHat Package Manager ( RedHat软件包管理工具)的缩写,类似windows的setup.exe ,这一文件格式名称虽然打上了RedHat的标志,但理念…...