二、指针进阶
1.字符指针
在上面我们知道指针是有一种指针类型为char *
基础使用方法:
int main() { char ch = 'w'; printf("%c\n", ch); char* pc = &ch; *pc = 'a'; printf("%c\n", ch); return 0; }
进阶用法:
int main() { const char* p = "abcdef";//双引号引用的 常量字符串 不可改变 //字符串表达式 将首字符a的地址交给p printf("%s\n", p);//abcdef printf("%c\n", *p);//a return 0; }
上面的代码是将常量字符串abcdef中的首字符a放在了字符指针变量p中
2.指针数组
指针数组这个名词看起来很蒙圈,其实它是一个数组只不过数组中的每个元素为指针;
实例:使用指针数组模拟实现二位数组
int main() { int arr1[5] = { 1,2,3,4,5 }; int arr2[5] = { 2,3,4,5,6 }; int arr3[5] = { 3,4,5,6,7 }; int* arr[3] = { arr1,arr2,arr3 }; int i = 0; for (i = 0; i < 3; i++) { int j = 0; for (j = 0; j < 5; j++) { printf("%d ", arr[i][j]); //printf("%d ", *(arr[i] + j)); } printf("\n"); } return 0; }
上面这个例子只是模拟实现 二维数组,并不是二维数组真正实现的样子,大家不要混淆了。
3.数组指针
3.1数组指针的定义
那数组指针到底是数组还是指针呢?
答案:指针
int *p1[10]; //[]的结合性高p1先和[]结合表明是一个数组,数组中的每个元素为int *所以叫指针数组 int (*p2)[10]; //p2先和*结合表明是一个指针,然后指向一个大小为10个整形的数组 p2是一个指针 所以叫数组指针
实例:用数组指针模拟实现二维数组
void print(int(*p)[5], int r, int c) { int i = 0; for (i = 0; i < r; i++) { int j = 0; for (j = 0; j < c; j++) { printf("%d ", *(*p + i) + j); //printf("%d ", (*p + i)[j]); } printf("\n"); } } int main() { int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} }; int(*p)[5] = &arr; print(p, 3, 5); return 0; }
上面数组指针的实例和指针数组的实例一样只是模拟实现二维数组,并不是二维数组真正的实现方式,请大家不要混淆。
3.2&数组名VS数组名
我们知道arr是数组名,数组名表示数组首元素的地址。
那么&arr数组名到底是啥?
int main() { int arr[10] = { 0 }; printf("%p\n", arr); printf("%p\n", &arr); return 0; }
我们不难发现两个地址是一样的;那么两个表示的意思究竟一样不?
让我们在看一段代码
int main() { int arr[10] = { 0 }; printf("%p\n", arr); printf("%p\n", arr+1); printf("%p\n", &arr); printf("%p\n", &arr+1); return 0; }
根据上面的代码我们发现arr和arr+1相差4,而&arr和&arr+1相差40,所以arr和&arr虽然值是一样的,但意义不一样。
实际上:&arr取的是整个数组的地址,而不是首元素的地址。数组的地址+1,是跳过整个数组的大小,所以&arr和&arr+1相差40
4.函数指针
让我们先看一段代码
int test() { return 0; } int main() { printf("%p\n", test); printf("%p\n", &test); return 0; }
通过上面的代码我们发现其实函数也是有地址的,所以我们也可以用一个指针变量来存储函数的地址,写法是这样的
int (*p)() //表示p是一个指向返回值为int类型,没有参数的函数指针
5.函数指针数组
函数指针数组是一个数组,数组中的每个元素为函数指针;
写法是这样的
int (*p[])() //p先和[]结合表示是一个数组,数组中的每个元素 ( int(*)() ) 为返回值为int,参数为空的函数指针
函数指针数组的用途:转移表
实例:利用函数指针数组实现整数的加减乘除的计算器
int add(int x, int y) { return x + y; } int sub(int x, int y) { return x - y; } int mul(int x, int y) { return x * y; } int div(int x, int y) { return x / y; } void meun() { printf("******************\n"); printf("***1.add 2.sub ***\n"); printf("***3.mul 4.div ***\n"); printf("*** 0.exit ***\n"); printf("******************\n"); } int main() { int ret = 0; int input = 0; int(*p[5])(int x, int y) = { NULL,add,sub,mul,div }; int x = 0; int y = 0; do { meun(); printf("请选择>:\n"); scanf("%d", &input); if (input >= 1 && input <= 4) { printf("请输入两个操作数>:\n"); scanf("%d %d", &x, &y); ret=(*p[input])( x, y); printf("%d\n", ret); } else if (input == 0) { printf("退出\n"); } else { printf("选择错误,请重新选择\n"); } } while (input); return 0; }
6.指向函数指针数组的指针
首先它是一个指针指向的是一个数组,数组中的每个元素为函数指针;
定义为:
int test(int a) { return a; } int main() { int (*p1)(int) = &test; //p1先于*结合表明是一个指针,指向( int ( )( ) )返回值为int类型的test函数 int (*p2[2])(int) = { NULL,test }; //p2先于[]结合表明是一个数组, //数组中的每个元素( int(*)(int) )为指向返回值为int,参数为int类型的指针 int (*(*p3)[2])(int) = &p2; //p3先于*结合表明是一个指针,指向(int (*[])(int))数组 //数组中的每个元素( int(*)(int) )为指向返回值为int,参数为int类型的指针 return 0; }