指针基础知识超详细讲解(C语言)(上)

news2024/11/27 8:24:56

还在为不懂指针而感到烦恼么?那还在等什么呢快来看看吧!冲冲冲!
在这里插入图片描述

文章目录

  • 1,认识指针
  • 2,指针变量
    • 指针变量的定义
    • 指针变量的大小
    • const修饰指针变量
  • 3,指针的运算
  • 4, 野指针
    • 概念
    • 成因
    • 规避
  • 5, assert断言
  • 6, 结尾

1,认识指针

什么是指针?
首先我们都知道数据是储存在内存之中的,我们可以把内存当成一座公寓,里面有许多房间,每个房间中储存着数据,但是我们会发现一个问题,我们根本不知道我们想要的数据在哪个房间,那么如果我们给每个房间都装上一个门牌号,只要告诉我们数据所在的房间的房间号,那么我们就可以很快的找到所需要的数据,而在计算机中这个门牌号我们有一个名字来称呼它, “地址”。
在这里插入图片描述
而所谓的指针也就是内存地址,我们常说的指针一般指的是指针变量,指针变量是用来存放内存地址的变量。

2,指针变量

指针变量的定义

既然指针变量是个变量那么它肯定可以储存数据,指针变量的内容存储的是其指向的对象的首地址,指向的对象可以是变量(指针变量也是变量),数组,函数等占据存储空间的实体。
我们先来写一个最简单的指针变量。
int a = 10;
int* pa = &a;&是取地址操作符可以取出a的地址
printf(“%p\n%d”,pa,*pa);打印地址时需要用的占位符是%p
我们可以看到输出的结果是
在这里插入图片描述
第一行打印的就是变量a的地址(十六进制),而第二行打印的是a的地址里存放的整形数据,*是解引用操作符,的作用是引用指针指向的变量值,引用其实就是引用该变量的地址,“解”就是把该地址对应的东西解开,解出来,就像打开一个包裹一样,那就是该变量的值了,所以称为“解引用”。
int
pa = &a;其中pa是指针变量的名字,*的意思是指pa是指针变量,而int的意思是pa所指向的地址中存放的数据的类型是整形,那么我们发现a的类型是int时我们要用 int * pa = &a;那么如果a是字符类型的话我们就要这样定义 char * pa = &a;
如果a是浮点型我们就要用 float * pa = &a;
如果我们需要修改a的值我们可以直接用指针变量来进行
*pa = 20;//*pa等价于a因此这一句等价于a=20;

指针变量的大小

想知道指针变量的大小我们可以尝试用如下代码

#include<stdio.h>
int main()
{
	int a = 10;
	int* pa = &a;
	char b = '1';
	char* pb = &b;
	float c = 1.0;
	float* pc = &c;
	printf("%zd %zd %zd", sizeof(pa), sizeof(pb), sizeof(pc));
	return 0;
}

在x86的环境下输出的结果为
在这里插入图片描述

在x64的环境下输出的结果为
在这里插入图片描述
我们可以发现指针变量的大小与所存放的地址指向的数据的数据类型无关,在x86环境下地址是由32位2进制数字组成的每一位占1个bit所以它的大小为4个字节,在x64的环境下地址是由64位2进制数字组成的每一位占1个bit所以它的大小为8个字节.

const修饰指针变量

我们知道const可以修饰普通变量如:
const int a = 10;
经过修饰后a这个变量会获得常量属性使a的值无法再更改,同理const在修饰指针变量的时候也就类似的效果。
根据不同需求,有三种不同效果的书写方式
1,const int* pa = &a;
2, int* const pa = &a;
3, const int* const pa = &a;
首先第一种我们可以理解为const和a结合了,无法更改pa中储存的地址,但是我们仍然可以更改a的值。
pa=20;但如果写int b = 20;pa = &b;那么就会报错。
第二种我们可以理解为const与a结合了,无法更改a的值但是我们可以更改pa储存的地址。
如int b = 20; pa=&b;但是如果写*pa=20时会显示报错
第三种则是前两种写法的结合既无法更改pa中储存的地址,又不可以更改a的值。

3,指针的运算

为了方便大家理解指针的运算我们可以先写出如下代码

#include<stdio.h>
int main()
{
	int a = 10;
	int* pa = &a;
	char b = '1';
	char* pb = &b;
	float c = 1.0;
	float* pc = &c;
	long long d = 0;
	long long* pd = &d;
	double e = 0.0;
	double* pe = &e;
	printf("%p %p %p %p %p\n", pa, pb, pc,pd, pe);//打印指针变量的地址
	printf("%p %p %p %p %p\n", pa+1, pb+1, pc+1, pd+1, pe+1);//打印指针变量+1之后的地址
	return 0;
}

我们运行之后的结果为(每次运行的时候结果会不一样因为每次数据不一定都分配到同一个地址)
在这里插入图片描述
对于int和float类型的指针每+1其地址会+4,
对于char类型的指针每+1其地址会+1,
对于double
和龙long long*类型的指针每+1其地址会+8,
这是为什么呢?我们知道int和float类型的数据占4个字节大小,对指针变量+1会使其跳过当前数据类型大小的字节跳到一个新地址,所以指针的加减运算与其是什么类型的指针有关。也就是说我们可以通过±整形来改变指针中储存的地址。
那么指针与指针之间可不可以进行运算呢?回答当然是可以,但是我们暂且先不讲之后再讲。(#^ . ^#)

4, 野指针

概念

野指针,正如它的名字,“野”,就像野鸡野鸭野狗一样不受人类的控制,野指针你也没法控制,因为你根本不知道它指向了那一位置。
定义:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)指针变量在定义时如果未初始化,其值是随机的,指针变量的值是别的变量的地址,意味着指针指向了一个地址是不确定的变量,此时去解引用就是去访问了一个不确定的地址,所以结果是不可知的。
由此可见野指针是十分危险的,那让我了解了解野指针的成因。

成因

1,指针变量未初始化
任何指针变量刚被创建时,它的值是随机的,它会乱指。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。如果没有初始化,编译器会报错“ ‘point’ may be uninitialized in the function ”。
2,指针释放后之后未置空
有时指针在free或delete后未赋值 NULL,便会使人以为是合法的。别看free和delete的名字(尤其是delete),它们只是把指针所指的内存给释放掉,但并没有把指针本身干掉。此时指针指向的就是“垃圾”内存。释放后的指针应立即将指针置为NULL,防止产生“野指针”。(读起来比较拗口,简单来说就是指针中所储存的地址指向的数据被清除了,但是指针并没有被清除,那么指针指向的东西就是无意义的垃圾内存,这时候它就变为了野指针。)
3,数组越界
打个比方比如有个数组 int a[10];而你却这么定义指针int* pa = &a[11];这样数组就越界了,指针所指的位置不知道有什么所以也变成了野指针。

规避

1,初始化时置 NULL
指针变量一定要初始化为NULL或者已知的值,因为任何指针变量(除了static修饰的指针变量)刚被创建时不会自动成为NULL指针,它的值是随机的。
2,释放时置 NULL
当指针p指向的内存空间释放时,没有设置指针p的值为NULL。delete和free只是把内存空间释放了,但是并没有将指针p的值赋为NULL。通常判断一个指针是否合法,都是使用if语句测试该指针是否为NULL,或者使用assert断言(马上讲)。

5, assert断言

什么是断言?
断言是一种用于调试的语句,可以用来检查程序运行时一些前提条件是否满足,如果不满足条件在运行时就会报错。
那么怎么使用呢?我们先用如下代码让大家认识一下断言语句的写法。

#include<stdio.h>
#include<assert.h>//断言的头文件
int main()
{
	int a = 10;
	assert(a == 20);//判断a是否等于20
	return 0;
}

显然条件不成立运行时会出现如下结果。在这里插入图片描述
那我们为什么要在指针章节来介绍这个语句呢?众所周知野指针是非常危险的所以为了避免出现野指针的情况我们通常要用assert语句判断一下该指针是否为NULL,以防止野指针。当条件成立时assert就不会使程序报错,但是一段代码中可能会用许多次assert在调试完成后我们要一个一个的把他们删除就会变得非常麻烦,其实想解决这个问题也非常简单,只需要加上一句#define NDEBUG就可以禁用assert如下。

`#define NDEBUG
#include<stdio.h>
#include<assert.h>
int main()
{
	int a = 10;
	assert(a == 20);
	return 0;
}`

这样再运行assert语句就会失效不会再报错。

6, 结尾

关于指针的基本知识还有很多所以我决定拆成三期来讲,如果觉得讲的不错的小伙伴希望也能再看看我之后要写的两期,我尽量加快更新(学习太紧张了o(╥﹏╥)o)。希望小伙伴们都能学好指针,为了自己的目标继续前进吧!
第二期链接,冲冲冲!
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1287004.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Sketch利器大公开:十款使用率超高的懒人插件汇总

在设计领域&#xff0c;Sketch以其高效小巧的优势赢得了众多设计团队的青睐&#xff0c;帮助全球设计师创作了许多令人难以置信的作品。在使用Sketch的过程中&#xff0c;辅助使用一些Sketch插件可以让我们更有效地完成设计任务。在本文中&#xff0c;我们将揭示大厂设计师的收…

Mysql主从复制原理和三种复制:异步、同步、半同步(主的binlog、从的relaylog)

借鉴&#xff1a;https://zhuanlan.zhihu.com/p/651625709 https://www.jb51.net/article/258847.htm 一&#xff1a;Mysql主从复制原理 MySQL的复制原理分三步 1.在主库上把数据更改&#xff0c;记录到二进制日志&#xff08;Binary Log&#xff09;中。 2.从库将主库上的日志…

分享86个选项卡TABJS特效,总有一款适合您

分享86个选项卡TABJS特效&#xff0c;总有一款适合您 86个选项卡TABJS特效下载链接&#xff1a;https://pan.baidu.com/s/1NBtPP2tT5YQqi6c744tCqg?pwd6666 提取码&#xff1a;6666 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0…

软件测试面试题解析--什么题是必问的?

设计测试用例的主要方法有哪些&#xff1f;简述一下缺陷的生命周期&#xff1f;测试流程&#xff1f;项目流程&#xff1f;验收测试中和β测试区别&#xff1f;如何维护测试用例&#xff1f;每天测多少用例怎么分配的测试的一天能找多少bug你在上一家公司&#xff0c;写没写过测…

【Maven】更新依赖索引

有时候给idea配置完maven仓库信息后&#xff0c;在idea中依然搜索不到仓库中的jar包。这是因为仓库中的jar包索引尚未更新到idea中。这个时候我们就需要更新idea中maven的索引了&#xff0c;具体做法如下&#xff1a; 打开设置----搜索maven----Repositories----选中本地仓库-…

装修流程篇

装修流程 https://www.xiaohongshu.com/explore/627ba70d00000000210357b3 https://www.xiaohongshu.com/explore/63b6bc0c000000002203776f 半包装修流程 https://www.xiaohongshu.com/explore/64e5ea3b0000000003021711 户型图 效果 https://www.xiaohongshu.com/ex…

P5 Linux 标准C库函数

目录 前言 01 标准输入、标准输出和标准错误 02 打开文件 fopen() 03 新建文件的权限 04 fclose()关闭文件 05 读文件和写文件 06 库函数 fseek 定位 6.1 lseek的使用 07 ftell()函数 前言 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《C_Chen…

sql 读写注入

root高权限读写注入 load_file 读取文件 大姐我真是整了半天都是nullnullnull缝子 结果看了半天这个my.ini是被隐藏的大哥 load_file()读取文件结果为null_mysql load_file返回null解决办法_黑小薛的博客-CSDN博客 终于读出来了 此时参数值系统变量 secure_file_priv已经被修…

使用DevEco Studio时遇见的错误情况与问题

第一个 问题:打开项目文件,控制台报错 hvigor ERROR: Unable to find sdk.dir in local.properties or OHOS_BASE_SDK_HOME in the system environment path. 解决办法:在项目根目录中打开local.properties。如果没有local.properties,自己创建。 在local.properties中填…

[ROS2] --- 手动编写一个节点

1 准备工作 1.1 创建/编译工作空间 创建工作空间 mkdir -p ~/dev_ws/src cd ~/dev_ws/src1. 2 创建功能包 ros2 pkg create learning01_write_a_node --build-type ament_cmake --dependencies rclcpp可以看到目录结构如下&#xff1a; 1. 3 创建节点 在learing01_write…

234 回文链表

解题思路&#xff1a; \qquad 由于链表的结构特点&#xff0c;访问链表中的元素的时间复杂度为O(n)。相比较而言&#xff0c;使用数组会方便很多&#xff0c;实现O(1)访问。 \qquad 所以这个题&#xff0c;可以先遍历一遍把数值存到数组中&#xff0c;再使用双指针判断是否是…

【Kubernetes】可视化UI界面Dashboard

安装和配置k8s可视化UI界面 一、安装Dashboard1.1、上传镜像并解压1.2、安装dashboard组件1.3、修改service1.4、访问dashboard 二、通过Token令牌访问Dashboard2.1、创建clusterrolebinding2.2、获取token2.3、使用token登录 三、通过kubeconfig文件访问Dashboard3.1、创建clu…

音视频技术开发周刊 | 322

每周一期&#xff0c;纵览音视频技术领域的干货。 新闻投稿&#xff1a;contributelivevideostack.com。 超级AI不会主宰人类&#xff0c;但人工智能必须开源&#xff01;LeCun最新采访引全网300万人围观 LeCun最新访谈视频中&#xff0c;再次坦露了自己对开源AI的看法。超级AI…

面试 Java 框架八股文十问十答第二期

面试 Java 框架八股文十问十答第二期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1.AOP的术语&#xff0c;以及两种动态代理实现方法&#xff0c;以及它们的区别…

“快慢指针”思想在物理或者逻辑循环中的应用

1 基础概念 1.1 什么是物理循环和逻辑循环&#xff1f; 物理循环是指物理索引访问顺序上相邻&#xff0c;逻辑上也相邻&#xff0c;比如循环链表&#xff0c;逻辑循环则指物理的索引上不一定相邻 1.2 快慢指针本质上可以解决逻辑循环问题&#xff0c;而物理循环也属于逻辑循…

MCS-51系列与AT89C5x系列单片机的介绍与AT系列的命名规则

MCS-51系列与AT89C5x系列单片机 主要涉及MCS-51系列与AT89C5x系列单片机的介绍与AT系列单片机的命名规则 文章目录 MCS-51系列与AT89C5x系列单片机一、 MCS-51系列单片机二、AT89C5x系列单片机2.1 AT89C5x/AT89S5x系列单片机的特点2.2 AT89系列单片机的型号说明2.2.1 前缀2.2.2…

握这些员工管理技巧,助你打造高效团队!

人力资源是一个组织中至关重要的一环&#xff0c;而员工管理是确保团队高效运转的关键因素之一。一个优秀的经理需要具备多方面的技巧和能力&#xff0c;以便激发员工的潜力&#xff0c;促进合作和增加团队的效率。在这里&#xff0c;我将分享一些实用的员工管理技巧&#xff0…

使用肘部法则选择KMeans聚类中的k值

在这篇文章中&#xff0c;我们将讨论如何选择最好的k&#xff08;聚类数&#xff09;的k-Means聚类算法。 肘部法则简介 任何无监督算法的基本步骤是确定数据可以被聚类到的聚类的最佳数量。因为我们在无监督学习中没有任何预定义数量的聚类。我们倾向于使用一些可以帮助我们…

sar命令详解

sar是强大的linux系统活动状况收集、报告命令。可以收集CPU&#xff0c;内存&#xff0c;磁盘I/O&#xff0c;网络等诸多数据。对于性能分析是个可靠的利器。 安装 sar命令是sysstat下的一个工具&#xff0c;所以安装sar需要首先安装sysstat命令&#xff0c;可以考虑yum安装或…

UE Windows平台下Linux的交叉编译项目打包

UE Windows平台下Linux的交叉编译项目打包 交叉编译&#xff08;Cross-compilation&#xff09; 使得在以Windows为中心的工作流程中工作的游戏开发者能够以Linux为目标对项目进行打包。目前&#xff0c;只有Windows支持交叉编译。 交叉编译支持的平台 Windows | Linux-x86_…