指针
-
指针变量定义
在计算机内部每一个字节单元都有一个编号,称为地址。
内存单元的地址称为指针,存放指针的变量称为指针变量。
请记住上面两句话,因为这就是指针的本质。
计算机位数对应于地址的字宽,32位计算机的字宽就是32位的,也就是4个字节。(
所有类型(int*,char*,struct*,数组等)的指针都是32位的,即4个字节的
)
为什么呢?因为计算机的位数代表了其寻址能力,因为指针变量存放的是指针,也就是32位二进制数据,也就是4个字节。所以在遇到 别人让你求sizeof(指针变量),这个问题就变得很简单了,现在我们知道了32位的机器下面,这个值是4,64位机器下面这个值是8。好了,下次别人再问你这个问题,你可以反问他:你说的是多少位的机器?
指针定义形式如下:
类型说明符* 变量名
- *表示一个指针变量,类型说明符表示指针所指向的数据类型。
- 虽然所有的指针都等长,但是还要指明数据宽度,因为对指针变量的其他操作都涉及都涉及指针变量的数据宽度。(即指针所指向数据的类型)
-
指针变量的赋值
指针变量定义以后,不能随便使用。指针变量的值只能是其所指向的变量的地址。不能是其他数据。
C语言中变量的地址是有编译系统分配的,用户不知道的。但是变量的地址可以用&运算符来查看变量的地址。形式如下:
&变量名
// & —>取地址符 -
指针变量的引用
- *------>指针运算符(间接存取运算符)
- &------>取地址运算符
指针变量P的目标变量m,因此*P,m,*(&m)表达式的含义相同。
- P-----指针变量,它的内容是地址
- *P-----指针所指向的对象,它的内容是数据(即其所指向的变量的值)
- &P------指针变量所在的存储区域的地址(注意这里的说法)
-
指针的运算
指针运算是以指针变量所存放的值(地址量)作为运算量来进行的运算。指针的运算是指就是地址的计算。定义指针变量P:
-
p+n---->指针向地址方向大的方向移动n个数据
-
p-n----->指针向地址方向小的地方移动n个数据
-
+±----->++p,p++
-
– ------>–p,p–
-
p-q--------->两个指针之间相隔数据元素的个数
p + x---->实际内存单元的地址量:p+x*sizeof(p指向的数据类型)
-
注意:两个指针相减的结果值不是地址量,而是两个指针间的元素个数
指针的关系运算:
- 具有不同数据类型的指针之间的关系运算没有意义。指向不同独居区域的两个指针之间的,关系运算也没有意义。
量个重要的表达式:
- *p++–>同一优先级,从右向左运算,相当于*(p++),表达式的作用是在原p的值的基础上进行间接操作,将p值加1。表达式的值是提取原p的内容。(++在后,p先参与运算*P,再把p值后移一个数据宽度)
-
-
空指针
空指针即指真指向了零号地址,可以用:int *p = 0;
C 中一般用NULL来代表0,它可以表明一个指针当前为指向任何变量。
在定义指针时,最好将指针初始化为0。
-
指针和数组
数组名是一个地址,指针的一次相加是以其所指向的对象的数据宽度为单位进行移动。
数组名 +i ---->数组名[i]
指针的效率要高于数组下标。
[]是变址运算符,*(a+i)和a[i]无条件等价
假设指针P指向数组a的首元素,那么素组元素有以下几种表达方式:a[i]<—>*a[i]<—>p[i]<—>*(p+i)
数组名是地址常量,指着是地址变量,数组名可以被作为指针参与运算,但是不能被赋值
-
指针与二维数组
二维数组可以看做是以一维数组为元素的特殊的一维数组。参与运算时以行为单位进行移动,也被称为行地址。二维数组a[3][2]
- a[]—>第一行第一列元素的地址
- a---->第一行的首地址,也等于第一行第一列元素的地址
- a+1—>第二行第一列元素的地址
a[1][1]<->*(&(a[1][0])+1)<->*(a[1]+1)<->*(*(a+1)+1)
当偏移量前的元素单元是整个素组时,偏移的单元是行,当偏移量前的元素单元是行时,偏移的单元是行中的元素。
-
多级指针
指向一级指针变量的指针称为二级指针。
二级指针:
<存储类型> <数据类型> **<指针名>
-
指针数组
指由若干个相同存储类型和数据类型指针变量构成的集合。
定义形式:
<储存类型> <数据类型> *<指针变量名> [<大小>]
指针数组名实际为二级指针。
-
const与指针
const关键字的作用是使得变量常量化,即限制变量为只读。
const int *a;
int const *a;
int *const a;
const int *const a;
前两个位限制指针变量a所指向的变量的值不能被修改;第三种形式时限定指针变量a的不能被改动。第四种为限制指针变量的值及其所指向的变量的值都不能修改。
总结:
- 1.指针变量名与const之间没有任何修饰符,限制指针变量为只读。即限定指针变量存储的地址值不能被改变
- *2.指针指向的值为只读,const修饰(int )或者修饰*
-
void指针
- void类型的指针变量是一种不确定的指针变量,它可以通过强制类型转换,才能让指针变量指向其他数据类型。
- 在没有强转之前void *类型的指针不能进行任何数据运算。
-
字符指针
- 字符指针就是存储字符变量的地址
- 利用字符数组对字符串进行遍历
- 虽然字符数组名是字符串的首地址,但是数组名是一个常量,其值是不能改变的(不能进行自加、自减、赋值等操作),但如果把字符数组的首地址赋值给一个字符指针变量,就可以移动这个字符指针变量来访问每一个字符。
字符指针数组:
-
若数组中存储了若干个字符串的地址,则这个数组就叫做字符指针数组。例如:
char s1[] = {"welcime"}; char s2[] = {"to"}; char s3[] = {"wuhan"}; char *a1[] = {s1,s2,s3}; char *a2[] = {"welcome","to","wuhan"};
上面这段代码中,a1和a2都是字符指针数组。a1,a2存储的是一维指针的地址,所以,a1,a2也是二级指针。