C中指針明析

基礎概念:

   一個指針是一個地址,是一個常量。而一個指針變量卻可以被賦予不同的指針值,是變量。

    我們中約定:“指針”是指地址,是常量,“指針變量”是指取值爲地址的變量。定義指針的目的是爲了通過指針去訪問內存單元。
指針變量的值是一個地址,那麼這個地址不僅可以是變量的地址,也可以是其它數據結構的地址。在一個指針變量中存放一個數組或一個函數的首地址有何意義呢? 因爲數組或函數都是連續存放的。通過訪問指針變量取得了數組或函數的首地址,也就找到了該數組或函數。這樣一來,凡是出現數組,函數的地方都可以用一個指針變量來表示,只要該指針變量中賦予數組或函數的首地址即可。這樣做,將會使程序的概念十分清楚,程序本身也精練,高效。在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值。
















 

   

  


發佈了24 篇原創文章 · 獲贊 4 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章