C语言指针常用形式的分析
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
C语言指针常用形式的分析
1指针的本质
众所周知,在C语言中,我们使用到的数据(此处的数据不包含程序指令)通常有两类:一类是数值不可改变的,我们称为常量,另一类是数值可以随时更改的,我们称为变量。
常量与变量的这种区别仅仅是表面的现象,深层次的区别在于:常量是以固定的方式被编写到了最终的计算机指令中,而变量却是存放在计算机内存中,每一个不同的变量都会在计算机内存中占据一块独立的存储空间。
在一个通用的32位计算机系统中,一个charr数据类型占用1字节的存储空间,一个int或者long或者float数据类型占用4字节的存储空间,一个double数据类型占用8字节的存储空间,其他还有很多不同的数据类型,各自占用存储空间。
既然变量在计算机内存中会占用一定的存储空间,那我们就有必要并且也必须知道这些变量到底被放在了计算机内存的哪个位置。
所以,我们首先需要对计算机内存中的每一个存储单元进行编号,这些不重复的编号就被称作内存单元地址,简称地址。
通常为了使用上的便捷,我们在对这些地址进行记录的时候采用十六迸制的方式,如果是8051系列的CPU,最大内存支持64K,也就是Ox0000-FFFF,而如果是通用的32位x86系列CPU,最大内存支持4G,0X00000000-0xFFFFFFFF,这种记录方式给我们带来的最大好处就是编号整齐,读起来一目了然。
什么是指针,指针就是一个内存单元的地址。
前面提到了计算机内存的每一个存储单元都有—个唯一的地址,每一变量在计算机内存中都会占用一定的存储空间(通常变量都占用不止一个单元的存储空间,我们用它们的首地址作为整个变量在内存中的地址),以一个通用的32位计算机系统为例,这个地址长度是—个8位的十六进制数。
而在C语言中,有一类非常特殊的变量,它们在内存中占用的空间恰好就是4个字节,而存储的内容就是一个以8位十六进制数表示的内存单元地址,这就是指针最本质的揭示。
不论什么类型的变量,他们的首地址肯定都是一个8位的十六进制数,所以,任何一种数据类型的指针都占用4个字节。
2常用指针类型的解析
2.1基本类型指针
Int a;
Int *p;
p=&a;
此种情况下,定义整型数据的指针P(即P变量中存放了一个内存单元的地址,该地址是某个整型变量在内存单元中的位置)。
所以,可以将整型变量a的地址(&a)赋值给整型指针P。
2.2指针与数组
Int a[4];
Int *p;
p=a;
此种情况下,定义整型数据的指针P,同时定义了整型数组a,对一个一维数组而言,数组名称即为该数组中第一个元素的地址,也就是数组的地址。
所以可以将整型数组的地址a赋值给整型指针P。
2.3二级指针
Int a;
Int *p;
Int **PP;
p=&a;
pp=&p;
此种情况下,定义了整型变量a和整型指针P,和我们分析的第一种情况完全一样。
但又定义了int *PP,即为一个二级指针。
怎么理解二级指针呢?前面分析过指针的本质就是一个变量,该变量在内存中占用4个节的存储空闻,而该变量区别于其他普通变量的就是其存放的内容(值)是另外某个内存存储单元的地址。
既然指针也是一个变量,那么很显然指针变量本身也具有一个内存单元,即指针本身的地址,我们通常使用一个二级指针来表示这一概念。
同理。
可以派生出更多级次的指针,但因为其过于复杂,一般没有实用价值。
2.4指针数组
Int *a[4];
Int**p;
p=a;
此种情况下,定义了一个指针数组a,数组中共有4个成员,每一个成员都是一个整型指针,而指针P是一个二级指针。
2.5数组指针
int(*p)[4];
int a[4l;
p=a;
此种情况下,定义了一个指针P,指针P指向一个有4个元素,且每个元素都是整型的数组。
而提被定义为一个有4个整型变量的数组,所以可以将a赋值给P。
对比第二种情况和第五
种情况,在第二种情况下,是将一个整型数组的地址赋值给了一个整型指针,而在第五种情况下,是将一个整型数组的地址赋值给了一个整型数组的指针,考虑到赋值关系左右两端应该具有的一致性,第五种应用方式似乎比第二种应用方式更完美。
2.6结构体指针
struct Stu
{
intno;
char
name[20];
l;
struct Stu*p;
struct Stu a:
p=&a;
在此种情况下,定义了一个结构体类型struct Stu,并且定义了一个该结构体变量a和一个该结构体指针P,a和P的最大区别就在于:a表示一个实际存在的结构体内容(即a变量中有一个整型成员和一个字符数组成员,共占有24字节的存储空间),而指针a仅仅表示了一个内存单元的地址,共4个字节(一个基本数据类型的指针和一个极其复杂的结构体类型的指针都分别只有4个字节的存储空间)。
2.7指针函数
int* func(int,int);
此种情况下,定义了一个函数func,该函数有两个整形变量作为参数,返回值类型为整形指针。
这就是通常称的指针函数,其本质仍然是在定义一个函数。
2.8函数指针
int(*func)(int,hat);
int g(int x,int y);
func=g;
此种情况下,定义了一个指针(而不是一个函数)func。
该指针指向了一个函数(即该指针变量中存放了一个函数在内存的存储地址),这个被指向的函数具有两个整形变量构成的参数,返回值是整型。
在对该函数指针赋值的时候。
必须采用一个类型完全一致的函数的名称。
当使用这个函数指针对函数进行调用的时候,可以采用下面两种方法:
func(x,y);
(*func)(x,y);
在通过函数指针调用函数的过程中,以上两种方法完全是等效的,但结合c语言的语法分析,似乎第二种方法更合理:func为一个指针,通过+将其中的值(地址)取出来,再到该地址空间开始函数的调用。
3指针类型的强制数据类型转换
在指针的各种应用中,强制数据类型转换是很常见的。
对指针的强制数据类型转换通常都不会有语法的错误(编译器通常都认为是合理的),而这些转换到底是否有意义,则需要程序员自己进行逻辑分析,下面就以一个比较常用的示例说明该问题。
struct Stu
I
int no;
char name[20];
};
struct Cls
{
struct Stu a[30];
);
此处定义了两个结构体类型,struct Stu和struct Cls,其中struct Cls类型中包含了一个struct Stu数组。
接下来定义指针如下:
Struct Cls*P;
这是一个struct Cls类型的指针,它指向一个struct Cls类型的变量,当我们对其进行强制数据类型转换如下:
(Struct Stu*)p;
此时指针P就被强制转换成为了一个指struct Stu类型的指针了。
指针的应用是c语言的精髓部分之一,在此仅仅对一些常用的形式作了分析,熟练地掌握指针,必将使c语言的编程水平上升一个新的台阶。