指针与其运用

什么是指针?

首先,要知道,计算机上CPU在处理数据时,会向内存读取数据,处理后的数据也会放回内存。那么内存里的空间是怎样管理的呢?

其实是内存空间被划分为一个个内存单元,每个内存单元的大小为1个字节,也就是8个bit。(1个bit可以放)。每个内存单元都有一个编号,有了编号,CPU能很快找到对应的内存空间。呀就是说,内存单元的编号,其实可以理解为门牌号,只不过在代码之中,被称作指针。

指针 ==地址==内存单元编号。在代码中,这样写:int * p, char * p, float * p......而p,就是指针。

其次,硬件CPU和硬件内存有大量数据交互,两者之间有很多线,其中一组线,专门用来传输地址,叫地址总线。32位机器就有32根地址总线,每根线只有两种状态,表示0或1。一根线有2种含义,32根线就有2^32种含义,每一种含义,都是一个地址。

最后,补充地址信息(指针p)下达给内存,在内存上找到地址对应的数据后,通过数据总线将数据传入CPU寄存器。

指针变量、取地址操作符&、解引用操作符*

在C语言中,创建一个变量,其实是在向内存申请空间。我们用&取出地址,用*来找到地址所指向的值。形象一点,就是拿着门牌号(p,也就是&a),找到房屋内的东西(*p,也就是a的值)。

指针变量类型的作用

在32位平台,所有数据指针均为4字节;在63位平台,所有数据指针均为8字节。

无论地址指向的是int(通常4字节)还是char(通常1字节),地址值本身的长度是固定的。

虽然指针不管什么类型,所占的空间大小都是一样的,但是,指针的类型,决定了

指针解引用的时候有多大权限。

int*的指针的解引用能访问4个字节(全部变成0),char*的指针解引用只能访问1个字节。

补充:在小端序(如x86、ARM等),低地址存低字节;在大端序(嵌入式、早期架构、某些网络协议),低地址存高字节。

再来看一个

结论:指针的类型决定了指针向前或向后走一步有多大。

void*指针

void* 指针 ,是一种无具体类型的指针,也可以成为范指针,可以用来接收任何类型的地址,但是不能直接进行指针的+-整数和解引用运算,也就是不能用(void* p)*p 进行运算。

指针运算

有三种。指针+-整数,指针-指针,指针的关系运算。

1.指针+-指针

数组在内存中是连续存放的,只要知道第一个元素,就能顺藤摸瓜找到后面所有的元素。

2.指针-(减)指针

前提条件:两个指针指向的是同一块空间

3.指针的关系运算

指针之间可以用关系运算符比较:<, <=, >, >=, ==, !=。比较的是之阵中存储的地址值(内存位置的大小关系)

为什么叫关系运算?

关系运算符,用于比较两个值的大小或者相等关系,当操作数是指针时,比较的就是内存地址的大小。

野指针

一种所指向的位置不可知的指针,也就是空有门牌号却找不到对应的空间。野指针的成因有三:一是指针未初始化,二是指针越界访问,三是指针指向的空间释放,如图。

那么如何规避野指针

1.对指针进行初始化

明确直到指针应该指向哪。如果现在还不知道指向哪里,就初始化NULL。对应头文件《time.h》。int* p = NULL。形象化理解:小孩p手里被塞了一把打不开任何门的钥匙NULL,安静的看着大人们(代码)工作,直到大人(代码)想起她,给她一把真钥匙,让她开门,参与工作。

2.小心指针越界

指针访问对应的空间,不能超出范围访问,超出了就是越界访问。

3.避免返回局部变量的地址

如上图。

const修饰指针

int const a = 10------即锁死a,使a具有常属性,但本质上还是变量,所以又叫常变量。

但是在C++中,const修饰a,a就是常量。

const a后,不能直接定义a,但是可以通过指针,间接地定义a。

const锁住它后面跟的东西

int const * p------锁死*p,即值,值可以不通过p而改,地址可改;图1

int * const p------锁死p存放的地址,地址不可改,但可改值;图2

图1

图2

assert断言

对应头文件<assert.h>,作用于全局,用于在运行时确保程序符合指定的条件,不符合就会报错且终止程序,因此有别称------断言。如果不想让assert工作了,就在开头写#define NDEBUG

好处在于,出现错误后,会爆出哪个文件哪以行出错;坏处在于,增加程序检查的额外时间。

其特性利于程序员排查问题,一般在debug中使用,在release中禁用就行。(vs的集成开发环境种,release直接优化了,于是即使release中有assert,也不影响用户使用程序的效率。

传值的调用和传址调用

strlen

求字符串长度的, strlen统计的是字符串中\0之前的字符个数,涉及头文件<string.h>。

函数原型:size_t strlen(const char* str)。参数接受一个字符串的首地址,然后开始统计字符串\0之前的字符个数,最终返回长度。

关键:

1.不计算\0

2.参数必须有效。

传递的指针必须指向以\0结尾的字符串

3.返回值类型。

是无符号类型,不要与有符号数混用

传值的调用和传址调用

传值调用:传给函数复印件,改复印件不影响原件。

传址调用:给函数原件的位置,直接操作原件。

用++两个整数交换数值++来说明。

传值调用:

可以看到,交换失败。

传址调用:

相关推荐
望酹江月3 小时前
HNU-RFID与传感器原理实验
c语言·单片机
计算机安禾5 小时前
【C语言程序设计】第39篇:预处理器与宏定义
c语言·开发语言·c++·vscode·算法·visual studio code·visual studio
本喵是FW5 小时前
C语言手记3
c语言·开发语言
HABuo6 小时前
【linux线程(一)】线程概念、线程控制详细剖析
linux·运维·服务器·c语言·c++·ubuntu·centos
C羊驼7 小时前
C语言学习笔记(十一):数据在内存中的存储
c语言·经验分享·笔记·学习
承渊政道8 小时前
【优选算法】(实战体验滑动窗口的奇妙之旅)
c语言·c++·笔记·学习·算法·leetcode·visual studio
C羊驼8 小时前
C语言学习笔记(十):操作符
c语言·开发语言·经验分享·笔记·学习
自信150413057599 小时前
选择排序算法
c语言·数据结构·算法·排序算法
hongtianzai9 小时前
Laravel7.x十大核心特性解析
java·c语言·开发语言·golang·php