指針數組、數組指針、函數指針、指針函數總結
指針數組 && 數組指針
char *a[5]; //定義一個指針數組, 數組的元素都是char *指針類型。初始化也能夠在裏面存放字符或字符串。a的類型是char *[5] //若char *a[5]={"red","white","blue","dark","green"}; //a在這裏的類型是char *[],實質上是一個二級指針。從上面我們能夠看到char (*)[]、 char [][]、char **事實上能夠看成是等價的也就是說a所代表的那塊內存裏面存放著的是數組中第一個元素的地址。 //a+1所代表的那塊內存裏面存放著的是數組中第二個元素的地址,依此類推…… //a[0]就是“red”字符串的地址,printf("%s",a[0]); //a[0]+1,表示在"red"字符串的地址上偏移一個位置。訪問字符'c'.printf("%c",*(a[0]+1)) //若a的地址是0x0000000。則a+1的地址是0x00000008(64位平臺)或0x00000004; int (*ptr)[5]; //定義一個指向數組的數組指針ptr,它的實際類型為char (*)[5],(數字能夠忽略)由於在有些嚴格的編譯器中不同一時候會提出警告 再定義一個二維數組int a[1][5]={1,2,3,4,5}; //a的類型為int [1][5](數字能夠忽略),列的維度同樣。p=a能夠賦值。
也就是說此時數組指針ptr能夠看做一個二級指針,它的使用方法跟char **a同樣。
#include <stdio.h> int main(void) { char *a[5]={"red","white","blue","dark","green"}; printf("%s %c %s\n", a[0], *(a[0]+1), a[1]+1); printf("%x %x\n",a[0], a[1]); char m[2][5]={"xxx", "yyyy"}; char (*ptr)[5]=m; printf("%x %s %s %x %s\n", ptr[0], ptr, ptr[1], ptr[0]+2, ptr[0]+1); printf("%d ",sizeof(a)); printf("%d ",sizeof(m)); return 0; }
@2 定義數組指針,ptr類型為char (*)[]。m類型為char [][]。這兩類型間是能夠賦值的。
但他們不是全然等價的。
@3 a的類型為char*[5],sizeof(a)=sizeof(char *)*5;
m的類型為char [][]的二維數組。sizeof(m)求得它在內存中實際所占字節,有些編譯器出於效率考慮會對字節進行對齊。
執行結果例如以下
常見誤區
double n =2.0, *pt=&n; printf("double %d %d\n", pt, pt+1);//差為8 char c='m', *q=&c; printf("char %d %d\n", q, q+1);//差為1 char **p=&q; printf("%d %d",p ,p+1);//差為4 printf("%d %d %d",sizeof(int*), sizeof(double*), sizeof(char*), sizeof(int**));
函數指針 && 指針函數
函數指針和其他指針一樣,對函數指針運行間接訪問之前必須把它初始化為指向某個函數。
以下是一種初始化函數指針的方法:
int fun( int );
int ( * pf ) ( int ) = &fun;
創建函數指針pf並將其指向函數fun。
在函數指針的初始化之前具有fun的原型是非常重要的,否則編譯器無法檢查fun的類型與pf所指向的類型一致。
初始化聲明後,我們能夠有下面三種方式調用函數:
int ans;
1) ans = fun( 25 );
2) ans = ( *pf ) ( 25 );
3) ans = pf ( 25 );
語句1簡單的使用名字調用函數fun。但它的運行過程可能跟你想的不一樣:函數名fun首先被轉換為一個函數指針,該指針指向內存中的一塊位置。然後,函數調用操作符調用函數,運行開始於這個地址的代碼。
語句2對pf運行間接訪問操作,將pf轉換為函數名。
但這樣的轉換事實上是不必要的,編譯器在運行函數調用操作符之前又會把它轉換回去。
語句3和前兩條運行效果一樣的。
函數指針的常見用途就是把函數指針作為參數傳遞給函數。以下是樣例。
#include <stdio.h> #include <string.h> int compare_int(void const *a, void const *b) { if( *(int *)a == *(int *)b) return 0; else return 1; } int compare_char(void const *a, void const *b) { if(strcmp ((char *)a, (char *)b) == 0) return 0; else return 1; } void Compare(void const *a, void const *b,int (*compare)(void const *, void const *)) { if(compare(a, b) == 0) printf("they are equal\n"); else printf("not equal\n"); } int main(void) { int m=4,n=5; Compare(&m, &n, compare_int); char a[4]="abc",b[4]="abc"; Compare(a, b, compare_char); }
執行結果:
使用以上技巧的函數被稱為回調函數(callback function)。用戶將一個函數指針作為參數傳遞給其他函數。後者將“回調”用戶的函數。分別為比較整型與字符串編寫不同的比較函數compar_int(void const *,void const *)和compar_char(void const *,void const *)。通過向Compare(const void *,const void *,int (*compare)(void const *, void const *))傳遞不同的函數指針,通過同一接口實現對不同類型數據的比較。
指針數組、數組指針、函數指針、指針函數總結