目录
指针初阶
字符指针
指针数组
数组指针
&数组名和数组名
关于数组代码含义
数组参数与指针参数
一维数组传参
二维数组传参
一级指针传参
二级指针传参
函数指针
函数指针数组
指向函数指针数组的指针
回调函数
指针初阶
字符指针
char* 一般使用
#includevoid main() { char* ps = "hello bit";//本质上把字符串首字符的地址存入ps指针 char arr[] = "hello bit";//本质上把字符串放入数组arr里,但是arr数组名表示首元素地址 printf("%cn", *ps);//h printf("%cn", *arr);//h //给起始位置的地址就可以打印出来,因为以字符串形式打印,所以会从后面找“ ” printf("%sn", arr); printf("%sn", ps); }
#includevoid main() { char str1[] = "hello bit";//数组1 char str2[] = "hello bit";//数组2 *str1 = 'p'; printf("%sn", str1);//可以更改 //下面的字符串为常量字符串在内存中仅存一份并且不可被更改 char* str3 = "hello bit"; char* str4 = "hello bit"; //*str3 = 'p'; //printf("%sn", str3);//不可更改 printf("%pn", str1);//0019F88C printf("%pn", str2);//0019F878 //下面地址与上面两个地址各不相同,独立出一个空间,为常量字符串地址 printf("%pn", str3);//00257B30 printf("%pn", str4);//00257B30 }
指针数组
定义:存放指针的数组
#includevoid main() { int a = 10, b = 20, c = 30; int* arr1[3] = { &a,&b,&c };//存放整形指针的数组 int i = 0; for (i = 0; i < 3; i++) { printf("%dn", *(arr1[i]));//*(arr1[i])也可以写成*(*(arr1+i)) } }
#includevoid main() { int a[] = { 1,2,3,4,5 }; int b[] = { 2,3,4,5,6 }; int c[] = { 3,4,5,6,7 }; int* arr[] = {a,b,c}; int i = 0; for (i = 0; i < 3; i++) { int j = 0; for (j = 0; j < 5; j++) { printf("%d ", *(arr[i] + j));//*(arr[i] + j)也可以写成arr[i][j] } printf("n"); } }
arr[i]等价于:*(arr+i)
数组指针
整形指针:指向整形的指针
字符指针:指向字符的指针
数组指针:指向数组的指针
#includevoid main() { int arr[] = { 1,2,3,4,5 }; //arr:数组首元素的地址——arr[0]的地址 //&arr:整个数组的地址 int(*parr)[10] = &arr;//parr就是一个数组指针,存放的是数组的地址 double* d[5];//指针数组 double* (*p)[5] = &d;//指针数组的数组指针 }
&数组名和数组名
#include
void main() {
int arr[10] = { 0 };
int* p1 = arr;
int (*p2)[10] = &arr;
printf("%pn", arr);
printf("%pn", &arr);
printf("%pn", arr+1);//地址比上面多4字节
printf("%pn", &arr+1);//地址比上面多40字节
//由此观之,数组地址的步长为数组首元素地址步长的元素个数倍
}
#include
void main() {
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int(*p)[10] = &arr;
int i = 0;
for (i = 0; i < 10; i++) {
printf("%d ", *((*p) + i));//p是整个数组的地址,*p代表arr
}
}
注意:数组名表示首元素的地址,二维数组的首元素是第一行,也就是第一行一维数组的地址也就是一位数组的指针
#includeprint(int(*p)[5], int r, int c) { int i = 0, j = 0; for (i = 0; i < r; i++) { for (j = 0; j < c; j++) { printf("%d ", *(*(p + i) + j)); //p+i——i+1行数组的地址,*(p+i)——i+1行的数组,*(p+i)+j——i+1行数组第j+1行元素的地址,*(*(p + i) + j)——i+1行数组第j+1行元素 } printf("n"); } } void main() { int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} }; print(arr, 3, 5); }
关于数组代码含义
int arr[5];//整形数组5个元素,每个元素是int
int* p1[10];//指针数组里面可存10个int类型的指针
int(*p2)[10];//int类型10个元素数组的指针
int(*p3[10])[5];//存放数组指针(该指针指向int类型5个元素的数组)的数组(该数组能存10个数组指针)
数组参数与指针参数
一维数组传参
一维数组传参
1.传过来一个10个元素的整形数组,用自动长度整形数组接受——ok
2.传过来一个10个元素的整形数组,用10个元素的整形数组接受——ok
3.传过来一个数组名(int类型首元素地址)用int类型指针接受——ok
4.传过来一个整形指针的数组可容纳20元素,用20元素整形指针数组接受——ok
5.传过来一个数组名(int*类型首元素地址),用整形二级指针接受——ok
二维数组传参
关于前3个由下面注释可知1,3都ok
4.二维数组传参,其数组名表示首元素的地址也就是第一行一维数组的地址,由此观之,只有6ok
注意:只有双重地址才可用二级指针接受,接受时你还得看类型对不对 。
一级指针传参
#include
void print(int* p,int sz) {
int i = 0;
for (i = 0; i < sz; i++) {
printf("%d ", *(p + i));
}
}
void main() {
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* p = arr1;
int sz = sizeof(arr1) / sizeof(arr1[0]);
print(p, sz);
}
二级指针传参
#include
void test(int** p) {
**p = 20;
}
void main() {
int a = 10;
int* pa = &a;
int** ppa = &pa;
test(ppa);
int b = 7;
int* arr[10] = { &b };
test(arr);
printf("%dn", a);
printf("%dn", *(arr[0]));
}
函数指针
#includevoid test(int** p) { **p = 20; } void main() { int a = 10; int* pa = &a; int** ppa = &pa; test(ppa); int b = 7; int* arr[10] = { &b }; test(arr); printf("%dn", a); printf("%dn", *(arr[0])); }
函数指针
定义:指向函数的指针(存放函数地址的指针)
#includeint Add(int a,int b) { return a + b; } void main() { //&函数名——取到函数的地址 printf("%pn", &Add);//由此观之,可以得到函数的地址 //注意:数组名!=&数组名,但是函数名==&函数名(函数没首元素的地址) printf("%pn", Add); //函数指针的保存 int (*p1)(int, int) = &Add;//当然,因为函数名==&函数名,所以这里面的&可省略 printf("%pn", p1); int (*p2)(int, int) = Add; printf("%pn", p2); //函数的调用 int ret=(*p1)(3, 5); int res=p2(3, 5);//直接拿函数名调用——p2==&Add而&Add==Add所以p2==Add printf("%dn",ret); printf("%dn",res); }
函数指针类型:返回值类型 (*)(参数类型列表)
代码阅读
函数指针类型为返回值的声明
void (* signal(int,void(*)(int)))(int);
替代——
void(*)(int) signal(int,void(*)(int));
//简便写法 typedef void(*pfun_t)(int);//对void(*)(int)的函数指针类型重命名为pfun_t; pfun_t signal(int, pfun_t);
函数指针数组
定义:存放函数指针的数组
#includeint Add(int a,int b) { return a + b; } int Sub(int a, int b) { return a - b; } void main() { int (*p1)(int, int) = Add; int (*p2)(int, int) = Sub; int (*parr[2])(int, int) = {p1,p2};//函数指针数组可存放2个返回值为int参数列表2个int的函数指针 int ret = (*parr[1])(8, 5);//通过函数指针数组进行函数调用1 int res = parr[0](8, 5);//通过函数指针数组进行函数调用2 printf("%dn", ret); printf("%dn", res); }
指向函数指针数组的指针
定义:取出函数指针数组的地址
int arr1[5];//整形数组 int (*p1)[5]=&arr1;//整形数组的指针 int* arr2[5];//整形指针的数组 int* (*p2)[5] = &arr2;//整形指针数组的指针 int (*p3)(int,int);//函数指针 int (*p4[5])(int, int);//函数指针的数组 int (*(*p4)[5])(int, int);//函数指针数组的指针
回调函数
定义:
举例:b函数里面有a函数的指针作为参数,当通过a函数的指针反过来调用a函数,这种机制叫回调函数机制,通过指针反过来调用的这个函数叫回调函数。
#includeint Add(int a,int b) { return a + b; } int AP(int(*p)(int,int)) { return p(2, 3);//这里我直接省略了* } void main() { int(*ap)(int(*)(int, int)) = &AP; int ret=ap(&Add); printf("%dn", ret); return; }
#includeint Add(int a,int b) { return a + b; } int AP(int(*p)(int,int)) { return p(2, 3);//这里我直接省略了* } void main() { //写法2——反正&AP==ap==AP==*ap所以将*ap用AP取代 int ret=AP(&Add); printf("%dn", ret); return; }



