本质上指针就是地址,口语中所说的指针,其实就是指针变量,指针变量是用来存放地址的一个指针。
我们知道计算机上CPU(中央处理器)在处理数据的时候,需要的数据是内存中读取的,处理后的数据也会放回内存中。
电脑上内存是8CB/16GB/32GB等,这些内存空间如何高效的管理?
其实就是把内存划分成一个一个的内存单元,每个内存单元的大小取1字节,每个内存单元都有一个编号。
有了内存单元的编号,CPU就可以快速找到一个内存空间。
内存单元的编号 == 地址 == 指针
2.1 取地址操作符(&)
在C语言中,创建变量其实就是向内存申请空间
上述代码创建整型变量a,向内存申请了4个字节,用于存放整数10,其中每个字节都有地址,上图中4个字节地址分别是:
0x00F5FCEC
0x00F5FCED
0x00F5FCEE
0x00F5FCEF
那我们如何得到a的地址?
这里就用到取地址操作符(&)
上述代码,运行之后,打印:0x00F5FCEC
&a取出来的是a所占4个字节中地址最小的字节的地址。
2.2.1 指针变量
我们通过取地址操作符(&)拿到的地址是一个数组,比如:0x00F5FCEC,这个数组有时候需要存储起来,方便后期使用,那我们就可以把地址值存放在指针变量中。
总结:变量a和指针变量pa都有各自的地址,只是把变量a的地址存放在指针变量pa里。
指针变量也是一种变量,这种变量就是用来存放地址的,存放在指针变量中的值都会理解为地址
2.2.2 解引用操作符(*)
输出:100
①*的作用是引用指针指向的变量值,引用其实就是引用该变量的地址,“解”就是把该地址对应的东西解开,解出来,就像打开一个包裹一样,那就是该变量的值了,所以称为“解引用”。 也就是说,解引用是返回内存地址中对应的对象。
解引用也可以改变该变量的数值。
②需要注意的是,在变量声明的时候,*不能当做解引用使用,只是表示你声明的变量是一个指针类型。
2.3 指针变量的大小
指针变量的大小取决于地址的大小
①32平台下地址是32bit位,指针变量大小是4字节
②64平台下地址是64bit位,指针变量大小是8字节
注意:指针变量的大小和类型无关,只要指针类型的变量,在相同平台下,大小都是相同的。
任务:上面两段代码,调试观察内存的变化,对比发现了什么?
发现:第一段代码会将n的4个字节全部改为0;但是第二段代码只是将n的第一个字节改为0。
结论:指针类型决定了对指针解引用的时候有多大权限(一次可以操作几个字节)。
比如:char*的指针解引用只能访问一个字节,而int*的指针解引用就可以访问4个字节。
运行结果:
结论:指针类型决定了指针向前或者向后走一步有多大(距离)。
void* 类型,无具体类型的指针(泛型指针),void* 类型的指针大部分使用在函数参数的部分,用来接收不同类型数据的地址。
但是void* 类型的指针不能直接进行指针的+-整数和解引用运算。
在C语言中,const是constant的缩写,翻译是“恒定不变的”。它是定义只读变量的关键字。或者说const是定义常变量的关键字
const修饰的变量被称为常变量,具有常属性,但是本质上还是变量。
保护被修饰的东西,防止被意外修改,增强程序的健壮性。
提高程序的运行效率。编译器通常不为普通const常量分配存储空间,而是将他们保护在符号表中,使得它成为一个编译期间的常量,没有存储和读取内存的操作,使得它的运行效率也很高。
总结:
①const int* p (int const *p):const放在*的左边。修饰的是*p,*p(指针指向的内容)不能修改;p(指针变量本身)可以修改
②int * const p :const放在*的右边。修饰的是p,p(指针变量本身)不可以修改;*p(指针指向的内容)可以修改。
③int const * const p (const int * const p):*的左右两边都有const,修饰的是*p和p,所以*p和p都不能被修改。
数组在内存中是连续存放的,只要知道第一个元素的地址,顺藤摸瓜就可以找到后面所有元素。
指针p+i,表示指针向后移动i个单位(每个单位为指针p的类型所占的字节数),指向原先指向的元素后的第i个元素。若p指向arr[0],则p+i指向arr[i];
两个指针相减,得到的就是指针之间的元素个数。指针s是字符串首地址,第一次p=s,随着p++,p指向最后一个字符后面的位置。所以p-s,就得到字符串的个数。
指针的比较,依赖于指针所指向的两个元素的相对位置,若指针p指向arr[i],指针q指向arr[j],p和q的结果由i和j的大小决定。
C语言的间接寻址运算符常和或运算符一起使用,具有以下四种不同的形式:
运行结果示例:
概念:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
① 指针未初始化
② 指针越界访问
③ 指针指向的空间释放
① 指针初始化
② 小心指针越界
③ 指针变量不再使用,及时置NULL,指针使用之前检查有效性
④ 避免返回局部变量的地址
库函数strlen的功能是求字符串长度,统计的是字符串0之前的字符个数。
库函数原型:
size_t strlen ( const char* str );
模拟实现,从起始地址开始向后逐个字符的遍历,只要不是0字符,计算器就+1,直到0就停止。
任务:写一个函数,交换两个变量的值
运行结果,如下:
结论:实参传递给形参的时候,形参会单独创建一份临时空间来接收实参,对形参修改不影响实参。
所以Swap()失败了。
答案:使用指针,在main函数中将a和b的地址传递给Swap函数,Swap函数里通过地址间接的操作main函数中的a和b,并达到交换的效果。
运行结果,如下:
将变量的地址传给函数,这种函数调用方式叫:传址调用。
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.mushiming.com/mjsbk/4181.html