轉載了N多指針相關的東東

一、基礎能力訓練:
	編寫一個程序實現功能:將字符串"Computer Secience"賦給一個字符數組,然後從第一個字母開始間隔的輸出該串,用指針完成。
#include <stdio.h>
#include <string.h>

int main()
{
	char str[]="Computer Science";
    int flag=1;
	char *p=str;

	while(*p)
	{
	   if ( flag )
	   { 
    	  printf("%c",*p);
       }
       flag = (flag + 1) % 2;
       p++;
    }
	printf("\n");
    return 0;
}


  

用指針將數組s[8]={1,2,3,4,5,6,7,8}中的值逆序存放。
	#include <stdio.h>
	
	int main()
	{
	    int s[8]={1,2,3,4,5,6,7,8};
	    int *p,*q,count,swap;
	
	    count = sizeof(s)/sizeof(int);
	    p=s; q=s+count-1;
	    while( p < q )
	    {
	       swap = *p;
	       *p = *q;
	       *q = swap;
	       p++;
	       q--;
	     }
	
	     for(p=s; p<s+count; p++)  printf("%d ", *p);
	
	     return 0;
	}
	
	
3)編寫一個程序實現功能:將兩個字符串合併爲一個字符串並且輸出,用指針實現。
	   char str1[20]={"Hello "}, str2[20]={"World "};
	
	#include <stdio.h>
	
	int main()
	{
	   char str1[20]={"Hello "}, str2[20]={"World "};
	   char *p=str1, *q=str2;
	
	   while( *p ) p++;
	   while( *q ) 
	   {
	      *p = *q;
	      p++;
	      q++;
	    }
	    *p = '\0';
	    printf("%s\n", str1);
	
	    return 0;
	}
	
4) 編寫一個程序實現以下功能:用指針數組處理一個二維數組,要求求出二維數組所有元素的和。
	        int array[3][4]={ {7,  10, -2,   3},
	                          {14, 30,  6, -15},
	                          {0,   5,  27, -7}
                         }  
#include <stdio.h>

int main()
{
  int array[3][4]={{7,10,-2,3},{14,30,6,-15},{0,5,27,-7}};
  int *pa[3]={array[0], array[1], array[2]}, i, j;
  int sum=0;

  for(i=0;i<3;i++)
  {
    for(j=0;j<4;j++,pa[i]++)
    {
      sum+=*pa[i];
    }
  }
  printf("%d\n",sum);
  return 0;
}


已知數組a[10]和b[10]中元素的值遞增有序,用指針實現將兩個數組中的元素按遞增的順序輸出。

#include <stdio.h>

int main()
{
   int a[10]={1,  4,  12,  13,  14,  20,  25,  32,  33,  40};
   int b[10]={0,  3,  15,  18,  19,  25,  39,  43,  44,  50};
   int *p=a, *q=b;

   while( (p < (a+10)) && (q < (b+10)) )
   {
      if( *p < *q )
      {
         printf("%d ", *p);
         p++;
      }
      else
      {
         printf("%d ", *q);
         q++;
      }
   }

   if( p = = (a+10) )
   {
      p = q;
      q = b;
   }
   else
   {
      q = a;
   }

   while( p < (q+10) )
   {
      printf("%d ", *p++);
   }

   printf("\n");
   return 0;
}


6) 定義字符指針數組char *str[5]分別指向5個字符串常量,從小到大輸出字符串的內容。

   #include <stdio.h>

	int main()
	{
      int i,j,min;
      char *str[5]={ "Shanghai",
                  "Beijing",
                  "Guangzhou",
                  "Tianjin",
                  "Chongqin"
                };
      char *p;

      for(i=0;i<4;i++)
      {
         min = i;

         for(j=i+1;j<5;j++ )
         {
            if( strcmp(str[min],str[j]) > 0 )
            {
               min = j;
            }
         }
         p = str[i];
         str[i] = str[min];
         str[min] = p;
      }

     for(i=0;i<5;i++)
     {
        printf("%s\n", str[i]);
     }

     return 0;
	}


7)  已知數組內容如下s[]={1,2,3,4,5,6,7,8,9}, 輸入一個數n(1 <= n <= 9),
使得該數組內容順序後移n個位置。
如n=3時,數組後移3個位置後的內容爲{7,8,9,1,2,3,4,5,6}

#include <stdio.h>
#include <stdlib.h>

#define LEN 9 

int main()
{
   int array[LEN]={1,2,3,4,5,6,7,8,9};
   int i,num,temp,*p;

   printf("Please input the number(1-9) of elements you want to move:");
   scanf("\n%d", &num);

   if((num < 1 ) || (num > 9))
   {
      printf("The number is out of range(1-9), exit...\n");
      exit(0);
   }

   for(i=0;i<num;i++)
   {
      temp = *(array+LEN-1);
      for(p=array+LEN-1;p>array;p--)
      {
         *p = *(p-1);
      }
      *p = temp;
   }

   for(p=array;p<array+LEN;p++) printf("%d ", *p);
   printf("\n");

   return 0;
}



8)  輸入一個字符串,內有數字和非數字字符,如 a123x456 17960? 302tab5876  將
其中連續的數字作爲一個整數,依次存放到整型數組a中。例如,123放在a[0],456放在a[1],統計共有多少個整數,並輸出這些數。

#include <stdio.h>

#define LEN 80

int main()
{
   char str[LEN],*p;
   int array[LEN/2],value=0,n=0;
   int begin_count=0; 

   printf("Please input a string which including any digits:\n");
   gets(str);
   //printf("%s\n", str);
   p = str;
   while( *p )
   {
      if ((*p >= '0') && (*p <= '9'))
      {
         begin_count = 1;
         value = value*10 + *p - '0';
      }
      else
      {
         if ( begin_count = = 1)
         {
            array[n++]=value;
            begin_count = 0;
            value = 0;
         }
      }
      p++;  
   }
   if (begin_count = = 1) array[n++]=value;
   for(value=0;value<n;value++) printf("%d ", array[value]);
   printf("\n");   

   return 0;
}

//==========================================================================
試驗九  函數
1) 編寫函數分別實現以下功能:(1)求兩個浮點數之和;(2)求兩個浮點數之差;(3)求兩個浮點數之積。
	
	#include <stdio.h>
	double add(double a, double b)
	{
		return a+b;
	}
	double subtract(double a, double b)
	{
		return a-b;
	}
	double multiple(double a,double b)
	{
		return a*b;
	}
	int main()
	{
		double num1,num2;
		printf("please input tow number:");
		scanf("%lf %lf",&num1,&num2);
		printf("%5.2f + %5.2f = %5.2f\n",num1,num2,add(num1,num2));
		printf("%5.2f + %5.2f = %5.2f\n",num1,num2,subtract(num1,num2));
		printf("%5.2f + %5.2f = %5.2f\n",num1,num2,multiple(num1,num2));
	}
	
	
2) 編寫一個函數,包括一個字符參數和兩個整型參數。字符參數是需要輸出的字符,
第一個整型參數說明了在每行中該字符輸出的個數,而第二個整型參數指的是需要輸
出的行數,編寫一個調用該函數的程序。
#include <stdio.h>
int main(void)    
{
	char ch;
	int i, j, col, row;
	    
printf("Enter a character : ");
	ch = getchar();           
	printf("Enter number of columns and number of rows: ");
	if (scanf("%d %d", &col, &row) != 2) return -1;
	for (i = 0; i < row ; i++)
	{
	for (j = 0; j < col; j++)
	{
	    putchar(ch);
	}
        putchar('\n');
	}
	return 0;
	}



3) 編寫一個函數taxis()實現數組的排序,在函數中調用swap()實現兩個數的交換。
打印出排序結果。

#include <stdio.h>

void swap(int *a,int *b)
{
	int tmp;
	tmp=*a;
	*a=*b;
	*b=tmp;
}

void taxis(int *a, int num)
{
	int i,j;
	for(i=0;i<num-1;i++)
	{
		for(j=i+1;j<num;j++)
		{
			if(a[i] > a[j])
				swap(&a[i],&a[j]);
}
}
}

int main()
{
	int i,a[]={2,5,9,8,7,6,4,3,1};
	taxis(a, sizeof(a)/sizeof(int));
	for(i=0;i<sizeof(a)/sizeof(int);i++)
	{
		printf("%d\t",a[i]);
}
printf("\n");
return 0;
}



4) 編寫一個函數,實現兩個字符串的比較。

	#include <stdio.h>
	int my_strcmp(char *p,char *q)
	{
		int i=0;;
		
		while(*(p+i) == *(q+i))
	    {
		   if( *(p+i) = ='\0' )  return 0;
           i++;
        } 
		return(*(p+i) - *(q+i));
	}
	
	int main()
	{
		int m;
	char str1[20],str2[20];
	
		printf("Input tow strings:");
		gets(str1);
	    gets(str2);
		printf("result:%d\n",my_strmp(str1,str2));
	    return 0;
	}



編寫一個函數is-within().它接受兩個參數,一個是字符,
另一個是字符串指針。其功能是如果字符在字符串中。
就返回1(真);如果字符不在字符串中,就返回0(假)。
在一個使用循環語句爲這個函數提供輸入的完整程序中進行測試。

	#include <stdio.h>
	#define  LEN  80
	int is_within(const char * str, char c);
	int main(void)
	{
	    char input[LEN];
	    char ch;
	    int found;;
	    
	    printf("Enter a string: ");
	    while (gets(input) && input[0] != '\0')
	    {
	        printf("Enter a character: ");
	        scanf("\n%c",  &ch);
	        found = is_within(input, ch);
	        if (found = = 0)
	            printf("%c not found in string.\n", ch);
	        else
	            printf("%c found in string %s\n", ch, input);
	        printf("Next string: ");
	    }
	    puts("Done.\n");
	    
	    return 0;
	}
	
	int is_within(const char * str, char ch)
	{
	    while (*str != ch && *str != '\0')
	    {
	        str++;
	    }
	    return *str;   /* = 0  if '\0'is reached, non-zero otherwise */
	}



輸出程序運行時的命令行參數。例如:
./myprog  a  b  c
a  b  c

#incldue <stdio.h>
int main(int argc,char *argv[])
{   int i = 1;
	while( i < argc )
	{
		printf("%s ",argv[i]);
		i++;
	}
	printf("\n");
	return 0;
}	



7) 以下函數的功能是用遞歸的方法計算x的n階勒讓德多項式的值。已有調用語句p(n,x);編寫函數實現功能。遞歸公式如下:
	
	
	
	#include <stdio.h>
	
	float p(int x,int n)
	{
		float t,t1,t2;
		if(n= =0) return 1;
		else if(n= =1) return x;
		else 
		{
			t1=(2*n-1)*x*p(x,(n-1));
			t2=(n-1)*p(x,(n-2));
			t=(t1-t2)/n;
			return t;
	}
	}
	
	int main()
	{
		int x,n;
		printf("input two int (x and n):");
		scanf("%d%d",&x,&n);
		printf("%.2f\n",p(x,n));
		return 0;
	}
	//===========================================================
	指針函數和函數指針的區別(轉載)
1,這兩個概念都是簡稱,指針函數是指帶指針的函數,即本質是一個函數。
我們知道函數都又返回類型(如果不返回值,則爲無值型),
只不過指針函數返回類型是某一類型的指針。其定義格式如下所示:

返回類型標識符 *返回名稱(形式參數表) 
{ 函數體 }

  返回類型可以是任何基本類型和複合類型。返回指針
的函數的用途十分廣泛。事實上,每一個函數,即使它不
帶有返回某種類型的指針,它本身都有一個入口地址,該
地址相當於一個指針。比如函數返回一個整型值,實際上
也相當於返回一個指針變量的值,不過這時的變量是函數
本身而已,而整個函數相當於一個“變量”。例如下面一
個返回指針函數的例子:

#include

float *find(); 
main() 
{ 
  static float score[][4]={{60,70,80,90},{56,89,34,45},{34,23,56,45}}; 
  float *p; 
  int i,m; 
  printf("Enter the number to be found:"); 
  scanf("%d",&m); 
  printf("the score of NO.%d are:\n",m); 
  p=find(score,m); 
  for(i=0;i<4;i++) 
    printf("%5.2f\t",*(p+i)); 
}

float *find(float(*pionter)[4],int n)/*定義指針函數*/ 
{ 
  float *pt; 
  pt=*(pionter+n); 
  return(pt); 
}

  學生學號從0號算起,函數find()被定義爲指針函數,起形參
pointer是指針指向包含4個元素的一維數組的指針變量。
pointer+1指向score的第一行。*(pointer+1)指向第一行的第0個元素。
pt是一個指針變量,它指向浮點型變量。main()函數中調用find()函數,
將score數組的首地址傳給pointer.

2,“函數指針”是指向函數的指針變量,因而“函數指針”
本身首先應是指針變量,只不過該指針變量指向函數。
這正如用指針變量可指向整型變量、字符型、數組一樣,
這裏是指向函數。如前所述,C在編譯時,每一個函數都有
一個入口地址,該入口地址就是函數指針所指向的地址。
有了指向函數的指針變量後,可用該指針變量調用函數,
就如同用指針變量可引用其他類型變量一樣,在這些概念
上一致的。函數指針有兩個用途:調用函數和做函數的參
數。函數指針的說明方法爲: 
數據類型標誌符 (*指針變量名)(參數);
注:函數括號中的參數可有可無,視情況而定。 
下面的程序說明了函數指針調用函數的方法:

#include"stdio.h"
                                                  
int max1(int x,int y)
{ return(x>y?x:y); }
int max2(int x,int y)
{ return(x>y?x:y); }
void main() 
{ 
  int (*ptr)(); 
  int a,b,c; 
  ptr=max1; 
  scanf("%d,%d",&a,&b); 
  c=(*ptr)(a,b); 
  printf("a=%d,b=%d,max=%d",a,b,c); 
  ptr=max2; 
  scanf("%d,%d",&a,&b); 
  c=(*ptr)(a,b); 
  printf("a=%d,b=%d,max=%d",a,b,c); 
}

  ptr是指向函數的指針變量,所以可把函數max()
賦給ptr作爲ptr的值,即把max()的入口地址賦給ptr,
以後就可以用ptr來調用該函數,實際上ptr和max都指
向同一個入口地址,不同就是ptr是一個指針變量,
不像函數名稱那樣是死的,它可以指向任何函數,
就看你像怎麼做了。在程序中把哪個函數的地址賦給它,
它就指向哪個函數。而後用指針變量調用它,因此可以
先後指向不同的函數,不過注意,指向函數的指針變量沒
有++和--運算,用時要小心。




指針函數是指函數的返回值類型是一個指針類型,即本質是一個函數。
  我們知道函數都有返回類型(如果不返回值,則爲無值型),
只不過指針函數返回類型是某一類型的指針。其定義格式如下所示:
  返回類型標識符 *函數名稱(形式參數表)
  { 函數體 }
  返回類型可以是任何基本類型和複合類型。
返回指針的函數的用途十分廣泛。事實上,每一個函數,
即使它不帶有返回某種類型的指針,它本身都有一個入
口地址,該地址相當於一個指針。比如函數返回一個整型
值,實際上也相當於返回一個指針變量的值,不過這時的
變量是函數本身而已,而整個函數相當於一個“變量”。
例如下面一個返回指針函數的例子:
#include <stdio.h>
  float *find(float(*pionter)[4],int n);
  main()
  {
  static float score[][4]={{60,70,80,90},{56,89,34,45},{34,23,56,45}};
  float *p;
  int i,m;
  printf("Enter the number to be found:");
  scanf("%d",&m);
  printf("the score of NO.%d are:\n",m);
  p=find(score,m-1);
  for(i=0;i<4;i++)
  printf("%5.2f\t",*(p+i));
  }
  float *find(float(*pionter)[4],int n)/*定義指針函數*/
  {
  float *pt;
  pt=*(pionter+n);
  return(pt);
  }
共有三個學生的成績,函數find()被定義爲指針函數,起
形參pointer是指針指向包含4個元素的一維數組的指針變
量。pointer+n指向score的第n+1行。*(pointer+1)指向第
一行的第0個元素。pt是一個指針變量,它指向浮點型變量。
main()函數中調用find()函數,將score數組的首地址傳
給pointer.
  【注意】
  指針函數不同於函數指針, int (*f)(int a);
或者char (*f1)(void);
  函數指針聲明爲指針,它與變量指針不同之處是,
它不是指向變量,而是指向函數。
  函數指針有兩個用途:調用函數和做函數的參數.
////////////////////////////////////////////////////////////////////////百科名片

函數指針

函數指針是指向函數的指針變量。 因而“函數指針”本身首
先應是指針變量,只不過該指針變量指向函數。這正如用指針
變量可指向整型變量、字符型、數組一樣,這裏是指向函數。
如前所述,C在編譯時,每一個函數都有一個入口地址,該入
口地址就是函數指針所指向的地址。有了指向函數的指針變量後,
可用該指針變量調用函數,就如同用指針變量可引用其他類型變量
一樣,在這些概念上是一致的。函數指針有兩個用途:調用函數和
做函數的參數。

目錄

方法
指針函數和函數指針的區別
關於函數指針數組的定義
  方法
  函數指針的聲明方法爲:   
數據類型標誌符 (指針變量名) (形參列表);   
注1:“函數類型”說明函數的返回類型,由於“()”的優先級高於“*”,
所以指針變量名外的括號必不可少,後面的“形參列表”表示指針變量
指向的函數所帶的參數列表。例如:   
int func(int x); /* 聲明一個函數 */   
int (*f) (int x); /* 聲明一個函數指針 */   
f=func; /* 將func函數的首地址賦給指針f */   
賦值時函數func不帶括號,也不帶參數,由於func代表函數的首地址,
因此經過賦值以後,指針f就指向函數func(x)的代碼的首地址。   
注2:函數括號中的形參可有可無,視情況而定。   
下面的程序說明了函數指針調用函數的方法:   
例一、   
#include<stdio.h>   
int max(int x,int y)
{ return(x>y?x:y); }   
void main()   
{   
int (*ptr)(int, int);   
int a,b,c;   
ptr=max;   
scanf("%d,%d",&a,&b);   
c=(*ptr)(a,b);   
printf("a=%d,b=%d,max=%d",a,b,c);   
}   
ptr是指向函數的指針變量,所以可把函數max()賦給ptr作爲ptr的值,
即把max()的入口地址賦給ptr,以後就可以用ptr來調用該函數,實際
上ptr和max都指向同一個入口地址,不同就是ptr是一個指針變量,
不像函數名稱那樣是死的,它可以指向任何函數,就看你想怎麼做了。
在程序中把哪個函數的地址賦給它,它就指向哪個函數。而後用指針變
量調用它,因此可以先後指向不同的函數。不過注意,指向函數的指針
變量沒有++和--運算,用時要小心。


   
不過,在某些編譯器中這是不能通過的。這個例子的補充如下。   
應該是這樣的:   
1.定義函數指針類型:   
typedef int (*fun_ptr)(int,int);   
2.申明變量,賦值:   
fun_ptr max_func=max;   

也就是說,賦給函數指針的函數應該和函數指針所指的函數原型是一致的。   
例二、   
#include<stdio.h>   
void FileFunc()   
{   printf("FileFunc\n");   }   
void EditFunc()   
{   printf("EditFunc\n");   }   
void main()   
{   
typedef void (*funcp)();   
funcp=FileFunc;   
(*funcp)();   
funcp=EditFunc;   
(*funcp)();   
}
 指針函數和函數指針的區別
  1,這兩個概念都是簡稱,指針函數是指帶指針的函數,即本質是一
個函數。我們知道函數都又有返回類型(如果不返回值,則爲無值型),
只不過指針函數返回類型是某一類型的指針。   
其定義格式如下所示:   
返回類型標識符 *返回名稱(形式參數表)   
{ 函數體 }   
返回類型可以是任何基本類型和複合類型。返回指針的函數的用途十分廣泛。
事實上,每一個函數,即使它不帶有返回某種類型的指針,它本身都有一個入
口地址,該地址相當於一個指針。比如函數返回一個整型值,實際上也相當於
返回一個指針變量的值,不過這時的變量是函數本身而已,而整個函數相當於
一個“變量”。
例如下面一個返回指針函數的例子:   
#include<iostream>   
using namespace std;   
void main()   
{   
float *find(float(*pionter)[4],int n);   
static float score[][4]={{60,70,80,90},{56,89,34,45},{34,23,56,45}};   
float *p;   
int i,m;   
cout<<"Enter the number to be found:";   
cin>>m;   
p=find(score,m);   
for(i=0;i<4;i++)   
cout<<" "<<*(p+i);   
}   
float *find(float(*pionter)[4],int n)/*定義指針函數*/   
{   float *pt;   pt=*(pionter+n);   return(pt);   }   
學生學號從0號算起,函數find()被定義爲指針函數,起形參pointer是指
針指向包含4個元素的一維數組的指針變量。pointer+1指向 score的第一行。
*(pointer+1)指向第一行的第0個元素。pt是一個指針變量,它指向浮點型變
量。
main()函數中調用find()函數,將score數組的首地址傳給pointer.   
2,“函數指針”是指向函數的指針變量,因而“函數指針”本身首先應是指針
變量,只不過該指針變量指向函數。這正如用指針變量可指向整型變量、字符
型、數組一樣,這裏是指向函數。如前所述,C在編譯時,每一個函數都有一個
入口地址,該入口地址就是函數指針所指向的地址。有了指向函數的指針變量
後,可用該指針變量調用函數,就如同用指針變量可引用其他類型變量一樣,
在這些概念上一致的。函數指針有兩個用途:調用函數和做函數的參數。
 關於函數指針數組的定義
  關於函數指針數組的定義方法,有兩種:一種是標準的方法;一種是蒙
騙法。   
第一種,標準方法:   
{   分析:函數指針數組是一個其元素是函數指針的數組。
	那麼也就是說,此數據結構是一個數組,且其元素是一個
	指向函數入口地址的指針。   
	根據分析:首先說明是一個數組:數組名[]   
	其次,要說明其元素的數據類型指針:*數組名[].   
		再次,要明確這每一個數組元素是指向函數入口地址
		的指針:函數返回值類型 (*數組名[])().請注意,
		這裏爲什麼要把“*數組名[]”用括號擴起來呢?
		因爲圓括號和數組說明符的優先級是等同的,如果
		不用圓括號把指針數組說明表達式擴起來,根據圓括
		號和方括號的結合方向,那麼 *數組名[]() 說明的
		是什麼呢?是元素返回值類型爲指針的函數數組。
		有這樣的函數數祖嗎?不知道。所以必須括起來,
		以保證數組的每一個元素是指針。   }   
		第二種,矇騙法:   儘管函數不是變量,但它在內存
		中仍有其物理地址,該地址能夠賦給指針變量。獲取函數
		地址的方法是:用不帶有括號和參數的函數名得到。   
		函數名相當於一個指向其函數入口指針常量。 那麼既然
		函數名是一個指針常量,那麼就可以對其進行一些相應的
		處理,如強制類型轉換。   
		那麼我們就可以把這個地址放在一個整形指針數組中,
		然後作爲函數指針調用即可。   完整例子:   
		#include "stdio.h"   
		int add1(int a1,int b1);   
		int add2(int a2,int b2);   
		void main()   
		{   
			int numa1=1,numb1=2;   
			int numa2=2,numb2=3;   
			int (*op[2])(int a,int b);   
			op[0]=add1;   
			op[1]=add2;   
			printf("%d %d\n",op[0](numa1,numb1),op[1](numa2,numb2));   
			}   
			int add1(int a1,int b1)   
			{   return a1+b1;   }
			   int add2(int a2,int b2)   
			 {   return a2+b2;   }
//////////////////////////////////////////////




指針是一個特殊的變量,它裏面存儲的數值被解釋成爲內存裏
的一個地址。   
要搞清一個指針需要搞清指針的四方面的內容
:指針的類型,指針所指向的   
  類型,指針的值或者叫指針所
  指向的內存區,
  還有指針本身所佔據的內存區。讓我們分別說明。   
  先聲明幾個指針放着做例子:   
  例一:   
  (1)int*ptr;   
  (2)char*ptr;   
  (3)int**ptr;   
  (4)int(*ptr)[3];   
  (5)int*(*ptr)[4];   
   
  指針的類型 
  從語法的角度看,你只要把指針聲明語句裏的指針名字去掉,
剩下的部分就是這個指針的類型。這是指針本身所具有的類型。
讓我們看看例一中各個指針的類型:   
  (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)int*ptr;//指針所指向的類型是int   
  (2)char*ptr;//指針所指向的的類型是char   
  (3)int**ptr;//指針所指向的的類型是int*   
  (4)int(*ptr)[3];//指針所指向的的類型是int()[3]   
  (5)int*(*ptr)[4];//指針所指向的的類型是int*()[4]   
  在指針的算術運算中,指針所指向的類型有很大的作用。   
  指針的類型(即指針本身的類型)和指針所指向的類型是兩個概念
。當你對C越來越熟悉時,你會發現,把與指針攪和在一起的 "類型 "
這個概念分成 "指針的類型 "和 "指針所指向的類型
 "兩個概念,是精通指針的關鍵點之一。我看了不少書,發
現有些寫得差的書中,就把指針的這兩個概念攪在一起了,所以看
起書來前後矛盾,越看越糊塗。
指針的值,或者叫指針所指向的內存區或地址指針的值是指針本身
存儲的數值,這個值將被編譯器當作一個地址,而不是一個一般的數
值。在32位程序裏,所有類型的指針的值都是一個32位整數,因爲32
位程序裏內存地址全都是32位長。   
指針所指向的內存區就是從指針的值所代表的那個
內存地址開始,長度爲sizeof(指針所指向的類型)的一片內存區。
以後,我們說一個指針的值是XX,就相當於說該指針指
向了以XX爲首地址的一片內存區域;我們說一個指針指向了某塊內
存區域,就相當於說該指針的值是這塊內存區域的首地址。   
  指針所指向的內存區和指針所指向的類型是兩個完全不同的概
念。在例一中,指針所指向的類型已經有了,但由於指針
還未初始化,所以它所指向的內存區是不存在的,或者說是無意義的。   
  以後,每遇到一個指針,都應該問問:這個指針的類型是什麼?
指針指的類型是什麼?該指針指向了哪裏?   
  指針本身所佔據的內存區 
  指針本身佔了多大的內存?你只要用函數sizeof(指針的類型)
測一下就知道了。在32位平臺裏,指針本身佔據了4個字節
的長度。   
  指針本身佔據的內存這個概念在判斷一個指針表達式是否是左
值時很有用。   
  指針的算術運算   
指針可以加上或減去一個整數。指針的這種運算的意義和通常的數
值的加減運算的意義是不一樣的。例如:   
  例二:   
  1、char a[20];   
  2、int *ptr=a;   
  ...   
 ...   
  3、ptr++;   
  在上例中,指針ptr的類型是int*,它指向的類型是int,它被初始化爲指向整形變量a。接下來的第3句中,指針ptr
被加了1,編譯器是這樣處理的:它把指針ptr的值加上了sizeof(int),在32位程序中,是被加上了4。由於地址是用字
節做單位的,故ptr所指向的地址由原來的變量a的地址向高地址方向增加了4個字節。   
由於char類型的長度是一個字節,所以,原來ptr是指向數組a的第0號單元開始的四個字節,此時指向了數組a中從第4
號單元開始的四個字節。   
  我們可以用一個指針和一個循環來遍歷一個數組,看例子: 
  例三:   
intarray[20];   
int*ptr=array;   
...   
//此處略去爲整型數組賦值的代碼。   
...   
for(i=0;i <20;i++)   
{   
 (*ptr)++;   
 ptr++;   
} 
  這個例子將整型數組中各個單元的值加1。由於每次循環都將指針ptr加1,所以每次循環都能訪問數組的下一個單元。   

  再看例子:   

  例四:   

  1、chara[20];   
  2、int*ptr=a;   
  ...   
  ...   
  3、ptr+=5; 
  在這個例子中,ptr被加上了5,編譯器是這樣處理的:將指針ptr的值加上5乘sizeof(int),在32位程序中就是加上
了5乘4=20。由於地址的單位是字節,故現在的ptr所指向的地址比起加5後的ptr所指向的地址來說,向高地址方向移動了
20個字節。在這個例子中,沒加5前的ptr指向數組a的第0號單元開始的四個字節,加5後,ptr已經指向了數組a的合法範
圍之外了。雖然這種情況在應用上會出問題,但在語法上卻是可以的。這也體現出了指針的靈活性。
如果上例中,ptr是被減去5,那麼處理過程大同小異,只不過ptr的值是被減去5乘sizeof(int),新的ptr指向的地址將比原來的ptr所指向的地址向低地址方向移動了20個字節。   
  總結一下,一個指針ptrold加上一個整數n後,結果是一個新的指針ptrnew,ptrnew的類型和ptrold的類型相同,ptrnew所指向的類型和ptrold所指向的類型也相同。ptrnew的值將比ptrold的值增加了n乘sizeof(ptrold所指向的類型)個字節。就是說,ptrnew所指向的內存區將比ptrold所指向的內存區向高地址方向移動了n乘sizeof(ptrold所指向的類型)個字節。   
  一個指針ptrold減去一個整數n後,結果是一個新的指針ptrnew,ptrnew的類型和ptrold的類型相同,ptrnew所指向的類型和ptrold所指向的類型也相同。ptrnew的值將比ptrold的值減少了n乘sizeof(ptrold所指向的類型)個字節,就是說,ptrnew所指向的內存區將比ptrold所指向的內存區向低地址方向移動了n乘sizeof(ptrold所指向的類型)個字節。   
運算符&和*   
這裏&是取地址運算符,*是...書上叫做 "間接運算符 "。   
  &a的運算結果是一個指針,指針的類型是a的類型加個*,指針所指向的類型是a的類型,指針所指向的地址嘛,那就是a的地址。   
  *p的運算結果就五花八門了。總之*p的結果是p所指向的東西,這個東西有這些特點:它的類型是p指向的類型,它所佔用的地址是p所指向的地址。   
  例五:   
inta=12;   
intb;   
int*p; 
int**ptr;   
p=&a; 
//&a的結果是一個指針,類型是int*,指向的類型是int,指向的地址是a的地址。   
*p=24; 
//*p的結果,在這裏它的類型是int,它所佔用的地址是p所指向的地址,顯然,*p就是變量a。   
ptr=&p; 
//&p的結果是個指針,該指針的類型是p的類型加個*,在這裏是int   **。該指針所指向的類型是p的類型,這裏是int*。該指針所指向的地址就是指針p自己的地址。   
*ptr=&b; 
//*ptr是個指針,&b的結果也是個指針,且這兩個指針的類型和所指向的類型是一樣的,所以用&b來給*ptr賦值就是毫無問題的了。   
**ptr=34; 
//*ptr的結果是ptr所指向的東西,在這裏是一個指針,對這個指針再做一次*運算,結果就是一個int類型的變量。 
  指針表達式   
一個表達式的最後結果如果是一個指針,那麼這個表達式就叫指針表式。   
  下面是一些指針表達式的例子:   
  例六:   
inta,b;   
intarray[10];   
int*pa;   
pa=&a;//&a是一個指針表達式。   
int**ptr=&pa;//&pa也是一個指針表達式。   
*ptr=&b;//*ptr和&b都是指針表達式。   
pa=array;   
pa++;//這也是指針表達式。 
例七:   
char*arr[20];   
char**parr=arr;//如果把arr看作指針的話,arr也是指針表達式   
char*str;   
str=*parr;//*parr是指針表達式   
str=*(parr+1);//*(parr+1)是指針表達式   
str=*(parr+2);//*(parr+2)是指針表達式 
  由於指針表達式的結果是一個指針,所以指針表達式也具有指針所具有的四個要素:指針的類型,指針所指向的類型,指針指向的內存區,指針自身佔據的內存。 

  好了,當一個指針表達式的結果指針已經明確地具有了指針自身佔據的內存的話,這個指針表達式就是一個左值,否則就不是一個左值。   
  在例七中,&a不是一個左值,因爲它還沒有佔據明確的內存。*ptr是一個左值,因爲*ptr這個指針已經佔據了內存,其實*ptr就是指針pa,既然pa已經在內存中有了自己的位置,那麼*ptr當然也有了自己的位置。   
  數組和指針的關係   
  數組的數組名其實可以看作一個指針。看下例:   
  例八:   
intarray[10]={0,1,2,3,4,5,6,7,8,9},value;   
...   
...   
value=array[0];//也可寫成:value=*array;   
value=array[3];//也可寫成:value=*(array+3);   
value=array[4];//也可寫成:value=*(array+4); 
上例中,一般而言數組名array代表數組本身,類型是int[10],但如果把array看做指針的話,它指向數組的第0個單元,類型是int*,所指向的類型是數組單元的類型即int。因此*array等於0就一點也不奇怪了。同理,array+3是一個指向數組第3個單元的指針,所以*(array+3)等於3。其它依此類推。   

  例九:   
char*str[3]={   
  "Hello,thisisasample! ",   
  "Hi,goodmorning. ",   
  "Helloworld "   
};   
chars[80];   
strcpy(s,str[0]);//也可寫成strcpy(s,*str);   
strcpy(s,str[1]);//也可寫成strcpy(s,*(str+1));   
strcpy(s,str[2]);//也可寫成strcpy(s,*(str+2)); 
上例中,str是一個三單元的數組,該數組的每個單元都是一個指針,這些指針各指向一個字符串。把指針數組名str當作一個指針的話,它指向數組的第0號單元,它的類型是char**,它指向的類型是char*。   
*str也是一個指針,它的類型是char*,它所指向的類型是char,它指向的地址是字符串 "Hello,thisisasample! "的第一個字符的地址,即 'H '的地址。   str+1也是一個指針,它指向數組的第1號單元,它的類型是char**,它指向的類型是char*。   

  *(str+1)也是一個指針,它的類型是char*,它所指向的類型是char,它指向   "Hi,goodmorning. "的第一個字符 'H ',等等。   

  下面總結一下數組的數組名的問題。聲明瞭一個數組TYPEarray[n],則數組名稱array就有了兩重含義:第一,它代表整個數組,它的類型是TYPE[n];第二   ,它是一個指針,該指針的類型是TYPE*,該指針指向的類型是TYPE,也就是數組單元的類型,該指針指向的內存區就是數組第0號單元,該指針自己佔有單獨的內存區,注意它和數組第0號單元佔據的內存區是不同的。該指針的值是不能修改的,即類似array++的表達式是錯誤的。   
  在不同的表達式中數組名array可以扮演不同的角色。   
  在表達式sizeof(array)中,數組名array代表數組本身,故這時sizeof函數測出的是整個數組的大小。   
在表達式*array中,array扮演的是指針,因此這個表達式的結果就是數組第0號單元的值。sizeof(*array)測出的是數組單元的大小。   
  表達式array+n(其中n=0,1,2,....?┲校琣rray扮演的是指針,故array+n的結果是一個指針,它的類型是TYPE*,它指向的類型是TYPE,它指向數組第n號單元。故sizeof(array+n)測出的是指針類型的大小。   
例十 
intarray[10];   
int(*ptr)[10];   
ptr=&array;:   
上例中ptr是一個指針,它的類型是int(*)[10],他指向的類型是int[10]   ,我們用整個數組的首地址來初始化它。在語句ptr=&array中,array代表數組本身。   

  本節中提到了函數sizeof(),那麼我來問一問,sizeof(指針名稱)測出的究竟是指針自身類型的大小呢還是指針所指向的類型的大小?答案是前者。例如:   
int(*ptr)[10];   
  則在32位程序中,有:   
sizeof(int(*)[10])==4   
sizeof(int[10])==40   
sizeof(ptr)==4 
實際上,sizeof(對象)測出的都是對象自身的類型的大小,而不是別的什麼類型的大小。 
指針和結構類型的關係   
可以聲明一個指向結構類型對象的指針。   
  例十一:   
structMyStruct   
{   
 inta;   
 intb;   
 intc;   
}   
MyStructss={20,30,40}; 
//聲明瞭結構對象ss,並把ss的三個成員初始化爲20,30和40。   
MyStruct*ptr=&ss; 
//聲明瞭一個指向結構對象ss的指針。它的類型是MyStruct*,它指向的類型是MyStruct。   
int*pstr=(int*)&ss; 
//聲明瞭一個指向結構對象ss的指針。但是它的類型和它指向的類型和ptr是不同的。 
  請問怎樣通過指針ptr來訪問ss的三個成員變量?   
  答案:   
ptr-> a;   
ptr-> b;   
ptr-> c;   
  又請問怎樣通過指針pstr來訪問ss的三個成員變量?   
  答案:   
*pstr;//訪問了ss的成員a。   
*(pstr+1);//訪問了ss的成員b。   
*(pstr+2)//訪問了ss的成員c。   
  雖然我在我的MSVC++6.0上調式過上述代碼,但是要知道,這樣使用pstr來訪問結構成員是不正規的,爲了說明爲什麼不正規,讓我們看看怎樣通過指針來訪問數組的各個單元:   
  例十二:   
intarray[3]={35,56,37};   
int*pa=array;   
  通過指針pa訪問數組array的三個單元的方法是:   
*pa;//訪問了第0號單元   
*(pa+1);//訪問了第1號單元   
*(pa+2);//訪問了第2號單元   
從格式上看倒是與通過指針訪問結構成員的不正規方法的格式一樣。   
  所有的C/C++編譯器在排列數組的單元時,總是把各個數組單元存放在連續的存儲區裏,單元和單元之間沒有空隙。但在存放結構對象的各個成員時,在某種編譯環境下,可能會需要字對齊或雙字對齊或者是別的什麼對齊,需要在相鄰兩個成員之間加若干個 "填充字節 ",這就導致各個成員之間可能會有若干個字節的空隙。   
  所以,在例十二中,即使*pstr訪問到了結構對象ss的第一個成員變量a,也不能保證*(pstr+1)就一定能訪問到結構成員b。因爲成員a和成員b之間可能會有若干填充字節,說不定*(pstr+1)就正好訪問到了這些填充字節呢。這也證明了指針的靈活性。要是你的目的就是想看看各個結構成員之間到底有沒有填充字節,嘿,這倒是個不錯的方法。   
過指針訪問結構成員的正確方法應該是象例十二中使用指針ptr的方法。   
  指針和函數的關係   
  可以把一個指針聲明成爲一個指向函數的指針。intfun1(char*,int);   
int(*pfun1)(char*,int);   
pfun1=fun1;   
....   
....   
inta=(*pfun1)( "abcdefg ",7);//通過函數指針調用函數。   
可以把指針作爲函數的形參。在函數調用語句中,可以用指針表達式來作爲實參。   
  例十三:   
intfun(char*);   
inta;   
charstr[]= "abcdefghijklmn ";   
a=fun(str);   
...   
...   
intfun(char*s)   
{   
intnum=0;   
for(inti=0;i{   
num+=*s;s++;   
}   
returnnum; 
} 
  這個例子中的函數fun統計一個字符串中各個字符的ASCII碼值之和。前面說了,數組的名字也是一個指針。在函數調用中,當把str作爲實參傳遞給形參s後,實際是把str的值傳遞給了s,s所指向的地址就和str所指向的地址一致,但是str和s各自佔用各自的存儲空間。在函數體內對s進行自加1運算,並不意味着同時對str進行了自加1運算。 
指針類型轉換   
當我們初始化一個指針或給一個指針賦值時,賦值號的左邊是一個指針,賦值號的右邊是一個指針表達式。在我們前面所舉的例子中,絕大多數情況下,指針的類型和指針表達式的類型是一樣的,指針所指向的類型和指針表達式所指向的類型是一樣的。   
  例十四:   
  1、floatf=12.3;   
  2、float*fptr=&f;   
  3、int*p;   
   在上面的例子中,假如我們想讓指針p指向實數f,應該怎麼搞?是用下面的語句嗎?   

  p=&f;   

  不對。因爲指針p的類型是int*,它指向的類型是int。表達式&f的結果是一個指針,指針的類型是float*,它指向的類型是float。兩者不一致,直接賦值的方法是不行的。至少在我的MSVC++6.0上,對指針的賦值語句要求賦值號兩邊的類型一致,所指向的類型也一致,其它的編譯器上我沒試過,大家可以試試。爲了實現我們的目的,需要進行 "強制類型轉換 ":   
p=(int*)&f; 
如果有一個指針p,我們需要把它的類型和所指向的類型改爲TYEP*TYPE,   那麼語法格式是:   
  (TYPE*)p;   
  這樣強制類型轉換的結果是一個新指針,該新指針的類型是TYPE*,它指向的類型是TYPE,它指向的地址就是原指針指向的地址。而原來的指針p的一切屬性都沒有被修改。   
  一個函數如果使用了指針作爲形參,那麼在函數調用語句的實參和形參的結合過程中,也會發生指針類型的轉換。   
  例十五: 
voidfun(char*);   
inta=125,b;   
fun((char*)&a);   
...   
...   
voidfun(char*s)   
{   
charc;   
c=*(s+3);*(s+3)=*(s+0);*(s+0)=c;   
c=*(s+2);*(s+2)=*(s+1);*(s+1)=c;   
}   
}   
注意這是一個32位程序,故int類型佔了四個字節,char類型佔一個字節。函數fun的作用是把一個整數的四個字節的順序來個顛倒。注意到了嗎?在函數調用語句中,實參&a的結果是一個指針,它的類型是int*,它指向的類型是int。形參這個指針的類型是char*,它指向的類型是char。這樣,在實參和形參的結合過程中,我們必須進行一次從int*類型到char*類型的轉換。結合這個例子,我們可以這樣來想象編譯器進行轉換的過程:編譯器先構造一個臨時指針char*temp,   然後執行temp=(char*)&a,最後再把temp的值傳遞給s。所以最後的結果是:s的類型是char*,它指向的類型是char,它指向的地址就是a的首地址。   

  我們已經知道,指針的值就是指針指向的地址,在32位程序中,指針的值其實是一個32位整數。那可不可以把一個整數當作指針的值直接賦給指針呢?就象下面的語句: 
unsignedinta;   
TYPE*ptr;//TYPE是int,char或結構類型等等類型。   
...   
...   
a=20345686;   
ptr=20345686;//我們的目的是要使指針ptr指向地址20345686(十進制   
)   
ptr=a;//我們的目的是要使指針ptr指向地址20345686(十進制) 
編譯一下吧。結果發現後面兩條語句全是錯的。那麼我們的目的就不能達到了嗎?不,還有辦法:   
unsignedinta;   
TYPE*ptr;//TYPE是int,char或結構類型等等類型。   
...   
...   
a=某個數,這個數必須代表一個合法的地址;   
ptr=(TYPE*)a;//呵呵,這就可以了。 
嚴格說來這裏的(TYPE*)和指針類型轉換中的(TYPE*)還不一樣。這裏的(TYPE*)的意思是把無符號整數a的值當作一個地址來看待。上面強調了a的值必須代表一個合法的地址,否則的話,在你使用ptr的時候,就會出現非法操作錯誤。   

  想想能不能反過來,把指針指向的地址即指針的值當作一個整數取出來。完   全可以。下面的例子演示了把一個指針的值當作一個整數取出來,然後再把這個整數當作一個地址賦給一個指針:   
  例十六:   
inta=123,b;   
int*ptr=&a;   
char*str;   
b=(int)ptr;//把指針ptr的值當作一個整數取出來。   
str=(char*)b;//把這個整數的值當作一個地址賦給指針str。 
  現在我們已經知道了,可以把指針的值當作一個整數取出來,也可以把一個整數值當作地址賦給一個指針。   
  指針的安全問題   
看下面的例子:   
  例十七: 
chars= 'a ';   
int*ptr;   
ptr=(int*)&s;   
*ptr=1298;   
  指針ptr是一個int*類型的指針,它指向的類型是int。它指向的地址就是s的首地址。在32位程序中,s佔一個字節,int類型佔四個字節。最後一條語句不但改變了s所佔的一個字節,還把和s相臨的高地址方向的三個字節也改變了。這三個字節是幹什麼的?只有編譯程序知道,而寫程序的人是不太可能知道的。也許這三個字節裏存儲了非常重要的數據,也許這三個字節里正好是程序的一條代碼,而由於你對指針的馬虎應用,這三個字節的值被改變了!這會造成崩潰性的錯誤。   
  讓我們再來看一例:   
  例十八:   
  1、chara;   
  2、int*ptr=&a;   
  ...   
  ...   
  3、ptr++;   
  4、*ptr=115;   
  該例子完全可以通過編譯,並能執行。但是看到沒有?第3句對指針ptr進行自加1運算後,ptr指向了和整形變量a相鄰的高地址方向的一塊存儲區。這塊存儲區裏是什麼?我們不知道。有可能它是一個非常重要的數據,甚至可能是一條代碼。而第4句竟然往這片存儲區裏寫入一個數據!這是嚴重的錯誤。所以在使用指針時,程序員心裏必須非常清楚:我的指針究竟指向了哪裏。在用指針訪問數組的時候,也要注意不要超出數組的低端和高端界限,否則也會造成類似的錯誤。   
  在指針的強制類型轉換:ptr1=(TYPE*)ptr2中,如果sizeof(ptr2的類型)大於sizeof(ptr1的類型),那麼在使用指針ptr1來訪問ptr2所指向的存儲區時是安全的。如果sizeof(ptr2的類型)小於sizeof(ptr1的類型),那麼在使用指針ptr1來訪問ptr2所指向的存儲區時是不安全的。至於爲什麼,讀者結合例十七來想一想,應該會明白的。


摘錄的別人的: 

C語言所有複雜的指針聲明,都是由各種聲明嵌套構成的。如何解讀複雜指針聲明呢?右左法則是一個既著名又常用的方法。不過,右左法則其實並不是C標準裏面的內容,它是從C標準的聲明規定中歸納出來的方法。C標準的聲明規則,是用來解決如何創建聲明的,而右左法則是用來解決如何辯識一個聲明的,兩者可以說是相反的。右左法則的英文原文是這樣說的: 

The   right-left   rule:   Start   reading   the   declaration   from   the   innermost   parentheses,   go   right,   and   then   go   left.   When   you   encounter   parentheses,   the   direction   should   be   reversed.   Once   everything   in   the   parentheses   has   been   parsed,   jump   out   of   it.   Continue   till   the   whole   declaration   has   been   parsed.   


這段英文的翻譯如下: 

右左法則:首先從最裏面的圓括號看起,然後往右看,再往左看。每當遇到圓括號時,就應該掉轉閱讀方向。一旦解析完圓括號裏面所有的東西,就跳出圓括號。重複這個過程直到整個聲明解析完畢。 

                筆者要對這個法則進行一個小小的修正,應該是從未定義的標識符開始閱讀,而不是從括號讀起,之所以是未定義的標識符,是因爲一個聲明裏面可能有多個標識符,但未定義的標識符只會有一個。 

                現在通過一些例子來討論右左法則的應用,先從最簡單的開始,逐步加深: 

int   (*func)(int   *p); 

首先找到那個未定義的標識符,就是func,它的外面有一對圓括號,而且左邊是一個*號,這說明func是一個指針,然後跳出這個圓括號,先看右邊,也是一個圓括號,這說明(*func)是一個函數,而func是一個指向這類函數的指針,就是一個函數指針,這類函數具有int*類型的形參,返回值類型是int。 

int   (*func)(int   *p,   int   (*f)(int*)); 

func被一對括號包含,且左邊有一個*號,說明func是一個指針,跳出括號,右邊也有個括號,那麼func是一個指向函數的指針,這類函數具有int   *和int   (*)(int*)這樣的形參,返回值爲int類型。再來看一看func的形參int   (*f)(int*),類似前面的解釋,f也是一個函數指針,指向的函數具有int*類型的形參,返回值爲int。 

int   (*func[5])(int   *p); 

func右邊是一個[]運算符,說明func是一個具有5個元素的數組,func的左邊有一個*,說明func的元素是指針,要注意這裏的*不是修飾func的,而是修飾func[5]的,原因是[]運算符優先級比*高,func先跟[]結合,因此*修飾的是func[5]。跳出這個括號,看右邊,也是一對圓括號,說明func數組的元素是函數類型的指針,它所指向的函數具有int*類型的形參,返回值類型爲int。 


int   (*(*func)[5])(int   *p); 

func被一個圓括號包含,左邊又有一個*,那麼func是一個指針,跳出括號,右邊是一個[]運算符號,說明func是一個指向數組的指針,現在往左看,左邊有一個*號,說明這個數組的元素是指針,再跳出括號,右邊又有一個括號,說明這個數組的元素是指向函數的指針。總結一下,就是:func是一個指向數組的指針,這個數組的元素是函數指針,這些指針指向具有int*形參,返回值爲int類型的函數。 

int   (*(*func)(int   *p))[5]; 

func是一個函數指針,這類函數具有int*類型的形參,返回值是指向數組的指針,所指向的數組的元素是具有5個int元素的數組。 

要注意有些複雜指針聲明是非法的,例如: 

int   func(void)   [5]; 

func是一個返回值爲具有5個int元素的數組的函數。但C語言的函數返回值不能爲數組,這是因爲如果允許函數返回值爲數組,那麼接收這個數組的內容的東西,也必須是一個數組,但C語言的數組名是一個右值,它不能作爲左值來接收另一個數組,因此函數返回值不能爲數組。 

int   func[5](void); 

func是一個具有5個元素的數組,這個數組的元素都是函數。這也是非法的,因爲數組的元素除了類型必須一樣外,每個元素所佔用的內存空間也必須相同,顯然函數是無法達到這個要求的,即使函數的類型一樣,但函數所佔用的空間通常是不相同的。 

作爲練習,下面列幾個複雜指針聲明給讀者自己來解析,答案放在第十章裏。 

int   (*(*func)[5][6])[7][8]; 

int   (*(*(*func)(int   *))[5])(int   *); 

int   (*(*func[7][8][9])(int*))[5]; 

                實際當中,需要聲明一個複雜指針時,如果把整個聲明寫成上面所示的形式,對程序可讀性是一大損害。應該用typedef來對聲明逐層分解,增強可讀性,例如對於聲明: 

int   (*(*func)(int   *p))[5]; 

可以這樣分解: 

typedef     int   (*PARA)[5]; 
typedef   PARA   (*func)(int   *); 

這樣就容易看得多了。
	



 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章