【C语言】指针篇-初识指针(1/5)
🌈个人主页:是店小二呀
🌈C语言笔记专栏:C语言笔记
🌈C++笔记专栏: C++笔记
🌈喜欢的诗句:无人扶我青云志 我自踏雪至山巅
文章目录
- **内存和地址(知识铺垫(了解即可))**
- 如何理解编址
- **指针变量**
- **指针的初始化和赋值运算**
- **指针变量的大小**
- **指针变量类型的意义**
- **指针+-整数**
- const修饰指针
- const修饰变量
- const修饰指针变量
- **指针运算**
- **野指针**
- **assert断言(assert.h头文件定义了宏assert())**
- **传值调用和传址调用**
内存和地址(知识铺垫(了解即可))
内存(Memory)是计算机的重要部件,也称内存储器和[主存储器]它用于暂时存放CPU中的运算数据,以及与硬盘等[外部存储器]交换的数据。
当CPU(中央处理器)在处理数据的时,需要的数据是在内存中读取的,处理后的数据也会放回内存中。
问题:那么内存空间如何高效的管理的呢?
- 是将内存划分为一个个的内存单元,每个内存单元的大小取一个字节(一个字节等于八个比特位,比特bit是二级制位(Binary digit)的简称,一个二进制包含的信息量成为一比特bit。)
- 每个内存单元都有一个编号(相当于宿舍房间的门牌号),有这个内存单元的编号,CPU就可以通过这个编号快速找到一个内存空间
- 在计算机中我们把内存单元的编号也称为地址。C语言给地址起了个新名字位指针,这里解释了计算机中内存是按照字节编址的,也是每个字节都有唯一的地址,而对于比特是没有地址
- 可以理解为:内存单元的编号==地址 ==指针;
如何理解编址
CPU访问内存中的某个字节空间,必须知道这个字节空间在内存的什么位置,因为内存中有很多字节,所以需要给内存进行编制,计算机中的编址不是把每个字节的地址都记录下,而是通过硬件设计完成。
钢琴、吉他上面没有写上“都瑞咪发嗦啦”这样 的信息,但演奏者照样能够准确找到每⼀个琴弦的每⼀个位置,这是为何?因为制造商已经在乐器硬件层面上设计好了,并且所有的演奏者都知道。本质是⼀种约定出来的共识!
首先,计算机内是有很多硬件单元的,而硬件单元是要相互协同工作,既然是协同工作,至少之间要能够进行数据传递,但是硬件和硬件之间是互相独立的,那么如何通信呢?那么需要通过"线"连起来,那么CPU和内存之间也是有大量的数据交互,所以这两者必须也用线连起来。
这里只关注一组线:地址总线
可以简单理解为32位机器有32根地址总线,那么每根线只有两态,表示0,1【电脉冲有无】,一根线能代表两种含义,两根线就能表示四种含义,依次类推。32根地址线,就能表示2^32种含义,每一种含义都代表一个地址。
地址信息被下达给内存,在内存上,就可以找到地址对应的数据,将数据在通过数据总线传入CPU内寄存器中
##正文
指针变量
了解内存和地址的关系,可知创建变量需要向内存申请一定大小的空间
指针变量时用于存放其他变量的地址(其他变量在内存中存储的位置),简称指针。指针本身是一种变量,需要占用一定大小的空间的,用来存放指针值(指针变量本身的地址)。
指针定义说明的一般形式:
类型说明符(void) *指针变量名(name);
*表示pa是一个指针变量
类型说明符表示指针变量指向什么类型的对象
比如:
int p=1;char q='a';
int *pa=&p;说明指针变量pa是指向int类型变量的指针
char *qa=&q;说明指针变量qa是指向char类型变量的指针
注意:
- 指针变量值表达的是某个数据对象的地址,只允许取正的整数值的。
- 但是他不等同于整形类型变量,如果指针变量取0值,即为NULL(空),则表示指针指向对象不存在,为空指针
指针的初始化和赋值运算
```类型说明符 指针变量名=初始化地址值``
注意:
- 初始化中也是将初始地址赋值给指针变量
- 在赋值语句中,变量的地址也只能赋值给指针变量,这种赋值运算操作限制在同类之间
## 指针运算符(& 、*)
取地址操作符 &:返回存放其他变量的内存地址(只限于一个具体的变量或数值元素,不可用于表达式)
int p=1;
int *pa=&p;//这里pa存放p的地址
*解引用操作符 :返回地址(指针标量指向的地址)中的变量值
int p=1;
int *pa=&p;//这里pa存放p的地址
int ret=*pa//ret==1
这里样对于变量的修改,多了一种途径,写代码就会更加灵活
指针变量的大小
通过前面“内存和地址”,32位机器有32根地址总线,每根地址线出来的电信号转换成数字信号后(1或0),将32根地址线产生的二级制序列当做一个地址,那么一个地址需要32个bit位,也是4个字节存储。那么在64位机器,有64根地址总线,一个的地址就是64个二级制位组成的二级制序列,那么一个需要地址需要64个bit位,也是8个字节存储。
小总结:
指针变量是用来存放地址的,那么在不同机器下,地址的大小也会影响指针变量的大小
- 32位平台下地址是32个bit位,指针变量大小是4个字节
- 64位平台下地址是64位bit位,指针变量大小是8个字节
- 指针变量的大小和类型是无关的,只要指针类型的变量,在相同的平台下,大小都是相同的
指针变量类型的意义
既然指针变量的大小与指向的类型无关,那么为什么要区分各种指针类型呢?
那当然是因为指针类型在其他方面有特殊的意义
#include <stdio.h>int main()
{int n=0x11223344;int *p1=&n;*p=0;int m=0x11223344;char *p2=(char *)&m;//原本&m 应该由int *类型存储*pc=0;return 0;
}
这里涉及到了大小端的知识,理解指针类型对解引用的影响
如图可得的,n的四个字节全部改为0,而m只是第一个字节改为0
结论:指针的类型决定,对指针解引用能修改几个字节的权利
拿上面的例子:
-
n是int 类型(占四个字节,其中两个数字算一个字节),int *指针类型指向n的地址,*当解引用的时候,int 指针只能访问四个字节
-
m是char 类型(占一个字节,其中两个数字算一个字节),char *指针类型指向m的地址,*当解引用的时候,char 指针只能访问一个字节(修改44)
指针±整数
代码:
#include <stdio.h>
int main()
{
int n = 10;
char *pc = (char*)&n;
int *pi = &n;
printf("%p\n", &n);printf("%p\n", pc);
printf("%p\n", pc+1);printf("%p\n", pi);
printf("%p\n", pi+1);
return 0;
}
结论:指针类型决定了指针向前或者向后走一步有多大(距离)。char *类型的指针变量+1跳过1个字节,int *类型的指针变量+1跳过了4个
const修饰指针
const修饰变量
如果不希望这个变量被修改,可以使用const进行限制。
int main()
{const int m=0;m=1;//ok?
}
上边的代码:使用const修饰(语法上加了限制),只要对n变量进行修改,就不符合语法规则,就会报错,对于const修饰后的变量是不能进行直接修改的.
通过上面刚学的一种修改变量的方法,通过n的地址取修改n值(打破语法规则)
int main()
{const int m=0;int *p=&m;*p=20;return 0;
}
这样子n变量还能被修改,const使用的就没有多大意义,这样子不是自己打自己脸吗?那么有什么办法p拿到了n的地址也不能修改n值(对指针下手)。
const修饰指针变量
int main()
{int m=0;int n=1;第一种:const int *pa=&m;pa=&n;*pa=10;//右边为不可修改值第二种: int * const pa=&m;pa=&n;//左边为不可修改值*pa=10;
}
总结:当const修饰指针变量的时候
- const放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变,但是指针变量本身的内容可变
- const放在*的右边,修饰的是指针变量本身,保证指针变量的内容不能修改,但是指针指向的内容,可以通过指针改变
指针运算
指针的基本运算有三种
1.指针±整数(在连续存放的数据,只要知道第一个元素的地址,就可以知道后面所有的地址),这里整数也称为偏移量
数组int main()
{int nums[]={1,2,3,4,5};int *p=nums;//首元素的地址printf("%d",*(p+2));//那么p的偏移量为+2,打印结果是3return 0;
}
2.指针-指针
int main()
{char *p="abcd";//不要忘记还有'\0'char *s=p;while(*p!='\0'){p++;}int ret=p-s;//4printf("%d",ret); return 0;
}
结论:指针减指针表示指向两个指针之间的元素个数,求首元素到某个元素之间相错个数(在连续存储的情况下)
3.指针的关系运算
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]);
while(p<arr+sz) //指针的⼤⼩⽐较
{
printf("%d ", *p);
p++;
}
return 0;
野指针
野指针;指针指向位置是不可知的(具有不确定因素)
下列有几种野指针的成因:
1.指针未初始化int *p;
2.指针越界访问(数组越界访问)
int nums[10]={0};
int *p=nums;
for(int i=0;i<11;i<++)
{*(p++)=i;
}
3.指针指向的空间释放
int* test()
{int m=0;return &m
}
int mian()
{int *p=test();printf("%d\n",*p);return 0;
}
m是一个被销毁的局部变量,这里指针指向m所在的位置空间是不明确的,原本属于m的空间,可能被给了其他变量占用,这样子就导致程序可能不能达到预期效果
规避野指针
1.确定指针指向一片有效的空间,如果指针目前没有指向,可以为指针赋值为NULL,NULL是一个定义的标识符常量,值为0,0也是地址,这个地址是无法使用的
2.当指针变量不再使用,设置为NULL,指针使用之前检查有效性(判断语句或者断言)
3.规定:只要指针为NULL就不去访问,但是给野指针赋值为NULL,将野指针暂时管理起来,还是存在危险的。
assert断言(assert.h头文件定义了宏assert())
作用:当符合程序符合指定条件,没有啥影响,如何不符合条件,就会报错终止运行。而这个宏常称为断言。
具体使用细节:
#inlclude <assert.h>
int p=0
assert(p!=0);
- assert()宏接受一个表达式作为参数。如果表达式为真(返回值为非零),没有啥影响,程序继续执行。
- 如果表达式为假(返回值为零),assert()就会报错,在标准报错流中stderr中写入一条错误信息(显示没有通过的表达式、表达式文件名和行号)
好处:
- 自动标识文件和出问题的行号
- 存在一种无需更改代码就能开启或关闭assert()的机制,就是在
#include <assert.h>
语句的前面,定义一个宏NDEBUG
#define NDEBUG
#include <stdio.h>
对于宏NEDBUG
使用时,编译器就会禁用文件中assert()语句
。如果程序出现问题,可以注释掉,就可以重新启动assert()语句
不足:assert()
的引入了额外的检查,增加了程序的运行时间
- 在
debug
和release
版本下,一般debug
调试中使用,在release(发布版本)
选择禁用assert
,提高程序效率。 - 在VS这样的集成开发环境中,
release
版本中,直接优化掉了。
总结:debug版本有利于程序员排查问题,release版本不行用户使用程序的效率
传值调用和传址调用
在函数章节,提到形参是实参的一份临时拷贝,形参的改变不会影响到实参
#include <stdio.h>
void Swap(int x,int y)
{int tmp=x;x=y;y=tmp;
}
int main()
{int a=10;int b=20;Swap(a,b);
}
这里x和y的值等于a和b的值,但是各属于独立的空间,那么x和y值交换,不会影响到实参a和b值的交换
对于这种将变量的数值传递给函数,调用方法:传值调用
对此可以使用指针
#include <stdio.h>
void Swap(int *x,int *y)
{int tmp=*x;*x=*y;*y=tmp;
}
int main()
{int a=10;int b=20;Swap(&a,&b);
}
这里在main函数中将a和b的地址传递给了Swap函数,Swap函数通过地址间接的操作main函数中的a和b
对于这种将变量的地址传递给函数,调用方法:传址调用
谢谢大家的观看,这里是个人笔记,希望对你学习C有帮助。
相关文章:

【C语言】指针篇-初识指针(1/5)
🌈个人主页:是店小二呀 🌈C语言笔记专栏:C语言笔记 🌈C笔记专栏: C笔记 🌈喜欢的诗句:无人扶我青云志 我自踏雪至山巅 文章目录 **内存和地址(知识铺垫(了解即可))**如何理解编址**指针变量*…...

【御控物联】物联网平台设备接入-JSON数据格式转化(场景案例四)
文章目录 一、背景二、解决方案三、在线转换工具四、技术资料 一、背景 物联网平台是一种实现设备接入、设备监控、设备管理、数据存储、消息多源转发和数据分析等能力的一体化平台。南向支持连接海量异构(协议多样)设备,实现设备数据云端存…...

stack和queue模拟实现
前言 上一期我们介绍了stack和queue的使用,本期我们来模拟实现一下他们! 本期内容介绍 容器适配器 deque介绍 为什么stack和queue的底层选择deque为默认容器? stack 模拟现实 queue 模拟实现 什么是容器适配器? 适配器是一种设…...
docker操作
1、容器生命周期管理命令 docker run docker run --name tomcat8 -d -p 28080:8080 tomcat:8.5.38 docker run -i --name hausf --network bridge --ip 172.17.0.10 ubuntu:20.04 /bin/bash docker run -d --name hausf --net host ubuntu:20.04 /bin/bash docker run…...
分布式锁介绍
引言 分布式锁是一种用于协调不同进程或线程对共享资源的访问控制的机制。在分布式系统中,由于多个节点可能同时访问或修改同一资源,因此需要一个中心化的协调机制来确保资源的访问是有序的,避免数据不一致的问题。 分布式锁的特性…...

Unity 获取RenderTexture像素颜色值
拿来吧你~ 🦪功能介绍🌭Demo 🦪功能介绍 💡不通过Texture2D 而是通过ComputerShader 提取到RenderTexture的像素值,效率有提升哦! 💡通过扩展方法调用,方便快捷:xxxRT.G…...

Tomcat以服务方式启动,无法访问网络共享目录问题
关于“Tomcat以服务方式启动,无法访问网络共享目录问题”解决方式如下: 1、通过doc命令【services.msc】打开本地服务找到,找到tomcat服务所在位置 2、右键打开Tomcat服务的属性 3、选择 登陆选项卡 4、选择“此账户”选项,并…...

SVN的介绍
首先SVN是什么: Apache下的一个开源的项目Subversion,通常缩写为 SVN,是一个版本控制系统。 版本控制系统是一个软件,它可以伴随我们软件开发人员一起工作,让我们编写代码的完整的历史保存下来。 目前它的各个版本的…...
ZYNQ-700呼吸灯
参考野火例程 实现呼吸灯即要调整led亮的占比时间,完成视觉上看起来由灭到亮或者由亮到灭的过程。 如果主频为50MHz,理论上一秒钟我们可以控制50_000_000次led的亮和灭,肉眼不可能分辨出来每一次亮灭,如果这50M我们设定为间隔一…...

UE5学习日记——制作多语言版本游戏,同时初步学习UI制作、多语言化、控制器配置、独立进程测试、打包配置和快速批量翻译等
所有的文本类,无论变量还是控件等都能实现本地化,以此实现不同语言版本。 在这里先将重点注意标注一下: 所有文本类的变量、控件等都可以多语言;本地化控制板中收集、编译时,别忘了编译这一步;支持批量复制…...
电脑重启后word文档空白或打不开,word无法自动修复,如何拯救
最近编辑word文档,写了好几个星期的内容随着电脑重启的一瞬间,灰飞烟灭,让我简直痛不欲生! 好在,天无绝人之路,以下两个方法拯救了地球 第一,普通的文档word自动修复不好使的时候,…...
MVC和MVVM这两种设计模式的区别
一、MVC和MVVM是什么? MVC是Model-View-Controller的简写,Model就是模型,对应后端数据,View就是视图对应用户界面,Controller就是控制器,对应页面的业务逻辑。 MVC的工作机制原理就是,用户操作…...
淘宝app端商品详情数据采集(商品价格,商品库存,商品销量,商品优惠券)
在淘宝App端采集商品详情数据,包括商品价格、库存、销量以及优惠券信息,可以通过多种方式实现。以下是几种常见的方法: 使用淘宝开放平台API: 淘宝开放平台提供了一系列API接口,这些接口允许开发者获取淘宝商品的详细…...

第42篇:随机存取存储器(RAM)模块<一>
Q:本期开始我们分期介绍随机存取存储器(RAM)模块及其设计实现方法。 A:随机存储器RAM,即工作时可以随时从一个指定地址读出数据,也可以随时将数据写入一个指定的存储单元。 DE2-115开发板上的Cyclone IV …...
在Java中实现记录1000万用户连续7天登录的功能,可以使用Redis的Bitmap来跟踪每个用户的登录状态
在Java中实现记录1000万用户连续7天登录的功能,可以使用Redis的Bitmap来跟踪每个用户的登录状态。以下是一个简化的Java示例,使用了Jedis库作为Redis的Java客户端。 首先,确保你已经在项目中添加了Jedis的依赖。如果你使用Maven,…...
深入探讨VIVE OpenXR:为Unity开发者的全面指南
随着虚拟现实(VR)和增强现实(AR)技术的迅速发展,开发者们对于能够简化和优化沉浸式应用开发的工具需求日益增长。HTC Vive 作为行业内的领先品牌,其最新推出的 VIVE OpenXR 插件为Unity开发者提供了一个强大…...

【Altium Designer 20 笔记】PCB线宽与过孔尺寸
电源线:40mil1A(一般翻倍给),地线比电源线粗一点即可;信号线:10-15mil 一、线宽 市电的火线和零线:80-100mil12V /24V 20mil~60mil 5V 20-30mil 3V 20-30mil GND 越宽越好20-30mil普通信号线 10mil-15mil…...

基于java的社区生活超市管理系统
开发语言:Java 框架:ssm 技术:JSP JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7(一定要5.7版本) 数据库工具:Navicat11 开发软件:eclipse/myeclip…...

51单片机入门_江协科技_27~28_OB记录的自学笔记_AT24C02数据存储秒表
27. AT24C02(I2C总线) 27.1. 存储器介绍 27.2. 存储器简化模型介绍,存储原理 27.3. AT24C02介绍 •AT24C02是一种可以实现掉电不丢失的存储器,可用于保存单片机运行时想要永久保存的数据信息 •存储介质:E2PROM •通讯接口:I2…...
LeetCode-热题100:169. 多数元素
题目描述 给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 1: 输入: nums [3,2,3] 输出…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

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可以提供外设…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...

解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...
【HarmonyOS 5】鸿蒙中Stage模型与FA模型详解
一、前言 在HarmonyOS 5的应用开发模型中,featureAbility是旧版FA模型(Feature Ability)的用法,Stage模型已采用全新的应用架构,推荐使用组件化的上下文获取方式,而非依赖featureAbility。 FA大概是API7之…...