「1」指针进阶——详解
🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀
目录
🐰指针的回顾
🐰字符指针
🐰指针数组
🌸模拟二维数组(整形)
🐰数组指针
🌸数组指针和指针数组的区分
🌸&数组名和数组名的区别
🌸数组指针p,*p等价于arr,*p就是数组名
🌸数组指针的使用
🌸数组参数和指针参数
🐰函数指针-指向函数的指针
🌸函数指针数组
🐰指针的回顾
1.指针是内存中一个最小单元的编号,也就是地址
2.平时口语上所说的指针,通常指的是指针变量,是用来存放地址的变量
3.把内存划分为一个个的内存单元,这个内存单元大小是1字节,从概念上讲:编号 == 地址 == 指针
指针变量:
我们可以通过& (取地址操作符) 取出变量的内存起始地址,把地址可以存放到一个变量中,这个变量就是指针变量
4.指针大小(4字节 32位/8字节 64位)
🐰字符指针
#include<stdio.h> int main() {char ch='w';char* pc=&ch;const char* p="abcdef";//"abcdef",是把字符串的首地址放到p中//"abcdef"是常量字符串,是不可以修改的char arr[]="abcdef";//"abcdef",这里的arr的值是可以修改的char *pa=arr;*pa='w';printf("%s\\n",arr);//修改的结果为wbcdefreturn 0; }
‼️注:常量字符串在内存中只保存一份!!!
#include<stdio.h> int main() {char str1[]="abcdef";char str2[]="abcdef";char* str3="abcdef";//保存的就是常量字符串char* str4="abcdef";//保存的就是常量字符串if(str1==str2)//数组保存的字符串是变量,所以str1!=str2{printf("str1==str2\\n");}else{printf("str1!=str2\\n");}if(str3==str4)//常量字符串在内存中只保留一份,所以str3==str4{printf("str3==str4\\n");}else{printf("str3!=str4\\n");}return 0; }
结果为:
str1!=str2str3==str4
🐰指针数组
字符数组-存放字符的数组char arr[10];整形数组-存放整形的数组int arr[10];指针数组-存放的就是指针char* arr[10];int* arr[10];#include<stdio.h> int main() {char* arr[]={"abc","bcd","edf"};//指针数组,保存了三个字符串的首地址for(int i=0;i<3;i++){printf("%s\\n",arr[i]);}return 0; }
结果为:abc
bcd
edf
🌸模拟二维数组(整形)
#include<stdio.h> int main() {int arr1[]={1,2,3,4,5};int arr2[]={1,2,3,4,5};int arr3[]={1,2,3,4,5};int arr4[]={1,2,3,4,5};int* arr5[]={arr1,arr2,arr3,arr4};for(int i=0;i<4;i++){for(int j=0;j<5;j++){printf("%d",*(arr5[i]+j));//printf("%d\\n",arr5[i][j]);//结果一样}printf("\\n");}return 0; }
结果为:
12345
12345
12345
12345
🐰数组指针
整形指针-指向整形的指针int a=10;int* P=&a字符指针-指向字符的指针char ch='w';char* pc=&ch;数组指针-指向数组的指针int arr[10];&arr就是数组的地址int (*pa)[10]=&arr;char arr[10];char(*pc)[10]=&arrint* arr[5];int* (*pa)[5]=&arr//这个数组指针指向的是arr这个指针数组🌸数组指针和指针数组的区分
指针数组->存放指针的数组数组指针->是一种指向数组的指针-存放的是数组的地址🌸&数组名和数组名的区别
数组名是数组首元素地址sizeof(数组名)--这个时候表示的不是首元素的首地址,计算的整个数组的大小&数组名--这里的数组名表示整个数组,取出的是整个数组的地址,从地址角度看和数组首元素的地址一样,他们的类型不一样#include<stdio.h> int main() {int arr[10]={0};printf("arr=%p\\n",arr);//数组首元素的地址printf("arr+1=%p\\n",arr+1);//数组第二个元素的地址printf("&arr[0]=%p\\n",&arr[0]);//数组首元素的地址printf("&arr[0]+1=%p\\n",&arr[0]+1);//数组第二个元素的地址printf("&arr=%p\\n",&arr);//整个数组的地址printf("&arr+1=%p\\n",&arr+1);//数组第最后一个元素的下一个的地址int(*p)[10]=&arr;//数组指针保存整个数组的地址return 0; }
结果
r=0x7ffeefbff3c0arr+1=0x7ffeefbff3c4&arr[0]=0x7ffeefbff3c0&arr[0]+1=0x7ffeefbff3c4&arr=0x7ffeefbff3c0&arr+1=0x7ffeefbff3e8🌸数组指针p,*p等价于arr,*p就是数组名
#include<stdio.h> int main() {int arr[10]={1,2,3,4,5,6,7,8,9,10};int (*p)[10]=&arr;for(int i=0;i<10;i++){printf("%d ",*((*p)+i));//*p等价于arr,*p就是数组名}return 0; }
结果为:1 2 3 4 5 6 7 8 9 10
🌸数组指针的使用
#include<stdio.h> void print(int (*arr)[5],int r,int c) {for(int i=0;i<r;i++){for(int j=0;j<c;j++){printf("%d ",*(*(arr+i)+j));//arr+i==&arr[i]//printf("%d ",arr[i][j]);}} } int main() {//二维数组的数组名,也表示首元素地址//二维数组的首元素是第一行的地址,是一个一维数组的地址int arr[3][5]={1,2,3,4,5,6,7,8,9,10};print(arr,3,5);return 0; }
结果为:
1 2 3 4 5 6 7 8 9 10 0 0 0 0 0二维数组arr
int (*p)[10]=&arr;p等价于arrarr=&arr[i]arr[i]=&arr[i][0]分析代码int arr[5];int *parr1[10];//指针数组int (*parr2)[10];//数组指针int (*parr3[10])[5];//数组中存放的数组指针🌸数组参数和指针参数
一维数组传参一维数组传参,形参可以是数组,可以是指针二维数组传参参数可以是指针,可以是数组,如果是指针,传过去的是第一行的地址函数形参的设计只能省略第一个[]的数字,因为一个二维数组,可以不知道有对少行,但是必须知道一行有多少元素一级指针传参当一个函数的参数部分为一级指针的时候,函数能接收什么参数数组,指针二级指针传参当一个函数的参数部分为二级指针的时候,函数能接收什么参数二级指针变量,一级指针的地址,指针数组
🐰函数指针-指向函数的指针
函数指针存放的是函数的地址,函数也是有地址的‼️注:函数名和取地址函数名 是一样的#include<stdio.h> int Add(int x,int y) {return x+y; } //函数是存在地址 int main() {printf("%p\\n",&Add);//0x100003f40printf("%p\\n",Add);//0x100003f40int (*pf)(int,int)=Add;//pf就是函数指针int ret=(*pf)(3,5);//函数指针的调用int rat=pf(3,5);//*pf和pf等价//这里的*没有实际的意义,可以不要pf(3,5),可以多加(pf)(3,5),都不影响结果,*pf)(3,5)是为了方便理解printf("%d %d\\n",ret,rat); }
结果为:
0x100003ef0
0x100003ef0
8 8
🌸函数指针数组
数组的每个元素是一个函数指针这是利用switch()语句制作的两位数计算器#include<stdio.h> 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 menu(void) {printf(" 两位数的计算器 \\n");printf(" 1.Add 2.Sub \\n");printf(" 3.Mul 4.Div \\n");printf(" 0.exit \\n"); } int main() {int input=0;do{menu();printf("请选择\\n");scanf("%d",&input);int x=0,y=0,ret=0;switch(input){case 1:printf("请输入两个操作数\\n");scanf("%d %d",&x,&y);ret=Add(x,y);printf("%d\\n",ret);break;case 2:printf("请输入两个操作数\\n");scanf("%d %d",&x,&y);ret=Sub(x,y);printf("%d\\n",ret);break;case 3:printf("请输入两个操作数\\n");scanf("%d %d",&x,&y);ret=Mul(x,y);printf("%d\\n",ret);break;case 4:printf("请输入两个操作数\\n");scanf("%d %d",&x,&y);ret=Div(x,y);printf("%d\\n",ret);break;default:printf("输入错误\\n");}}while(input); }
结果为:
两位数的计算器
1.Add 2.Sub
3.Mul 4.Div
0.exit
请选择
1
请输入两个操作数
3 8
11
这种算法,太冗余了,不够简洁这是利用函数指针数组制作的两位数计算器#include<stdio.h> 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 menu(void) {printf(" 两位数的计算器 \\n");printf(" 1.Add 2.Sub \\n");printf(" 3.Mul 4.Div \\n");printf(" 0.exit \\n"); } int main() {int input=0;do{int x=0,y=0;menu();printf("请选择\\n");scanf("%d",&input);printf("请输入两个操作数\\n");scanf("%d %d",&x,&y);int (*pf[5])(int,int)={0,Add,Sub,Mul,Div};//这里之所以数组元素给了5个,是为了与菜单对应起来if(input<5&&input>=0){int ret=(*pf[input])(x,y);printf("%d\\n",ret);}else if(input==0){printf("计算结束\\n");break;}else{printf("输入错误\\n");}}while(input); }
结果为:
两位数的计算器
1.Add 2.Sub
3.Mul 4.Div
0.exit
请选择
1
请输入两个操作数
3 8
11
这种算法,很简洁,逻辑更清晰。
🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸