当前位置: 首页 > news >正文

指针的学习1

目录

什么是指针?

野指针

造成野指针的原因:

如何避免野指针?

内存和指针

如何理解编址?

指针变量和地址

取地址操作符&

指针变量和解引用操作符

指针变量

如何拆解指针类型?

指针变量的大小

指针变量类型的意义

指针的解引用

指针+整数

void*指针

void* 类型的指针有什么用呢?

const修饰指针

const修饰变量

const修饰指针变量

指针运算

指针+-整数

指针-指针

指针的关系运算

assert断言

使用assert()有几个好处:

指针的使用和传址调用

strlen的模拟实现

传值调用和传址调用


什么是指针?

指针(pointer)是编程语言中的一个对象,利用地址,它的值直接指向存在电脑存储器中另一个地方的值,由于通过地址能找到所需的变量单位,可以说,地址指向该变量单位,因此,将地址形象化的称为“指针”,意思是,通过它能找到以它为地址的内存单元

指针是一个变量,存放内存单元的地址(编号)

#include <stdio.h>
int main()
{int a = 10;//在内存中开辟一组空间int* p = &a;//将a的地址存放在p变量中,p就是一个指针变量return 0;
}

野指针

野指针:指针指向的位置是不可知的(随机的、不正确的、没有明确限制的) 

造成野指针的原因:
  1. 指针未初始化;
  2. 指针越界访问;
  3. 指针指向内存空间释放; 
如何避免野指针?
  • 指针初始化;

如果明确知道指针指向哪里就直接赋值地址,如果不知道指针应该指向哪里,可以给指针赋值NULL

NULL是C语言中定义的一个标识符常量,值是0,0也是地址,这个地址是无法使用的,读写该地址会报错

  • 小心指针越界;
  • 指针指向空间释放即使置NULL;指针使用之前检查有效性 

当指针变量指向一块区域的时候,我们可以通过指针访问该区域,后期不再使用这个指针访问空间的时候,我们可以把该指针置为NULL,因为约定俗成的一个规则就是:只要是NULL指针就不去访问,同时使用指针之前可以判断指针是否为NULL

  • 避免返回局部变量的地址

内存和指针

计算机上CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数据也会放回内存中

把内存划分为一个个的内存单元,每个内存单元的大小取1个字节

1byte=8bit(bit是最小的内存单元)

一个比特位可以存储一个2进制的位1或者0

内存单元的编号=地址=指针

如何理解编址?

首先,必须理解,计算机内有很多的硬件单元,这些硬件单元要互相协同工作。所谓的协作,至少相互之间要能够进行数据传递

但是,硬件与硬件之间是相互独立的,需要用“线”进行通信

CPU和内存之间也是有大量的数据交互的,所以两者必须用线连起来-地址总线

CPU访问内存中的某个字节空间,必须知道这个字节空间在内存的什么位置,而内存中字节很多,需要给内存进行编址

计算机中的编址,并不是把每个字节的地址记录下来,而是通过硬件设计完成的

32位机器有32根地址总线,每根线有两种状态,表示0或1(电脉冲有无),一根线表示2种含义,2根线表示4种含义,32根地址线表示2^32种含义,每一种含义代表一个地址

地址信息被下达给内存,在内存上就可以找到该地址对应的数据,将数据通过数据总线传入CPU内寄存器

指针变量和地址

取地址操作符&

在C语言中创建变量其实就是向内存申请空间

&a取出的是a所占4个字节中地址较小的字节地址

指针--地址

指针变量--存放地址的变量

指针变量和解引用操作符
指针变量

通过取地址操作符(&)拿到的地址是一个数值,这个数值需要存放在指针变量

指针变量也是一种变量,这种变量是用来存放地址的,存放在指针变量中的值都会理解为地址

指针变量中存储的是一个地址,指向同类型的一块内存空间

如何拆解指针类型?
int a=10;
int* pa=&a;

pa左边写的是int*,*说明pa是指针变量,前面的int说明pa指向的是整型(int)类型的对象

int main()
{int a = 10;int* p = &a;*p = 0;//*解引用操作符(间接访问操作符)//*&a=0;printf("%d", a);//0return 0;
}
指针变量的大小

32位机器假设有32根地址总线,每根地址线出来的电信号转换成数字信号后是1或0,把32根地址线产生的2进制序列当作一个地址,那么一个地址就是32个bit位,需要4个字节才能存储

如果指针变量是用来存放地址的,那么指针变量的大小就得是4个字节的空间才可以

同理,64位机器,假设有64根地址线,一个地址就是64个二进制位组成的二进制序列,存储起来就需要8个字节的空间,指针变量的大小就是8个字节

指针变量--存放地址的

一个字节对应一个地址

指针用来存放地址,地址是唯一标示一块地址空间的

总结:

1.32位平台下地址是32个bit位,指针变量大小是4个字节

2.64位平台下地址是64个bit位,指针变量大小是8个字节

3.注意指针变量的大小和类型是无关的,只要是指针类型的变量,在相同的平台下大小都是相同的

指针变量类型的意义

指针的解引用

指针类型决定了指针进行解引用操作时,能够访问空间的大小(对指针解引用的时候有多大的权限--一次能操作几个字节)

int* p;*p能够访问4个字节

char* p;*p能够访问1个字节

doble* p;*p能够访问8个字节

指针+整数

指针类型决定了,指针走一步能走多远(指针的步长,单位是字节)

void*指针

void* 无具体类型的指针(或者泛型指针),这种类型的指针可以用来接受任意类型的地址,但也有局限性,void* 类型的指针不能进行指针的+-整数和解引用的运算

void* 类型的指针有什么用呢?

一般void* 类型的指针是使用在函数参数的部分,用来接收不同类型数据的地址,这样的设计可以实现泛型编程的效果,使得一个函数来处理多种类型的数据

const修饰指针

const修饰变量

变量不再被改变,变量有了常属性,本质仍是变量,常变量(在C++中,const修饰的变量就是常量)

如果要修改变量,就要通过指针来修改,这样就打破了const的限制,是不合理的,所以应该让变量的地址也不能被修改

const修饰指针变量

const修饰指针变量,可以放在*的左边,也可以放在*的右边,意义是不一样的

int main()
{int a = 10;int b = 20;int* const p = &a;//const在*右边//p=&b;//err*p = 100;printf("%d", a);return 0;
}
  • const限制的是指针变量本身,指针变量不能再指向其他变量了,但是可以通过指针变量,修改指针变量指向的内容
int main()
{int a = 10;int b = 20;int const* p = &a;//const在*右边printf("p=%d\n", p);p=&b;//*p = 100;//errprintf("p=%d", p);return 0;
}

运行结果:

  • const放在*左边,限制的是:指针指向的内容,不能通过指针来修改指向的内容,但是可以修改指针变量本身的值(修改指针变量的指向)

*两边可以同时加const

指针运算

指针的作用就是访问内存的

指针的基本运算有三种:

  • 指针+-整数
  • 指针-指针
  • 指针的关系运算
指针+-整数
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int* p = &arr[0];int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);for (i = 0; i < sz; i++){/*printf("%d ", *p);p++;*///等同于下面一句:printf("%d ", *(p + i));//p没有变化}return 0;
}
指针-指针

指针-指针的绝对值是:两个指针之间的元素个数;指针+指针无意义

计算的前提是:两个指针指向了同一块空间

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int my_strlen(char* str)
{char* start = str;while (*str != '\0'){str++;}return str - start;//指针-指针
}
int main()
{//strlen-求字符串长度,‘\0’之前的字符个数char arr[] = "abcdef";int len = my_strlen(arr);printf("%d", len);return 0;
}
指针的关系运算
int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);int* p = arr;//&arr[0]while (p < arr + sz){printf("%d ", *p);p++;}return 0;
}

assert断言

assert.h头文件定义了宏assert(),用于在运行时确保程序符合指定条件,如果不符合,就报错终止运行,这个宏常常被称为“断言”

assert(p != NULL);

上面代码在程序运行到这一行语句时,验证变量是否等于NULL,如果不等于NULL,程序继续运行,否则就会终止运行,并且会给出报错信息提示

assert()宏接受一个表达式作为参数,如果该表达式为真(返回值非零),assert()不会产生任何作用,程序继续运行。如果该表达式为假(返回值为0),assert()就会报错,在标准错误流stderr中写入一条错误信息,显示没有通过的表达式,以及包含这个表达式的文件名和行号

使用assert()有几个好处:

assert()的使用对程序员是非常友好的,它不仅能自动标识文件和出问题的行号,还有一种无需更改代码就能开启或关闭assert()的机制。如果已经确认程序没有问题,不需要再做断言,就在#include <assert.h>语句的前面,定义一个宏NDEBUG

#define NDEBUG
#include <assert.h>

然后,重新编译程序,编译器就会禁用文件中所有的assert()语句,如果程序又出现问题,可以移除这条#define NDEBUG指令(或者把它注释掉),再次编译,这样就重新启用了assert()语句

assert的缺点是:因为引入了额外的检查,增加了程序的运行时间

一般我们可以在Debug中使用,在Release版本中选择禁用assert就行,在VS这样的集成开发环境中,在Release版本中,直接优化掉了,这样在Debug版本写有利于程序员排查问题,在Release版本不影响用户使用时程序的效率

指针的使用和传址调用

strlen的模拟实现
size_t my_strlen(const char* str)//size_t无符号的整型
{size_t count = 0;assert(str != NULL);while (*str != '\0'){count++;str++;}return count;
}
int main()
{char arr[] = "abcdef";size_t len = my_strlen(arr);printf("%d", len);return 0;
}
传值调用和传址调用

下面看一个典型代码,曾几何时,我被它坑过:

void Swap(int x, int y)
{int temp = x;x = y;y = temp;
}
int main()
{int a = 10;int b = 20;printf("交换前:a=%d,b=%d\n", a, b);Swap(a, b);//传值调用printf("交换后:a=%d,b=%d", a, b);return 0;
}

当实参传递给形参的时候,形参是实参的一份临时拷贝,对形参的修改不会影响实参

如果要交换两个数的值,参考以下代码:

void Swap(int* pa, int* pb)
{int temp = *pa;*pa = *pb;*pb = temp;
}
int main(){int a = 10;int b = 20;printf("交换前:a=%d,b=%d\n", a, b);Swap(&a, &b);//传址调用printf("交换后:a=%d,b=%d", a, b);return 0;
}

相关文章:

指针的学习1

目录 什么是指针&#xff1f; 野指针 造成野指针的原因&#xff1a; 如何避免野指针&#xff1f; 内存和指针 如何理解编址&#xff1f; 指针变量和地址 取地址操作符& 指针变量和解引用操作符 指针变量 如何拆解指针类型&#xff1f; 指针变量的大小 指针变量…...

c++:敲桌子

先输出1-100数字&#xff0c;从100个数字中找到这些特殊数字改为敲桌子。 特殊数字&#xff1a;1.7的倍数 2.十位数上有7 3.个位数上有7 #include<iostream> using namespace std; int main() {for (int i 1; i < 100; i) {if (i / 10 7 || i % 10 7|| i % 7 0)…...

Linux中判断文件系统的方法

文章目录 Linux中判断文件系统的方法1.使用mount命令2.使用blkid命令3.使用file命令4.使用fstab文件5.使用df命令&#xff08;这个用的比较多&#xff09;6.使用fsck命令7.使用lsblk命令(推荐-简单好用) Linux中判断文件系统的方法 1.使用mount命令 # 这样查看的只有已经挂载…...

聊聊ClickHouse MergeTree引擎的固定/自适应索引粒度

前言 我们在刚开始学习ClickHouse的MergeTree引擎时&#xff0c;就会发现建表语句的末尾总会有SETTINGS index_granularity 8192这句话&#xff08;其实不写也可以&#xff09;&#xff0c;表示索引粒度为8192。在每个data part中&#xff0c;索引粒度参数的含义有二&#xf…...

20240202在WIN10下使用whisper.cpp

20240202在WIN10下使用whisper.cpp 2024/2/2 14:15 【结论&#xff1a;在Windows10下&#xff0c;确认large模式识别7分钟中文视频&#xff0c;需要83.7284 seconds&#xff0c;需要大概1.5分钟&#xff01;效率太差&#xff01;】 83.7284/4200.1993533333333333333333333333…...

【Linux】基本指令(上)

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:Linux ⚙️操作环境:Xshell (操作系统:CentOS 7.9 64位) 目录 Xshell快捷键 Linux基本指令 ls指令 pwd指令 cd指令 touch指令 mkdir指令 rmdir指令/rm指令 结语 Xshell快捷键 AltEnter 全屏/取消全屏 Tab 进…...

【DB2】—— 一次关于db2 sqlcode -420 22018的记录

情况描述 在DB2 10.5数据库中执行以下SQL语句&#xff1a; SELECT * FROM aa WHERE aa.ivc_typ IN (213,123,12334,345)其中aa.ivc_typ列的类型为VARCHAR(10) 关于执行会发生以下情况 类型转换&#xff1a;SQL引擎会尝试把IN列表中的整数常量转换为VARCHAR(10)类型&#xf…...

账簿和明细账

目录 一. 账簿的意义和种类二. 明细账 \quad 一. 账簿的意义和种类 \quad 账簿是由一定格式、互有联系的账页组成&#xff0c;以审核无误的会计凭证为依据,用来序时地、分类地记录和反映各项经济业务的会计簿籍&#xff08;或称账本&#xff09;。设置和登记账簿是会计工作的重…...

C# Onnx GroundingDINO 开放世界目标检测

目录 介绍 效果 模型信息 项目 代码 下载 介绍 地址&#xff1a;https://github.com/IDEA-Research/GroundingDINO Official implementation of the paper "Grounding DINO: Marrying DINO with Grounded Pre-Training for Open-Set Object Detection" 效果 …...

PyCharm / DataSpell 导入WSL2 解析器,实现GPU加速

PyCharm / DataSpell 导入WSL2 解析器的实现 Windows的解析器不好么&#xff1f;设置WSL2和实现GPU加速为PyCharm / DataSpell 设置WSL解析器设置Interpreter Windows的解析器不好么&#xff1f; Windows上的解析器的确很方便&#xff0c;也省去了我们很多的麻烦。但是WSL2的解…...

Android矩阵Matrix裁切setRectToRect拉伸Bitmap替代Bitmap.createScaledBitmap缩放,Kotlin

Android矩阵Matrix裁切setRectToRect拉伸Bitmap替代Bitmap.createScaledBitmap缩放&#xff0c;Kotlin class MyImageView : AppCompatImageView {private var mSrcBmp: Bitmap? nullprivate var testIV: ImageView? nullconstructor(ctx: Context, attrs: AttributeSet) :…...

TensorFlow2实战-系列教程11:RNN文本分类3

&#x1f9e1;&#x1f49b;&#x1f49a;TensorFlow2实战-系列教程 总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Jupyter Notebook中进行 本篇文章配套的代码资源已经上传 6、构建训练数据 所有的输入样本必须都是相同shape&#xff08;文本长度&#xff0c;…...

故障诊断 | 一文解决,RF随机森林的故障诊断(Matlab)

效果一览 文章概述 故障诊断 | 一文解决,RF随机森林的故障诊断(Matlab) 模型描述 随机森林(Random Forest)是一种集成学习(Ensemble Learning)方法,常用于解决分类和回归问题。它由多个决策树组成,每个决策树都独立地对数据进行训练,并且最终的预测结果是由所有决策…...

DAO设计模式

概念&#xff1a;DAO(Data Access Object) 数据库访问对象&#xff0c;**面向数据库SQL操作**的封装。 &#xff08;一&#xff09;场景 问题分析 在实际开发中&#xff0c;针对一张表的复杂业务功能通常需要和表交互多次&#xff08;比如转账&#xff09;。如果每次针对表的…...

【Midjourney】新手指南:参数设置

1.--aspect 或 --ar 用于设置图片长宽比&#xff0c;例如 --ar 16:9就是设置图片宽为16&#xff0c;高为9 2.--chaos 用于设置躁点&#xff0c;噪点值越高随机性越大&#xff0c;取值为0到100&#xff0c;例如 --chaos 50 3.--turbo 覆盖seetings的设置并启用极速模式生成…...

阿里云a10GPU,centos7,cuda11.2环境配置

Anaconda3-2022.05-Linux-x86_64.sh gcc升级 centos7升级gcc至8.2_centos7 yum gcc8.2.0-CSDN博客 paddlepaddle python -m pip install paddlepaddle-gpu2.5.1.post112 -f https://www.paddlepaddle.org.cn/whl/linux/mkl/avx/stable.html 报错 ImportError: libssl.so…...

RTSP/Onvif协议视频平台EasyNVR激活码授权异常该如何解决

TSINGSEE青犀视频安防监控平台EasyNVR可支持设备通过RTSP/Onvif协议接入&#xff0c;并能对接入的视频流进行处理与多端分发&#xff0c;包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等多种格式。在智慧安防等视频监控场景中&#xff0c;EasyNVR可提供视频实时监控直播、云端…...

React16源码: React中event事件对象的创建过程源码实现

event 对象 1 &#xff09; 概述 在生产事件对象的过程当中&#xff0c;要去调用每一个 possiblePlugin.extractEvents 方法现在单独看下这里面的细节过程&#xff0c;即如何去生产这个事件对象的过程 2 &#xff09;源码 定位到 packages/events/EventPluginHub.js#L172 f…...

深度学习(12)--Mnist分类任务

一.Mnist分类任务流程详解 1.1.引入数据集 Mnist数据集是官方的数据集&#xff0c;比较特殊&#xff0c;可以直接通过%matplotlib inline自动下载&#xff0c;博主此处已经完成下载&#xff0c;从本地文件中引入数据集。 设置数据路径 from pathlib import Path# 设置数据路…...

AI工具【OCR 01】Java可使用的OCR工具Tess4J使用举例(身份证信息识别核心代码及信息提取方法分享)

Java可使用的OCR工具Tess4J使用举例 1.简介1.1 简单介绍1.2 官方说明 2.使用举例2.1 依赖及语言数据包2.2 核心代码2.3 识别身份证信息2.3.1 核心代码2.3.2 截取指定字符2.3.3 去掉字符串里的非中文字符2.3.4 提取出生日期&#xff08;待优化&#xff09;2.3.5 实测 3.总结 1.简…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接&#xff1a;A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串&#xff0c;只有在同时为 o 时输出 Yes 并结束程序&#xff0c;否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制

使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下&#xff0c;限制某个 IP 的访问频率是非常重要的&#xff0c;可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案&#xff0c;使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...

NPOI Excel用OLE对象的形式插入文件附件以及插入图片

static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...

解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist

现象&#xff1a; android studio报错&#xff1a; [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决&#xff1a; 不要动CMakeLists.…...