> 文章列表 > 「1」指针进阶——详解

「1」指针进阶——详解

「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!=str2

str3==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]=&arr
int* 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=0x7ffeefbff3c0
arr+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等价于arr
arr=&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

这种算法,很简洁,逻辑更清晰。

🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸