指针
内存的作用:CPU执行程序的过程中用来存放
(1)、指令
(2)、数据----一个或者多个数字的统称
a.数值---具有实际意义的数字
b.地址值---内存中某个字节单元的编号(某块内存空间的首地址)
C语言中地址类型的写法:T*-----T类型的地址
如果某个地址值其类型是T*类型,则以该地址值为首地址的内存空间中存放的T类型的元素
C语言允许用指针类型(地址类型)去定义变量,并将这样的变量统称为指针,这样的变量自身空间存放的是指定地址类型的地址值。
指针定语句:
T * 指针名=NULL或者T类型的地址表达式(即表达式的运算结果是T类型的地址值)
1、指针变量的sizeof---指针变量自身空间的大小
sizeof(指针名)或sizeof(指针类型)=32位机采用连续的4个字节存放一个地址值----4
64位机采用连续的8个字节存放一个地址值----8
2、指针变量定义语句的作用
3个基本作用+N个额外作用(N指指针类型的级数,T*:一级指针,T**:二级指针.....T*...:N级指针)
3个基本作用:
(1)、为该指针变量分配sizeof(指针名)个字节的内存空间(该指针自身内存的空间)
(2)、给该空间命名为指针名
(3)、该空间采用sizeof(指针名)个字节来描述另一块内存空间(该指针的指向空间)的首地址。
N个额外作用:
1、其一级指向空间中连续存放着一个或者连续多个T**...N-1个星...**类型元素
2、其二级指向空间中连续存放着一个或者连续多个T**...N-2个星...**类型元素
。。。
N-1、其N-1级指向空间中连续存放着一个或者连连续多个T*类型元素
N、其N级指向空间中连续存放着一个或者多个T类型元素
3、指针相关的运算
<1>对指针变量自身空间的运算
&N级指针名----求该指针变量自身空间的首地址 地质类型为N+1级指针类型 ----右值表达式
sizeof(N级指针名)或者sizeof(T**...N个星...**)----32位机4,64位机8 ----右值表达式
N级指针名=同类型的地址表达式(该表达式的计算结果T**...N个星...**类型)---左值表达式
<2>对指针变量自身空间保存的地址值做运算
*N级指针名----访问其一级指向空间
*(N级指针名+x)----访问其一级指向空间---左值表达式
*(*(N级指针名+x)+y)----访问其二级指向空间---左值表达式
C语言之所以引入指针类型是为了提供一种可以使用地址值访问内存空间的方式,即C语言支持两种访问内存空间的方法:
(1)、直接访问法:通过空间名称访问
(2)、间接访问法:通过空间首地址访问
例如:
int x = 6;
y = x*3 ---直接访问
y = *(&x) * 3 ---间接访问
地址值运算可类比成街道门牌号的运算(同一块空间才有意义):
T类型的地址值+/-整数n----n为T类型元素个数
T类型地址值1-T类型地址值2---元素个数
T类型地址值1 比较运算符 T类型的地址值2
++/-- :
指针变量名 ++/-- :整体运算结果是指针变量名,后对指针变量当前的地址值+1或者-1的运算(左值表达式)---位于赋值号右边时,其值为老地址。
++/--指针变量名:整体运算结果是指针变量名,先对指针变量当前的地址值+1或者-1的运算(左值表达式)----位于赋值号右边时,其值为新地址。
地址值类型的转换:----越界
(新的地址值类型)老类型的地址表达式----改变的是以此地址为首的内存空间中的二进制位的作用,地址值不会发生改变。
例;
unsigned short x=0x1234;
unsigned int *p=(unsigned int *)&x;
*p=0xabcd; 越界
C语言编程时的第一大基本原则:类型一致性
1、赋值运算
2、函数调用时 实参与形参
3、函数返回 return 表达式 与返回值类型
4、指针类型作为函数的形参类型
当函数的某个形参是指针类型时,一维这调用该函数,调用方会将一块内存空间的首地址通过该形参传输进函数体,函数体中根据需要可以对该空间通过该形参进行间接访问,这样给函数定义带来两个方面的变化:
<1>如果该形参指向空间存放着批量同类型元素,则函数就具备处理批量元素的能力
<2>函数不仅可以通过返回值向调用方反馈处理结果,也可以通过向该形参指向空间填写处理结果的方式,向调用方反馈处理结果
因此,当函数的某个形参是指针类型时,根据函数体中对其指向空间使用方式,将其分为三类
<1>值参数 :函数体中只读该形参指向的空间的内容 const T*
<2>结果参数:函数体中只向该形参指向的空间中填写新内容(原空间内容与本函数实现逻辑无关)
<3>值-结果参数:函数体中既要读该形参指向空间的老内容,又会修改形参指向空间的内容
如果形参类型是指针类型,并且其指向空间中存在着批量元素,为防止函数体中有对该形参指向空间的越界操作,需要采取如下措施进行传参:
<1>指针类型形参指向空间存放着批量元素,并以某种特殊元素作为结尾标记时:
仅需要传递地址值----仅需要指针类型的形参即可
<2>指针类型形参指向空间存放着批量元素,并不以某种特殊元素作为结尾标记时:
不仅需要指针类型的形参传递首地址,还需要其他类型形参的配合:
(1)、首地址+元素个数
(2)、第一个元素地址+最后一个元素地址
(3)、首地址+第一个元素下标+最后一个元素下标
5、指针类型作为函数的返回值类型
函数体中只能以如下语句进行返回:
return NULL;或return 与返回值类型同类型的地址表达式
编写这样的函数要注意一个基本原则:以返回的地址值为首地址的内存空间仍然在其生存期内,即不能返回已释放的内存空间的地址值。
C语言编程的第二大基本原则:
程序中任何一处使用的内存空间必须是程序员已知可控的内存空间
6、特殊指针
1、空指针
指针变量自身空间的地址值为NULL的指针
NULL---是一个宏定义 #define NULL (void *)0----即0地址
以0地址为首地址的一段内存空间是受操作系统保护的内存空间,任何程序不可以读其空间内容,也不能改其空间的内容。
2、野指针---编程错误
(1)、定义指针(非static局部指针)时,没有给其初始化,此时该指针自身空间的地址值是一个不确定的地址值,因此无法知晓该指针指向何处。
(2)、悬垂指针:指针变量指向内存空间已经被释放
当发生野指针错误时,程序运行过程中可能会出现两种情况:
<1>段错误 ----程序死翘翘(定位bug很容易)
<2>程序运行到某处发生该处计算结果与该处代码逻辑不符 ----逻辑混乱(定位bug很困难)
为了更容易定位错误,因此编码我们习惯把野指针变成空指针
<3>通用指针void *类型指针变量
该类指针指向空间存放的元素类型暂时不确定,即该指向空间存放的元素类型可以由程序逻辑根据需要重新指定元素类型,因此不能对该类型地址做如下运算:*p ,p+/-n , p1-p2 , p++/p-- ,++p/--p
程序中应该定义另一种非void *类型的指针,然后将void *类型的地址值强转并赋值给非void类型的指针才能对其指向空间做访问。
从void类型分析:1、sizeof(void)无意义
2、不能定义void变量
从void在C语言的含义:1、空或者没有
2、不确定