1. 程式人生 > >指針數組、數組指針、函數指針、指針函數總結

指針數組、數組指針、函數指針、指針函數總結

col 回調函數 分享 類型 blue 不同的 art func pos

指針數組 && 數組指針

char *a[5];      
//定義一個指針數組, 數組的元素都是char *指針類型。初始化也能夠在裏面存放字符或字符串。a的類型是char *[5]
//若char *a[5]={"red","white","blue","dark","green"};
//a在這裏的類型是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同樣。

從上面我們能夠看到char (*)[]、 char [][]、char **事實上能夠看成是等價的

#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;

}
@1 定義指針數組,組中元素均為char *類型

@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 *))傳遞不同的函數指針,通過同一接口實現對不同類型數據的比較。


指針函數,指針函數是指帶指針的函數。即本質是一個函數。函數都有返回類型(假設沒有返回值,則為無值型),僅僅只是指針函數返回類型是某一類型的指針。

指針數組、數組指針、函數指針、指針函數總結