C中指针明析

来源:互联网 发布:手机彩票关注源码 编辑:程序博客网 时间:2024/05/19 12:11
基础概念:

   一个指针是一个地址,是一个常量。而一个指针变量却可以被赋予不同的指针值,是变量。

    我们中约定:“指针”是指地址,是常量,“指针变量”是指取值为地址的变量。定义指针的目的是为了通过指针去访问内存单元。
指针变量的值是一个地址,那么这个地址不仅可以是变量的地址,也可以是其它数据结构的地址。在一个指针变量中存放一个数组或一个函数的首地址有何意义呢? 因为数组或函数都是连续存放的。通过访问指针变量取得了数组或函数的首地址,也就找到了该数组或函数。这样一来,凡是出现数组,函数的地方都可以用一个指针变量来表示,只要该指针变量中赋予数组或函数的首地址即可。这样做,将会使程序的概念十分清楚,程序本身也精练,高效。在C语言中,一种数据类型或数据结构往往都占有一组连续的内存单元。 用“地址”这个概念并不能很好地描述一种数据类型或数据结构,而“指针”虽然实际上也是一个地址,但它却是一个数据结构的首地址,它是“指向”一个数据结构的,因而概念更为清楚,表示更为明确。


   指针的加减法:

    只针对指向数据的指针有意义,指向其他的类型变量无意义。这里的加减表示,指针向前或向后移动一个位置,在数组上来说,就是上一个元素或下一个元素的区别,跟我们的地址值加一减一不一样。


实例说明:

 *P++,因为*与++优先级相同,根据右结合,所以可以写成*(P++),这样更容易看懂。 指针变量加减时,是数组前移或后移。


int a[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}}

a[0]是第一个一维数组的数组名和首地址,因此也为1000。*(a+0)或*a是与a[0]等效的, 它表示一维数组a[0]0 号元素的首地址,也为1000。&a[0][0]是二维数组a的0行0列元素首地址,同样是1000。因此,a,a[0],*(a+0),*a,&a[0][0]是相等的。

同理,a+1是二维数组1行的首地址,等于1008。a[1]是第二个一维数组的数组名和首地址,因此也为1008。&a[1][0]是二维数组a的1行0列元素地址,也是1008。因此a+1,a[1],*(a+1),&a[1][0]是等同的。

由此可得出:a+i,a[i],*(a+i),&a[i][0]是等同的。

此外,&a[i]和a[i]也是等同的。因为在二维数组中不能把&a[i]理解为元素a[i]的地址,不存在元素a[i]。C语言规定,它是一种地址计算方法,表示数组a第i行首地址。由此,我们得出:a[i],&a[i],*(a+i)和a+i也都是等同的。

另外,a[0]也可以看成是a[0]+0,是一维数组a[0]的0号元素的首地址,而a[0]+1则是a[0]的1号元素首地址,由此可得出a[i]+j则是一维数组a[i]的j号元素首地址,它等于&a[i][j]。

由a[i]=*(a+i)得a[i]+j=*(a+i)+j。由于*(a+i)+j是二维数组a的i行j列元素的首地址,所以,该元素的值等于*(*(a+i)+j)。

因为是二维数组,所以*a指向的并不是二维数组中的一个数,而是一个地址,*(a+1)同样是一个地址;只有*(*(a+1)+2)与*(a[1]+2)这个指向的才是二维数组中的元素。


二维指针的表达形式为:

类型说明符  (*指针变量名)[长度]

int a[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}};

把二维数组a分解为一维数组a[0],a[1],a[2]之后,设p为指向二维数组的指针变量。可定义为:int (*p)[4]

注意:指针变量名与*必须要用括号包起来。

例子:

main(){    int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};    int(*p)[4];    int i,j;    p=a;    for(i=0;i<3;i++){for(j=0;j<4;j++) printf("%2d  ",*(*(p+i)+j));printf("\n");}}



函数指针:

   

函数指针变量定义的一般形式为:

类型说明符  (*指针变量名)();

int max(int a,int b){  if(a>b)return a;  else return b;}main(){  int max(int a,int b);  int(*pmax)();  int x,y,z;  pmax=max;  printf("input two numbers:\n");  scanf("%d%d",&x,&y);  z=(*pmax)(x,y);  printf("maxmum=%d",z);}

1) 调用函数的一般形式为:

    (*指针变量名) (实参表)



指针型函数

在C语言中允许一个函数的返回值是一个指针(即地址),这种返回指针值的函数称为指针型函数。

定义指针型函数的一般形式为:

    类型说明符 *函数名(形参表)  

    {  

        ……          /*函数体*/

    }  

例子:

main(){  int i;  char *day_name(int n);     printf("input Day No:\n");  scanf("%d",&i);  if(i<0) exit(1);  printf("Day No:%2d-->%s\n",i,day_name(i));}char *day_name(int n){  static char *name[]={ "Illegal day",                        "Monday",                        "Tuesday",                        "Wednesday",                        "Thursday",                        "Friday",                        "Saturday",                        "Sunday"};  return((n<1||n>7) ? name[0] : name[n]);}


指针数组:

main(){int a[3][4]={0,1,2,3,4,5,6,7,8,9};      int *pa[3]={a[0],a[1],a[2]};      int *p=a[0];      int i;      for(i=0;i<3;i++)      printf("%d,%d,%d\n",a[i][2-i],*a[i],*(*(a+i)+i));            printf("=======================\n");      for(i=0;i<3;i++)      printf("%d,%d,%d\n",*pa[i],p[i],*(p+i));   }   main(){     static char *name[]={ "Illegal day",                        "Monday",                        "Tuesday",                        "Wednesday",                        "Thursday",                        "Friday",                        "Saturday",                        "Sunday"};  char *ps;  int i;  char *day_name(char *name[],int n);  printf("input Day No:\n");  scanf("%d",&i);  printf("input Day after %s:\n",*name);  ps=day_name(name,i);  printf("Day No:%2d-->%s\n",i,ps);}char *day_name(char *name[],int n){  char *pp1,*pp2;  pp1=*name;  printf("ddd *name %s:\n",*(name+2));  pp2=*(name+n);  return((n<1||n>7)? pp1:pp2);}


这里的区别,是由于char与int打印不一样造成,char打印,只需要给出地址即可,int必须给出具体的值。

另外,*name与name[0],是一样的,就比如说:*(name+1)与name[1]等同。

注意:当指针数据当成一个实参,传递给函数形参时,此时形参相当于是char **,意义为指向指针的指针,也就是双重指针的意思,这里的地址也就必须使用*name来表示指向第一个元素的内存位置。(可以想象的是,name数组中,是一个一个的地址,这些地址会指向一个一个的字符串,就是这个意思)


指向指针的指针:

  

main(){static int a[5]={1,3,5,7,9}; int *num[5]={&a[0],&a[1],&a[2],&a[3],&a[4]}; int **p,i; p=num; for(i=0;i<5;i++)   {printf("%d\t",**p);p++;}}


可以想象一个模型是,在num数组中有5个元素,每个元素都存放着一个指向int型元素的地址,  此时,p变量的值为num的首地址,则*p的值为num数组中的第一个元素的内容,也就是一个地址值,**p,就为这个地址值所指向的int值。

当p++时,根据右结合定律,**p,会先去做一次*p,其实也就是*(*(p+1))的操作,这时,实际情况是,把p变量的值,设置为num数组第二元素的地址。然后*(p+1)的内容就是num数组中,第二个元素(地址值)内容,**(p+1),就再交指向地址址所指的int值。
















 

   

  


原创粉丝点击