指针---C语言

news2024/11/25 2:24:06

目录

前言:

一.指针基础

1.1内存单元

1.2内存单元和指针的大小

二.指针变量

2.1指针类型

2.2野指针

三.指针运算

四.指针和数组的关系

4.1下标与解引用的等价替换

4.2指针数组

五.二级指针


❤博主CSDN:啊苏要学习

  ▶专栏分类:C语言◀

  C语言的学习,是为我们今后学习其它语言打好基础,C生万物!

  开始我们的C语言之旅吧!✈


前言:

  接下来我们进入C语言里的重头戏---指针。指针是一个很好用的东西,学好指针,无异于打下半片江山

一.指针基础

  指针实际上是用来指向内存空间的一个变量。可能读者会觉得博主说得轻描淡写,我们先抛开先前对指针的恐惧,一步一步来讲,先从内存的基础讲起。

1.1内存单元

  内存是存取数据的一块大空间,我们知道,无论是什么事物,不好好利用都会有挥霍完的一天,相应的,要想高利用率的使用好内存空间,计算机前人们在设计的时候,就把内存空间划为一个一个小小的内存单元

  那又如何区分这些长的一样的内存单元呢?在生活中,一栋栋商品房,房型差不多,如何让住户知道自己买的房间在哪里咧,假设有亲戚朋友要来我家,如何让他们知道我住哪里呢我想,给个编号,给个地址不就好了~,现实中如此,计算机也如此,使用一个个编号给内存单元定义地址

  这个编号是使用地址线(电线)的通电,不通电这两种状态转换成数字信号1,0给内存单元编号,这个编号也就是它们的地址啦

  补充32位电脑有32根地址线,每一根地址线可以产生0或1的数字信号,总共有2的32次方种组合,也就是可以管理2的32次方个内存单元。64位电脑就可以管理2的64次方个内存单元

1.2内存单元和指针的大小

  那么一个内存单元多大合适呢?在以前我们常说4G、8G内存的电脑。我们姑且来算一下吧,假如一个内存单元只能存储一个bit位,那么32位机器内存大小为2的32次方个bit位:

   二进制第33位的1代表2的32次方,我们现在转换成Gb单位需要除以8(Byte)、除以1024(Kb)、除以1024(Mb)、除以1024(Gb)。

  由于程序员的除法取商,再除1024就是0了。所以现在是转换到Mb的单位,512Mb就是0.5G,这未免也太小了吧,听过最小的内存也是4G~,那一个内存单元从一个bit位变成一个字节呢0.5G乘以8变成4G,可以接受~ 

  总结计算机中一个内存单元是一个字节的大小

  指针是存放内存单元地址的,一个地址的产生前面也说过。如果是32位平台,就用32根地址线生成32个数字信号来编号,那一个地址就是32个bit位,所以指针大小就是4个字节;如果是64位平台,指针大小为8个字节,这是固定的,不会根据数据类型改变指针大小

  总结指针大小如果在32位平台下是固定4个字节,在64位平台下是固定8个字节

二.指针变量

  如何创建指针变量呢?请看值一段代码:

#include <stdio.h>

int main()
{
    int a = 0;
    int* pa = &a;
    *pa = 10;
    printf("%d\n", a);
    return 0;
}

2.1指针类型

  和创建普通变量是一样的,指针类型+变量名创建整型指针变量pa&取地址操作符取出整型变量a的地址放到指针变量pa里面,*解引用pa的意思是找到pa存放的地址对应的内存单元,也就是找到了a,*pa相当于a

  char*、short*、int*、float*、double*的大小分别是多少?都是4个字节的空间大小(32位),那char*类型的指针变量也可以存放整型变量的地址是毋庸置疑的,但这样做对吗?我们看代码:

  将a的地址放到char*的指针里面是能放进去的,只是编译器会有一个警告,报的是类型不兼容

  这就是我们这里要讲的指针类型的意义

  • 指针变量的类型决定了指针解引用时改变多少个字节
  • 指针变量的类型决定了指针加减运算时跳过多少个内存单元

  我们使用整型指针可以把-1完全变成0,而使用字符指针却改不成,这是为什么呢?请看:

  *pc只改了一个字节,(内存中用十六进制表示,两个十六进制位等于一个字节,16是2的四次方),所以a的补码为0xffffff00;打印的时候转换成原码~

   以上解释就是指针类型决定指针访问权限还有一个指针决定指针加减运算跳过多少个内存单元的问题,博主简单说一下

  一个指向整型的指针+1,指针变量里的地址会指向哪一个内存单元呢?我们看代码:

  整型a的起始地址是c4,本来a占有的内存单元有c4、c5、c6、c7这四个内存单元,一个内存单元一个字节,整型变量是四个字节大小嘛。然后使用它的首地址代表a的地址,整型值10就放在这四个内存单元里p存放的值是a的地址,所以&a和p是一样的

  打印p+1不是等于c5,而是c8,为什么呢?这里我们就得了解指针类型决定指针跳过多少个内存单元可以这样理解,整型指针加1的意思是:指向下一个整型(当然下一个不一定是整型),只是这样说而已

2.2野指针

  野指针就像野孩子一样,没有人管,这是非常危险的。野指针的常见情况如下:

  1. 没有初始化的局部指针变量。
  2. 指针指向的变量销毁掉了。
  3. 数组越界访问。

  局部变量没有初始化是随机值,一个局部指针变量如果没有初始化,那它也是一个随机值;指针变量是存放地址的变量,随机值存放在指针里面会被当成地址看待如果此时不小心对指针进行了解引用操作,就会对不属于我们的内存单元里的内容进行修改,造成破坏,导致程序挂掉

  指针指向的空间释放掉了,指针就变成了野指针。请看代码:

  a是test函数里的局部变量,在test函数里a存在,然后返回a的地址,a出了代码块,生命周期结束,被释放掉了,可是*p还是接收到a变量的地址,但a已经不属于我们了,此时p就是野指针

  数组越界访问变成野指针在后面讨论指针和数组的关系时讲~

避免野指针
在创建指针变量的时候,如果不知道指向谁,初始化为NULL(空指针)
指针使用完后,赋值成空指针
在使用指针之前,用if测试指针现在放的是不是NULL,因为空指针不能解引用

三.指针运算

  指针的运算有指针加减整数,指针减指针,指针大小关系比较

  指针加减整数前面讲过了,就是什么样的真正类型,跳过多少个内存单元。我们主要是看一下指针减去指针和指针关系比较

  指针减去指针表示的是之间的元素个数;这里是9个元素可以这样理解&arr[9]-&arr[0]下标9减0是9

  补充指针相减的绝对值才是元素个数,因为指针相减可以是负数。指针与指针相减的前提是指针类型相同、指向同一块空间,基本用在数组里面。

  指针的关系运算

#include <stdio.h>

#define n_ele 5

//方式一:
int main()
{
    float* vp = NULL;
    float varr[n_ele];
    for(vp = &varr[n_ele]; vp > &varr[0];)//第三个条件省略
    {
        *--vp = 0;
    }
    return 0;
}

//方式二:
int main()
{
    float* vp = NULL;
    float varr[n_ele];
    for(vp = &varr[n_ele-1]; vp >= &varr[0]; vp--)
    {
        *vp = 0;
    }
    return 0;
}

  使用两个指针的关系比较充当for循环里的入口条件测试。

  第一种方式vp第一次从下标为5的位置和下标为0的位置比较,注意下标为5的位置其实不在数组内;*--vp是先把指向数组下标为5的指针变成指向数组下标为4的指针,再*解引用找到内存空间改成数值0,没有越界操作

  第二种方式第一次从下标为4开始比较,最后停止的时候,是用指向相当于数组下标为-1的指针和数组下标为0的比较,不符合循环条件,退出循环,也没有越界访问这两种方式完成的功能都一样,把数组元素都赋值成0,哪一种好呢?

  其实第一种方式会更好,因为他是C语言标准允许的。C语言标准规定:允许指向数组元素的指针和指向数组最后一个元素的下一个位置的指针进行比较,但不允许和指向第一个元素前一个位置的指针进行比较

四.指针和数组的关系

  相信在前面,读者多多少少感觉到了数组的下标访问,和指针运算之间有种莫名其妙但又说不出来的感觉。其实数组的和指针是非常相似的!

  以前说过数组名一般表示的是首元素地址,既然是地址,其实也就是指针但和指针不同的是arr它表示的是首元素地址,也就是说 arr = arr + 1;这句代码试图将arr指向第二个元素,这是不允许的如果是这种情况 :p = arr + 1;指针p在没有再次修改的情况下,都是指向数组第二个元素

4.1下标与解引用的等价替换

  arr[0]访问的是数组的第一个元素,用指针可以*(parr+0)访问;arr[1]访问的是数组的第二个元素,用指针可以*(parr+1)访问所以下标访问实际上就是让arr(首元素地址)加上一个整数【指针加减整数运算】后,解引用访问

  总结arr[i] = *(arr+i) = *(parr+i) = parr[i]

  阴间写法:*(arr+i)和*(i+arr)道理是一样的,前面是arr[i],后面可以这样写i[arr]!!!

4.2指针数组

  指针数组,存放指针的数组~

#include <stdio.h>

int main()
{
    char* arr[3] = {"hello,world","C so good","I like it"};
    //字符串常量时首字母地址,也就是说"hello,world"实际上表示的是h的地址
    //是字符的地址,用字符指针char* ,arr是一个接收字符指针的数组---指针数组。
    return 0;
}

五.二级指针

  指针是存放变量的地址的,指针变量也是变量,它也有地址存放一级指针变量地址的指针叫做二级指针

  一级指针pa的类型是int*,这颗*不是解引用的那颗星,而是用来标志pa是一个指针的,这是一种理解另一种理解是*pa的类型是int,也就是说pa解引用后指向的是一个整型

  二级指针ppa的类型是int**。一样的道理,可以把靠近pa的一颗星看做是一个标志ppa是一个指针,然后是指向int*的;也可以是*pa后是一个一级整型指针

  指针的内容不止有这些,学习指针的路还很长,后面再回~


结语:希望读者读完有所收获!在学C的路上,祝福我们能越来越C!✔

  读者对本文不理解的地方,或是发现文章在内容上有误等,请在下方评论区留言告诉博主哟~,也可以对博主提出一些文章改进的建议,感激不尽!最后的最后!

  ❤求点赞,求关注,你的点赞是我更新的动力,一起努力进步吧。

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

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

相关文章

如何获取HTTP请求时间与响应时间【附源码】

文章目录 一、问题描述二、抓包观察三、查找文档四、思考尝试五、精益求精六、源码解说 一、问题描述 今日遇到了一个问题&#xff0c;要去获取HTTP报文在请求和响应的时间&#xff0c;因为没有原生的API可以调用&#xff0c;所以需要一定的技巧~ 下面主体的框架和代码&#xf…

如何在 Linux 服务器上更改分区方案?

在 Linux 服务器上&#xff0c;分区方案对于数据存储和系统管理至关重要。当服务器的存储需求发生变化或者需要重新组织分区时&#xff0c;更改分区方案是一个常见的任务。 本文将详细介绍如何在 Linux 服务器上更改分区方案。 步骤一&#xff1a;备份数据 在更改分区方案之前…

Microsoft Office 2013安装

哈喽&#xff0c;大家好。今天一起学习的是office2013的安装&#xff0c;有兴趣的小伙伴也可以来一起试试手。 一、测试演示参数 演示操作系统&#xff1a;Windows 7 支持Win10安装&#xff0c;不建议Win11安装&#xff0c;不支持WinXP系统 系统类型&#xff1a;64位 演示版本…

Jmeter函数助手函数--计数器详解

函数 作用 ${__counter(,)} 计数器&#xff0c;每次加1 ${__dateTimeConvert(,,,)} 时间格式转换 ${__intSum(,,)} 整数相加 ${__P(,)} 获取属性 ${__setProperty(,,)} 设置属性 ${__Random(,,)} 随机数 ${__threadNum} 线程编号 ${__time(,)} 获取当前时间戳…

Axure教程-竖向堆叠图(中继器)

本文将教大家如何用AXURE中的中继器动态竖向堆叠图 一、效果介绍 如图&#xff1a; 预览地址&#xff1a;https://wo8zqr.axshare.com 下载地址&#xff1a;https://download.csdn.net/download/weixin_43516258/87810606 二、功能介绍 简单填写中继器内容即可生成动态竖向堆…

Day5 模块(单元)测试——单元测试、自顶向上测试、自下向上测试

Day5 模块(单元)测试——单元测试、自顶向上测试、自下向上测试 文章目录 Day5 模块(单元)测试——单元测试、自顶向上测试、自下向上测试什么是单元测试?单元测试结构化程序时代单元测试与使用单元测试的误解单元测试过程成本效率不高结论单元测试的优点测试用例白盒覆盖…

SAP 用CO13冲销工序报工,但是没有产生货物移动(TCODE:CO1P 、 SE38 :CORUPROC,CORUAFWP)

前言 通常情况下&#xff0c;对PPO做GI或GR的时候&#xff0c;出现的异常可以在COGI中间被列出&#xff1b;在这些数据进入COGI之前&#xff0c;系统会把这些数据记录在CO1P中&#xff1b;换句话说&#xff0c;系统有时会出现DB的更新延时&#xff0c;当延时发生的时候&#xf…

从零实现一个数据库(DataBase) Go语言实现版 6.持久化到磁盘

英文源地址 持久化至磁盘 前一章中的b树数据结构可以很容易地转存到磁盘上.让我们在它之上建立一个简单地kv存储. 由于我们的b树实现是不可变的, 我们将以仅追加的方式分配磁盘空间, 重用磁盘空间将推迟到下一章. 持久化数据的方式 正如前面章节所提到的, 将数据持久化到磁…

黑马程序员的基础班都是一些什么内容?

黑马推出了基础班的课程&#xff0c;各学科点击申请基础班试学 Java学科基础班 JavaSE基础基础班阶段一 课时:9天 技术点:60项 测验:1次 学习方式:线下面授 学习目标 1.掌握Java开发环境基本配置 2.掌握运算符、表达式、流程控制语句、数组等的使用 3.熟练使用IDEA开发工具…

SQL优化的思路和步骤

数据库优化 创建索引: 创建合适的索引提高查询速度 分库分表:当一张表的数据比较多或者一张表的某些字段的值比较多并且使用时改用水平分表和垂直分表来优化 读写分离(集群): 当一台服务不能满足需要时&#xff0c;采用读写分离的方式进行集群 缓存: 使用redis来进行缓存 …

ServerBoss:国产免费的Linux连接工具,服务器管理工具

在这个数字化时代&#xff0c;Linux正在成为越来越多企业的首选操作系统。但是&#xff0c;由于它复杂的命令行界面和复杂的文件系统&#xff0c;许多用户可能会认为Linux不太友好和难以驾驭。同时目前大部分Linux连接工具都是国外产品&#xff0c;且需要商业授权。在此背景下&…

案例14:Java酒店管理系统设计与实现开题报告

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

产研团队任务管理工具:盘点国内外9款知名任务管理系统软件

以下是10款国内外最知名的任务管理系统&#xff1a;1.研发项目任务管理-PingCode&#xff1b;2.通用项目任务管理-Worktile&#xff1b;3.免费开源研发任务工具-Redmine&#xff1b;4.海外著名项目任务管理工具-Asana&#xff1b;5.免费任务管理软件-Trello&#xff1b;6.个人任…

springboot防止反编译proguard+xjar

一、背景 项目组核心代码模块部署于用户服务器上&#xff0c;直接甩jar包到服务器的方式&#xff0c;极有可能导致数据泄露和代码泄露&#xff0c;为了防止有技术能力的用户反编译我们的程序&#xff0c;采用了proguard和xjar两种方式来混淆和加密jar包&#xff0c;注&#xf…

shell和ansible自动化运维实例

目录 1、找到java进程并kill 2、nohup启动jar包&#xff0c;并按日期写入log日志 3、vscode上传服务器 4、ansible-playbook的copy模块 5、ansible-playbook的cron模块 6、ansible将文件批量推送至其他服务器的指定目录 将N台电脑上的java程序定时重启&#xff0c;不用每隔…

霍尔电流传感器的注意事项及其在直流列头柜中的应用

安科瑞虞佳豪 霍尔电流传感器​注意事项 &#xff08;1&#xff09;电流传感器必须根据被测电流的额定有效值适当选用不同的规格的产品。被测电流长时间超额&#xff0c;会损坏末极功放管&#xff08;指磁补偿式&#xff09;&#xff0c;一般情况下&#xff0c;2倍的过载电流…

清华开源图文对话大模型!表情包解读有一手,奇怪的benchmark增加了

丰色 萧箫 发自 凹非寺 量子位 | 公众号 QbitAI 什么&#xff0c;最懂表情包的中文开源大模型出现了&#xff1f;&#xff1f;&#xff01; 就在最近&#xff0c;来自清华的一个叫VisualGLM-6B的大模型在网上传开了来&#xff0c;起因是网友们发现&#xff0c;它连表情包似乎…

物联协议整理——蓝牙BLE

最近公司很多物联设备都使用BLE蓝牙和ZigBee通信&#xff0c;中间对设备功耗要求很高&#xff0c;补充下相关知识。 蓝牙协议栈 PHY层&#xff08;Physical layer物理层&#xff09;。PHY层用来指定BLE所用的无线频段&#xff0c;调制解调方式和方法等。PHY层做得好不好&#…

编译原理之词法分析实验(附完整C/C++代码与总结)

一、实验内容 通过完成词法分析程序&#xff0c;了解词法分析的过程。编制一个读单词程序&#xff0c;对PL/0语言进行词法分析&#xff0c;把输入的字符串形式的源程序分割成一个个单词符号&#xff0c;即基本保留字、标识符、常数、运算符、分界符五大类。 对PL/0语言进行词法…

关于VSCODE的插件 一

官方API文档 1. 要学好TypeScript。 官方教程 1.1TypeScript是一门弱类型语言。 强类型和弱类型主要是站在变量类型处理的角度进行分类的。这些概念未经过严格定义&#xff0c;它们并不是属于语言本身固有的属性&#xff0c;而是编译器或解释器的行为。主要用以描述编程语言…