当前位置: 首页 > ds >正文

C语言进阶(指针2.函数指针和指针函数,二级指针,指针数组和数组指针,void*指针)

1.指针函数和函数指针

        1. 1指针函数

                是函数,函数的返回值是指针 不能返回局部变量的地址

                指针函数返回的地址可以作为下一个函数调用的参数

封装函数实现strlen功能:

#include <stdio.h>int  mylen(char *pstr){int i = 0;while(*pstr != '\0'){                                                                                                                                                                                                                                pstr++;i++;}return i;}int main(void){char str[32] = {0};int len = 0;gets(str);len = mylen(str);printf("len = %d",len);return 0;}

封装函数实现strcpy功能:

 #include <stdio.h>char *mystrcpy(char *pdst , char *psrc){char *pret = pdst;while(*psrc != '\0'){*pdst = *psrc;pdst++;psrc++;}*pdst = '\0';return pret;}int main(void){char src[50] = {0};char dst[50] = {0};gets(src);mystrcpy(dst,src);printf("src = %s\n",src);printf(" dst = %s\n", dst);                                                                                                                                                                                                      return 0;}

封装函数实现strcmp功能:

  #include <stdio.h>int mystrcmp(char *pdst , char *psrc){while(*pdst == *psrc&&*pdst != '\0'){pdst++;psrc++;}return *pdst - *psrc;                                                                                                                                                                                                            }int main(void){char src[50] = {0};char dst[50] = {0};int res = 0;gets(dst);gets(src);res = mystrcmp(dst,src);printf("%d", res);return 0;}

封装函数实现strcat功能:

#include <stdio.h>void  mystrcat(char *pstr1 , char *pstr2){while(*pstr1 != '\0'){pstr1++;}while(*pstr2 != '\0'){*pstr1 = *pstr2;pstr1++;pstr2++;}*(pstr1+1) ='\0';                                                                                                                                                            }int main(void){char str1 [500] = {0};char str2 [50] = {0};gets(str1);gets(str2);mystrcat(str1,str2);printf("str1 = %s\nstr2 = %s\n",str1,str2);return 0;}

封装函数实现倒置功能:

   #include <stdio.h>char *mysweap(char *psrc){char *pret = psrc;//这里把pret指向psrc的首地址.int i = 0;int j = 0;char tmp = '0';while(*psrc != '\0'){psrc++;i++;}j = i;psrc = pret;//由于psrc进行了自加操作,因此需要重新指向首地址才能交换for(i = 0;i <j/2 ;i++){tmp = pret[i];pret[i] = pret[j - 1 - i];pret[j - 1 -i] = tmp;}return pret;                                                                                                                                                               }int main(void){char src[50] = {0};gets(src);char *res = NULL;res = mysweap(src);printf("%s", res);return 0;}

        1.2.函数指针

                是指针,指针指向一个函数。

其形式为:

int (*p)(int,int);

        函数指针,对加减乘除函数的调用:

#include <stdio.h>int jia(int a ,int b){return a + b;}int jian(int a ,int b){return a - b;}int cheng(int a ,int b){return a * b;}int chu(int a ,int b){return a / b;}int jisuanqi(int x,int y,int (*p)(int a ,int b)){return  p( x, y);}int main(void){int (*p)(int a , int b) = NULL;int num1 = 0;int num2 = 0;char op = 0;scanf("%d %c %d",&num1,&op,&num2);                                                                                                                                           int ret = 0;switch(op){case '+':p = jia;break;case '-':p = jian;break;case '*':p = cheng;break;case '/':p = chu;break;}printf("ret = %d",jisuanqi(num1 ,num2,p));return 0;}

        如下代码会根据jisuanqi函数调用时的不同参数p进行不同的操作运算:(函数指针,调用操作方法)

#include <stdio.h>#include <stdlib.h>int InputArray(int *parray, int len){int i = 0;for (i = 0; i < len; i++){scanf("%d", &parray[i]);}return 0;}int OutputArray(int *parray, int len){int i = 0;for (i = 0; i < len; i++){printf("%d ", parray[i]);}printf("\n");return 0;}int Desc(int num1, int num2){if (num1 < num2){return 1;}return 0;}int Asc(int num1, int num2){if (num1 > num2){return 1;}return 0;}int AbsAsc(int num1, int num2){if (abs(num1) > abs(num2)){return 1;}return 0;}int AbsDesc(int num1,int num2){if(abs(num1) < abs(num2)){return 1;}return 0;}int SortArray(int *parray, int len, int (*pfun)(int, int)){int i = 0;int j = 0;int tmp = 0;for (j = 0; j < len-1; j++){for (i = 0; i < len-1-j; i++){if (pfun(parray[i], parray[i+1])){tmp = parray[i];parray[i] = parray[i+1];parray[i+1] = tmp;}}}return 0;}int main(void){int a[5] = {0};InputArray(a, 5);SortArray(a, 5, AbsDesc);OutputArray(a, 5);return 0;}

2.二级指针

        二级指针是指向一级指针变量的指针。

int **q;定义一个指针变量q,占8个字节空间,指向一个指针变量空间,即指向一级指针变量的指针,也就是
二级指针

        使用场景:

                1. 函数体内部想修改函数体外部指针变量值的时候,需要传指针变量的地址即二级指针

                2. 指针数组传参,数组的数组名是指向数组第一个元素的指针,第一个元素是指针,所以数组名 为指向指针的指针即二级指针。

二级指针的原理:指向指一级针变量的指针。

#include <stdio.h>int main(void){int num = 100;int *p = NULL;int **q = NULL;p = &num;q = &p;printf("&num = %p\n",&num);printf("&p = %p\n",&p);printf("&q = %p\n",&q);printf("-----------------------------------\n");                                                                                                                             printf("p = %p\n",p);printf("q = %p\n",q);printf("num = %d\n",num);printf("-----------------------------------\n");printf("*p = %d\n",*p);printf("*q = %p\n",*q);printf("-----------------------------------\n");printf("**q = %d\n",**q);return 0;}

 

        函数体内部想修改函数体外部指针变量的值,可以使用二级指针

#include <stdio.h>void fun(char **pptmp){*pptmp = "hello world";                                                                                                                                                      }int main(void){char *p = NULL;fun (&p);printf("p = %s",p);return 0;}

3.指针数组和数组指针

3.1指针数组

指针数组是数组,数组的每个元素都是指针,将字符串的首地址存放在各个指针构成的数组中其形式为:

 int *a[5];
定义一个数组,占40个字节,数组名为a,数组中每个元素都是int *型的指针

        存放字符串使用字符型数组,操作字符串使用指针。

        存放字符串数组使用字符型二维数组,操作字符串数组使用指针数组。

        使用指针数组(每个元素都是指针,因此都是八个字节)代替二维数(元素字节长度不固定)组进行排序,前者相对后者,其元素字节大小相等,而后者字节大小不固定,容易产生越界访问。

对于不同字符串采用冒泡排序:

#include <stdio.h>#include <string.h>int main (void){char str [5][50] = {0};char *pstr [5] = {str[0],str[1],str[2],str[3],str[4]};int i = 0;int j = 0;char *ptmp = NULL;for(i = 0;i < 5;i++){gets(str[i]);}for(j = 0;j <4;j++){for(i = 0;i < 5-j-1;i++){if(strcmp (pstr[i],pstr[i+1])>0)ptmp = pstr[i];pstr[i] = pstr[i+1];pstr[i + 1] = ptmp;}}for(i = 0;i < 5;i++){printf("pstr[%d] = %s\n",i,  pstr [i] );}for(i = 0;i < 5;i++){printf("str[%d] = %s\n",i,str[i]);                                                                                                                                               }return 0;}

                                        

                                        避免了对数据交换,只对地址进行交换

3.2数组指针

数组指针是指针,指针指向整个数组,其形式为:

int (*a)[5];
定义一个指针,占8个字节,指针变量名为a,是指向数组20个字节空间的指针

对一维数组数组名&:值不变,类型升级为指向整个数组的指针(对一维数组数组名取地址不会得到二级指针**a,而是会将指针由指向a[0]首地址变为指向整个数组的首地址,两者相等,但是类型不同,一个是指向单个元素,一个是指向整个数组)。

对指针数组*:值不变,类型降级为指向数组第一个元素的指针。

int a[5] = {1, 2, 3, 4, 5};a == &a[0]a == int *
//这两种情况a不能理解为int*型。 
//sizeof:获得数据类型、变量所占字节
//&: & int * -> int **    &a -> int (*p)[5]

数组函数的实质:

#include <stdio.h>#include <string.h>int main (void){int a[5] = {1,2,3,4,5};printf("a[0] = %p\n",&a[0]);printf("a[1] = %p\n",&a[1]);printf("a[2] = %p\n",&a[2]);printf("a[3] = %p\n",&a[3]);printf("a[4] = %p\n",&a[4]);printf("----------------------------\n");printf("a:%p\n",a);printf("a + 1 :%p\n",a + 1);printf("a + 2 : %p\n",a + 2);printf("----------------------------\n");printf("*a = %d\n",*a);printf("*(a+1) = %d\n",*(a+1));printf("*(a+2) = %d\n",*(a+2));printf("----------------------------\n");printf("&a = %p\n",&a);printf("&(a+1) = %p\n",&a+1);printf("----------------------------\n");printf("*&a = %p\n",*&a);printf("*&(a+1) = %p\n",*&a+1);                                                                                                                                              printf("----------------------------\n");printf("**&a = %d\n",**&a);return 0;}

                                    

数组指针需要注意的事项:

        如上代码,答案是3和5,第二个输出:(给a取地址,变成了指向整个数组的指针,字节大小为20,因此&a+1向后偏移20字节,而int*将其强制转化为整型类型,后续-1向前偏移四个字节,此时指针指向a[4]=5)。

数组指针的使用场景:

1)一维数组和指针的关系:数组的数组名是指向数组第一个元素的指针常量

 int a[5] = {1, 2, 3, 4, 5};int *p = NULL;p = &a[0];p = a;a == &a[0];a[n] == *(a+n) == *(p+n) == p[n];

2)二维数组和指针的关系: 数组的数组名是指向数组第一行元素的数组指针

 int a[2][3] = {1, 2, 3, 4, 5, 6};int *p = NULL;int (*q)[3] = NULL;p = &a[0][0];p = a[0];p = *a;q = a;a:指向数组第一行元素的数组指针        int (*)[3]a[0]:指向a[0][0]的指针             int *a[1]:指向a[1][0]的指针             int *
访问数组第m行第n列元素的方式:
a[m][n]*(a[m]+n)*(*(a+m)+n)*(p+m*N+n)*(*(q+m)+n)*(q[m]+n)q[m][n]

数组指针,其数组名指向第一排,数组名+1指向第二排,对其取星值不变,由指向数组的指针变为指向元素的指针:

      

        3.3二维数组的传参

传参形式

int fun(int(*p)[3],int len);//形参为指针数组
int a[2][3]={1,2,3,4,5};
fun(a,2);//调用fun函数,传递数组名和行数

传递二维数组并打印:

#include <stdio.h> int OutputArray(int (*p)[3], int len){int i = 0;int j = 0;for (j = 0; j < len; j++){for (i = 0; i < 3; i++){printf("%d ", p[j][i]);}printf("\n");}return 0;}int InputArray(int (*p)[3],int len){int j = 0;int i = 0;for(j = 0;j < len; j++){for(i = 0;i < 3; i++){scanf("%d",&p[j][i]);                                                                                                                                                }}}int main(void){int a[2][3] = {0};InputArray(a,2);OutputArray(a, 2);return 0;}

                              

接收字符串将其排序后打印:(传递指针数组

#include <stdio.h>
#include <string.h>
int OutputString(char (*p)[32], int len)
{	int i = 0;for (i = 0; i < len; i++){printf("%s\n", p[i]);}return 0;
}
int InputString(char (*p)[32], int len)
{int i = 0;for (i = 0; i < len; i++){gets(p[i]);}return 0;
}
int SortString(char (*p)[32], int len)
{int i = 0;int j = 0;char tmp[32] = {0};for (j = 0; j < len-1; j++){for (i = 0; i < len-1-j; i++){if (strcmp(p[i], p[i+1]) > 0){strcpy(tmp, p[i]);strcpy(p[i], p[i+1]);strcpy(p[i+1], tmp);}}}return 0;
}
int main(void)
{char str[5][32] = {0};InputString(str, 5);SortString(str, 5);OutputString(str, 5);return 0;
}

        3.4指针数组的传参

传参形式

int fun(char **ppstr, int len);
char *pstr[5]= {NULL};
fun(pstr , 5);

接收字符串将其排序后打印:(传递数组指针

#include <stdio.h>
#include <string.h>
int InputArray(char (*p)[32], int len)
{int i = 0;for (i = 0; i < len; i++){gets(p[i]);}return 0;
}
int SortArray(char **ppstr, int len)
{int j = 0;int i = 0;char *ptmp = NULL;for (j = 0; j < len-1; j++){for (i = 0; i < len-1-j; i++){if (strcmp(ppstr[i], ppstr[i+1]) > 0){ptmp = ppstr[i];ppstr[i] = ppstr[i+1];ppstr[i+1] = ptmp;}}}return 0;
}
int OutputArray(char **ppstr, int len)
{int i = 0;for (i = 0; i < len; i++){printf("%s\n", ppstr[i]);}return 0;
}
int OutputArray2(char (*p)[32], int len)
{int i = 0;for (i = 0; i < len; i++){printf("%s\n", p[i]);}return 0;
}
int main(void)
{char str[5][32] = {0};char *pstr[5] = {str[0], str[1], str[2], str[3], str[4]};InputArray(str, 5);SortArray(pstr, 5);OutputArray(pstr, 5);printf("=================\n");OutputArray2(str, 5);return 0;
}

4.void*指针

                void *指针主要用来保存内存地址,其转化为char*,int*,double*时不需要类型转换,直接赋值就可以。char*,int*,double*转化为void*时需要强制类型转换。多用于函数传参和返回值,统一参数和返回类型。

void *p;
char *a;
int *b;
double *c;
p=(void *)a;

##练习

http://www.xdnf.cn/news/16723.html

相关文章:

  • 数据结构 排序(2)---选择排序
  • 使用鼠标在Canvas上绘制矩形
  • PDF转Word免费工具!批量处理PDF压缩,合并, OCR识别, 去水印, 签名等全功能详解
  • Shader开发(四)计算机图形学中的颜色定义
  • Java 大视界 -- Java 大数据机器学习模型在金融信用评级模型优化与信用风险动态管理中的应用(371)
  • Day23-二叉树的层序遍历(广度优先搜素)
  • [明道云]-基础教学2-工作表字段 vs 控件:选哪种?
  • Redis 跨主机连接超时分析:从网络波动到架构优化
  • 个人健康管理小程序(消息订阅、Echarts图形化分析)
  • TGD第八篇:二维应用——图像边缘检测
  • ftp加ssl,升级ftps
  • 三维扫描相机:工业自动化的智慧之眼——迁移科技赋能智能制造新纪元
  • 从东南亚出发:小程序容器技术如何助力 App 快速打入全球市场?
  • LeetCode 1616.分割两个字符串得到回文串
  • PHP性能优化与高并发处理:从基础到高级实践
  • 直播间里的酒旅新故事:内容正在重构消费链路
  • 设计模式:状态模式 State
  • 配置daemon.json使得 Docker 容器能够使用服务器GPU【验证成功】
  • 设计模式十三:代理模式(Proxy Pattern)
  • mac 字体遍历demo
  • 网络原理 - TCP/IP(一)
  • 大数据集分页优化:LIMIT OFFSET的替代方案
  • 解密数据结构之二叉树
  • 解锁全球数据:Bright Data MCP 智能解决代理访问难题
  • 84、【OS】【Nuttx】【启动】栈溢出保护:asm 关键字(下)
  • 使用jQuery时的注意事项
  • 网络安全运维面试准备
  • 2025年科研算力革命:8卡RTX 5090服务器如何重塑AI研究边界?
  • 外星人笔记本装win11哪个版本好_外星人笔记本装win11专业版教程
  • Java中的异常判断以及文件中的常用方法及功能