void main()//關於指針的擴展理解
{
int ar[10] = {};//ar時整型數組
int a = 1;
int b = 2;
int c = 3;
int *br[10] = { &a, &b, &c };//br不是指針而是一個存放地址的數組
int(*cr)[10]=&ar;//cr是一個存放數組的首指針,cr後面括號的值必須和所存放數組的 大小一樣,這是cr+1時,會移動整個數組大小,它的識別能力爲整個數組
//int(*xr) = &br;這樣無法編譯通過,因爲在這條語句中xr是一個存放整型數組的指 針,然而br是一個存放地址的數組,所以類型不同
int *(xr)[10]=&br;//xr也是一個指向數組的首地址,但是xr所指的數組是存放地址的
//同理,當qr要指向br時需要加
int *(&qr)[10] = br;
int(&qr)[10] = ar;//引用
//int &cr[10] 這樣的寫法是錯誤的,因爲引用是不開闢空間的,然而給的方括號中10,又讓系統去開闢空間,造成了矛盾
//同理 int &(&cr)[10]自然也無法通過編譯
}
下面是函數指針的介紹
int Add(int x, int y)
{
return x + y;
}
int dis(int x, int y)
{
return x - y;
}
int *App(int x,int y)
{
int z = x + y;
return &z;
}
void printdis(int x, int y, int(*pfun)(int, int))//printdis(int x, int y, int pfun(int, int)),這樣也是正確的,當函數的聲明在形參時,是當做函數指針使用的
{
if (pfun != NULL)
{
int z = (*pfun)(x, y);
cout << z;
}
}
void main2()
{
int pfub(int, int);//是函數聲明
int(*pfun)(int, int);//pfun是一個指針,而最前面的int表示所調用函數的返回類型
int *(*pfum)(int, int);//同理int *知識表示調用函數的類型,(*pfun)表示pfun是一個指針
//上面兩種方式是定義函數指針的唯一方式
int(*pfun)(int, int) = NULL;//是將pfun的值賦爲NULL,而不是將函數的值賦值爲NULL;
pfun = Add;//表示將add函數的地址賦值給pfun
int x = 1;
int y = 2;
int z;
int z = (*pfun)(x,y);
pfum = App;
int *p;
p = (*pfum)(x, y);
sizeof(pfun);//結果爲4,就是指針的大小
//sizeof(*pfun)是無法計算的,因爲無法計算出函數的大小
//同理函數指針pfun+=1也是無法進行的,因爲無法計算函數的大小所以也無法用過+1來跳到下一個函數;
printdis(x, y, Add);//這就是函數指針的調用方式,至於函數指針的定義是在printdis函數中進行的
}
//下面的函數內容是使用一個指針,將多個類型的數組進行輸出,qsort,bsearch
struct Student
{
char s_id[20];
char s_name[20];
char s_sex;
int s_age;
};
void * PrintInt(void *p)
{
int *s = (int*)p;
printf("%d \n", *s);
return s + 1;
}
void * PrintDouble(void *p)
{
double *s = (double*)p;
printf("%f \n", *s);
return s + 1;
}
void * PrintStudent(void *p)
{
Student *s = (Student *)p;
printf("%s ", s->s_id);
printf("%s ", s->s_name);
printf("%c ", s->s_sex);
printf("%d \n", s->s_age);
return s + 1;
}
void PrintArray(void *ar, int n, void * (*pfun)(void*))
{
if (ar == NULL || n < 1 || pfun == NULL)
return;
for (int i = 0; i<n; ++i)
{
ar = pfun(ar);
}
printf("\n");
}
struct node{
int(*p)(int);
void(*q)(double);
};
int app(int){}
void diss(double){}
int main3()
{
int ar[] = { 12, 23, 34, 45, 56, 67, 78, 90 };
int arlen = sizeof(ar) / sizeof(ar[0]);
double dr[] = { 1.2, 2.3, 3.4, 5.6, 7.8 };
int drlen = sizeof(dr) / sizeof(dr[0]);
Student sr[] = { "201901001", "yhping", 'm', 23,
"201901002", "lilingjie", 'f', 15,
"201901003", "zhanghuan", 'f', 18
};
int studlen = sizeof(sr) / sizeof(sr[0]);
PrintArray(ar, arlen, PrintInt);
PrintArray(dr, drlen, PrintDouble);
PrintArray(sr, studlen, PrintStudent);
int x = 1, y = 2;
int(*pfunm[2])(int, int) = { Add, dis };//用數組的方式來使用函數指針,(*pfunm[2])中的pfunm是一個存放地址的數組不是指針
node n = { app, diss };
int di; //但是使用數組存放函數指針是必須要求每個函數的類型相同
cin >> di; //但是爲了是解決這個難題,可以使用結構體來初始化
switch (di)
{
case 0:
cout<<(*pfunm[0])(x, y); break;
case 1:
cout<<(*pfunm[1])(x, y); break;
default:break;
}
return 0;
//如果給出了函數的地址,需要我們調用函數,這是我們需要先將地址給強轉爲函數指針類型,再調用函數
//比如地址爲0x00412db0
//調用的方式爲int z = (*(int(*)(int,int)0x00412db0)(x,y)
typedef int(*gun)(int, int);//這是類型聲明,不是宏替換,這是gun就是函數指針類型
#define sun int*
sun a, b;//相當於int *a,*b
typedef int *sum;
sum a, b;//也相當於 int *a,*b
//在typedef中*sum就已經說明了他爲指針類型,然後經過typedef後確定了他是一個int類型的指針類型
//所以typedef的意義和#define是不同的
}
舉一個例題
要求數組指針向下移動,在從數組裏面向下移動,輸出ar2中的第三個
在這要說明的數組的地址和數組的首元素地址的值是一樣的,但是意義不同
在數組的地址前加*號就變爲了數組的首元素地址如&ar0是數組的地址,
*&ar就變爲了數組首元素的地址
int ar0[4];
int ar1[4];
int ar2[4] = { 1, 2, 4, 5 };
int(*s)[4] = &ar0;
s += 2;
cout<<*(*s+2);
//也可寫作
cout<<*(*(s+2)+2);
cout<<*(s[2]+2);
cout<<s[2][2];