1:指针四要素(这部分主要从网上搜索到的,还不错):
指针的类型
指针所指向的类型
指针的值或者叫指针所指向的内存区
指针本身所占据的内存区
1 指针的类型。
从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。让我们看看例一中各个指针的类型:
(1)int *ptr; //指针的类型是int *
(2)char *ptr; //指针的类型是char *
(3)int **ptr; //指针的类型是 int **
(4)int (*ptr)[3]; //指针的类型是 int(*)[3]
(5)int *(*ptr)[4]; //指针的类型是 int *(*)[4]
怎么样?找出指针的类型的方法是不是很简单?
1 .2指针所指向的类型。
当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待。从语法上看,你只须把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。例如:
(1)int *ptr; //指针所指向的类型是int
(2)char *ptr; //指针所指向的的类型是char
(3)int **ptr; //指针所指向的的类型是 int *
(4)int (*ptr)[3]; //指针所指向的的类型是 int()[3]
(5)int *(*ptr)[4]; //指针所指向的的类型是 int *()[4]
在指针的算术运算中,指针所指向的类型有很大的作用。
指针的类型(即指针本身的类型)和指针所指向的类型是两个概念。当你对C越来越熟悉时,你会发现,把与指针搅和在一起的"类型"这个概念分成"指针的类型"和"指针所指向的类型"两个概念,是精通指针的关键点之一。
1.3指针的值,或者叫指针所指向的内存区或地址。
指针的值是指针本身存储的数值,这个值将被编译器当作一个地址,而不是一个一般的数值。在32位程序里,所有类型的指针的值都是一个32位整数,因为32位程序里内存地址全都是32位长。
指针所指向的内存区就是从指针的值所代表的那个内存地址开始,长度为sizeof(指针所指向的类型)的一片内存区。以后,我们说一个指针的值是XX,就相当于说该指针指向了以XX为首地址的一片内存区域;我们说一个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的首地址。
指针所指向的内存区和指针所指向的类型是两个完全不同的概念。在例一中,指针所指向的类型已经有了,但由于指针还未初始化,所以它所指向的内存区是不存在的,或者说是无意义的。
以后,每遇到一个指针,都应该问问:这个指针的类型是什么?指针指向的类型是什么?该指针指向了哪里?
1.4指针本身所占据的内存区。
指针本身占了多大的内存?你只要用函数sizeof(指针的类型)测一下就知道了。在32位平台里,指针本身占据了4个字节的长度。指针本身占据的内存这个概念在判断一个指针表达式是否是左值时很有用。(注释:在picc18里,指针占用了两个字节)
下面就picc18列举个实例看下面程序
intdata[10]={1,2,4,5,6,7,8};
intlenth1,lenth2,lenth3;
int*ptr1,*ptr2;
main()
{
ptr1=&data[0];
ptr2=&data[1];
lenth1=ptr2-ptr1;
lenth2=(int)ptr2-(int)ptr1;
lenth3=*ptr2-*ptr1;
}
在watch窗口可以看到lenth1 为1,而lenth2为2,可以这样解释:在lenth1=ptr2-ptr1;这条语句中两个INT类型指针变量相减得一个(这在c中是允许的)非指针的数,这个数的代表如下:
如果这两个指针指向的内型为INT型,那么这个数代表两个指针之间相隔多少个INT型变量,显然在以上程序中,data[0],和data[1]之间相隔了1个INT型变量。
而在 lenth2=(int)ptr2-(int)ptr1;实际上是求data[1]和data[0]之间占用多少个内存空间,注意(int)ptr是ptr的值(不是ptr所指向的数的值)
lenth3=*ptr2-*ptr1;相信稍微懂c的人都知道是在求ptr所指向的两个值之间的差,和lenth3=data[1]-data[0]等效。
大家不防试试lenth4=(char*)ptr2-(char*)ptr1;看看等于多少,
2: 指针函数和函数指针有什么区别
2.1,这两个概念都是简称,指针函数是指带指针的函数,即本质是一个函数。我们知道函数都又返回类型(如果不返回值,则为无值型),只不过指针函数返回类型是某一类型的指针。其定义格式如下所示:
返回类型标识符 *返回名称(形式参数表)
{ 函数体 }
返回类型可以是任何基本类型和复合类型。返回指针的函数的用途十分广泛。事实上,每一个函数,即使它不带有返回某种类型的指针,它本身都有一个入口地址,该地址相当于一个指针。比如函数返回一个整型值,实际上也相当于返回一个指针变量的值,不过这时的变量是函数本身而已,而整个函数相当于一个“变量”。例如下面一个返回指针函数的例子:
chardata[10];
char*test(void);
main()
{
char *ptr;
ptr=test();
}
char* test(void)
{
char *p;
p=data;
return p;
}
注意:该程序在picc18中调试
2.2,“函数指针”是指向函数的指针变量,因而“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。如前所述,C在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。有了指向函数的指针变量后,可用该指针变量调用函数,就如同用指针变量可引用其他类型变量一样,在这些概念上一致的。函数指针有两个用途:调用函数和做函数的参数。函数指针的说明方法为:
数据类型标志符 (*指针变量名)(参数);注:函数括号中的参数可有可无,视情况而定。
下面的程序说明了函数指针调用函数的方法:
charmax(char x,char y);
char min(char x,char y);
char (*ptr)(char,char);
char a=2,b=3,c;
main()
{
ptr=max;
c=(*ptr)(a,b);
ptr=min;
c=(*ptr)(a,b);
}
char max(char x,char y)
{
return x>=y?x:y;
}
char min(char x,char y)
{
return x<=y?x:y;
}
注意:该程序在picc18中调试
在pic的c程序编写中,函数指针不是很常用,如果大家有兴趣看看UCOS的pic18的移植版本,就可以发现ucos中是用函数指针传递任务程序的入口地址的。
3:结构联合与指针
先看下面的一个简单的举例
typedef struct datas
{
char datah;
char datal;
struct datas*next;
} data;
//a是一个结构变量
dataa,b;
data*ptr1,*ptr2;
main()
{
ptr1=&a;
ptr1->datah =1;
ptr1->datal =2;
ptr2=&b;
ptr1->datah =3;
ptr1->datal =4;
ptr1->next=ptr2;
ptr2->next=0;
}
数据a,b是一个结构型变量,ptr则是指向结构型变量的指针,在c语言里,通过形如ptr->x的形式来访问结构或者指针的成员。
在结构变量中定义了一个指针struct datas*next; 这是在指针链中常用到的,ptr1->next=ptr2;ptr2->next=0;实际上已经建立了一条简单的指针链,当然建立指针链用这种初始化的方法不够简单,但是上面的程序只是为了说明指针和结构而已。
在单片机的c语言程序中,联合和结构是经常用在一起的下面在举一个简单的列子:
typedef struct
{
char datah;
char datal;
} data;
typedefunion
{
datatwpbyte;
intbytes;
} piccdata;
piccdataadres[10];
piccdata*ptr1,*ptr2;
charlenth1,lenth2;
main()
{
ptr2=adres;
ptr1=adres;
ptr1++;
lenth1=ptr1-ptr2;
lenth2=(char)ptr1-(char)ptr2;
}
在以上程序中,lenth2为2,而lenth1为1,道理和第一个列子一样,只是应该注意的是在piccdata型变量中占用的空间为2个字节而不是4个字节!!!
另:结构与联合是pic应用的一个好东西,这点HOTpower曾经有一很经典的文章,在此列中,只要稍微加以改动,就可以对一个16位变量即可以整体访问,也可分为高八位访问和低八位访问。这在ad转换中是很有用的。
4:const与指针
const是一个C语言的关键字,它限定一个变量不允许被改变。如果const关键字不涉及到指针,我们很好理解,下面是涉及到指针的情况:
int b = 500;
const int* a = &b;[1]
int const *a = &b;[2]
Int* const a = &b;[3]
const int* const a = &b;[4]
如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。因此,[1]和[2]的情况相同,都是指针所指向的内容为常量(const放在变量声明符的位置无关),这种情况下不允许对内容进行更改操作,如不能*a = 3 ;[3]为指针本身是常量,而指针所指向的内容不是常量,这种情况下不能对指针本身进行更改操作,如a++是错误的;[4]为指针本身和指向的内容均为常量。
有了上面的基础,对于在picc18中的c语言应用就可以开始了,在单片机编程中,经常会用到查表程序等,通常把大量的数据放入rom中,下面是一个简单的列子
const int a[8]={1,2,3,-3,3,5,6,7};
const int *ptr;
main()
{
ptr=a;
ptr++;
}
显然ptr是一个指向常量的指针,ptr指向的数是不可变的,但是ptr本身是可变的,我们可以通过ptr来访问定义在rom中的数组a[8];