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

C语言进阶知识--指针(3)

目录

  1. 回调函数是什么?
  2. qsort使用举例
  3. qsort函数的模拟实现
  4. sizeof和strlen的对比
  5. 数组和指针笔试题解析
  6. 指针运算笔试题解析

正文开始

1. 回调函数是什么?

回调函数就是一个通过函数指针调用的函数。
如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,被调用的函数就是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

//使用回调函数改造前

#include <stdio.h>
int add(int a, int b)
{return a + b;
}
int sub(int a, int b)
{return a - b;
}
int mul(int a, int b)
{return a * b;
}
int div(int a, int b)
{return a / b;
}
int main()
{int x, y;int input = 1;int ret = 0;do{printf("*************************\n");printf(" 1:add          2:sub \n");printf(" 3:mul          4:div \n");printf("*************************\n");printf("请选择:");scanf("%d", &input);switch (input){case 1:printf("输入操作数:");scanf("%d %d", &x, &y);ret = add(x, y);printf("ret = %d\n", ret);break;case 2:printf("输入操作数:");scanf("%d %d", &x, &y);ret = sub(x, y);printf("ret = %d\n", ret);break;case 3:printf("输入操作数:");scanf("%d %d", &x, &y);ret = mul(x, y);printf("ret = %d\n", ret);break;case 4:printf("输入操作数:");scanf("%d %d", &x, &y);ret = div(x, y);printf("ret = %d\n", ret);break;case 0:printf("退出程序\n");break;default:printf("选择错误\n");break;}} while (input);return 0;
}

//使用回调函数改造后

#include <stdio.h>
int add(int a, int b)
{return a + b;
}
int sub(int a, int b)
{return a - b;
}
int mul(int a, int b)
{return a * b;
}
int div(int a, int b)
{return a / b;
}
void calc(int(*pf)(int, int))
{int ret = 0;int x, y;printf("输入操作数:");scanf("%d %d", &x, &y);ret = pf(x, y);printf("ret = %d\n", ret);
}
int main()
{int input = 1;do{printf("*************************\n");printf(" 1:add          2:sub \n");printf(" 3:mul          4:div \n");printf("*************************\n");printf("请选择:");scanf("%d", &input);switch (input){case 1:calc(add);break;case 2:calc(sub);break;case 3:calc(mul);break;case 4:calc(div);break;case 0:printf("退出程序\n");break;default:printf("选择错误\n");break;}} while (input);return 0;
}

2. qsort 使用举例

2.1 使用qsort函数排序整型数据

#include <stdio.h>
//qosrt函数的使用者得实现一个比较函数
int int_cmp(const void * p1, const void * p2)
{return (*(int *)p1 - *(int *)p2);
}
int main()
{int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };int i = 0;qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){printf("%d ", arr[i]);}printf("\n");return 0;
}
2.2 使用qsort排序结构数据
#include <string.h>
#include <stdio.h>
struct Stu //学生
{char name[20];//名字int age;//年龄
};
//假设按照年龄来比较
int cmp_stu_by_age(const void* e1, const void* e2)
{return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
//strcmp - 是库函数,是专门用来比较两个字符串的大小的
//假设按照名字来比较
int cmp_stu_by_name(const void* e1, const void* e2)
{return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
//按照年龄来排序
void test2()
{struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };int sz = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
}
//按照名字来排序
void test3()
{struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };int sz = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
}
int main()
{test2();test3();return 0;
}

3. qsort函数的模拟实现

使用回调函数,模拟实现qsort(采用冒泡的方式)。
注意:这里第一次使用void* 的指针,讲解void* 的作用。

#include <stdio.h>
int int_cmp(const void * p1, const void * p2)
{return (*(int *)p1 - *(int *)p2);
}
void _swap(void *p1, void * p2, int size)
{int i = 0;for (i = 0; i < size; i++){char tmp = *((char *)p1 + i);*((char *)p1 + i) = *((char *)p2 + i);*((char *)p2 + i) = tmp;}
}
void bubble(void *base, int count, int size, int(*cmp)(void *, void *))
{int i = 0;int j = 0;for (i = 0; i < count - 1; i++){for (j = 0; j < count - i - 1; j++){if (cmp((char *)base + j*size, (char *)base + (j + 1)*size) > 0){_swap((char *)base + j*size, (char *)base + (j + 1)*size, size);}}}
}
int main()
{int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };int i = 0;bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){printf("%d ", arr[i]);}printf("\n");return 0;
}

4. sizeof和strlen的对比

4.1 sizeof

在学习操作符的时候,我们学习了sizeof,sizeof计算变量所占内存空间大小,单位是字节,如果操作数是类型的话,计算的是使用该类型创建的变量所占内存空间的大小。
sizeof只关注占用内存空间的大小,不在乎内存中存放什么数据。

例如:

#include <stdio.h>
int main()
{int a = 10;printf("%d\n", sizeof(a));printf("%d\n", sizeof a);printf("%d\n", sizeof(int));return 0;
}

4.2 strlen

strlen是C语言库函数,功能是求字符串长度,函数原型如下:size_t strlen ( const char * str )
strlen统计的是从其参数str所指向的地址开始向后,到\0之前字符串中字符的个数,该函数会一直向后找\0字符,直到找到为止,所以可能存在越界查找。

例如:

#include <stdio.h>
int main()
{char arr1[3] = {'a', 'b', 'c'};char arr2[] = "abc";printf("%d\n", strlen(arr1));printf("%d\n", strlen(arr2));printf("%d\n", sizeof(arr1));printf("%d\n", sizeof(arr2));return 0;
}

4.3 sizeof 和 strlen的对比

sizeofstrlen
1. sizeof是操作符1. strlen是库函数,使用需要包含头文件 string.h

5. 数组和指针笔试题解析

5.1 一维数组

int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a+0));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(a[1]));
printf("%d\n",sizeof(&a));printf("%d\n",sizeof(*&a));
printf("%d\n",sizeof(&a+1));
printf("%d\n",sizeof(&a[0]));
printf("%d\n",sizeof(&a[0]+1));

5.2 字符数组

代码1

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));

代码2

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));

代码3

char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));

代码4

char arr[] = "abcdef";
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));

代码5

char *p = "abcdef";
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p+1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p+1));
printf("%d\n", sizeof(&p[0]+1));

代码6

char *p = "abcdef";
printf("%d\n", strlen(p));
printf("%d\n", strlen(p+1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p+1));
printf("%d\n", strlen(&p[0]+1));

5.3 二维数组

int a[3][4] = {0};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a[0][0]));
printf("%d\n",sizeof(a[0]));
printf("%d\n",sizeof(a[0]+1));
printf("%d\n",sizeof(*(a[0]+1)));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(*(a+1)));
printf("%d\n",sizeof(&a[0]+1));
printf("%d\n",sizeof(*(&a[0]+1)));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a[3]));

数组名的意义

  1. sizeof(数组名):这里的数组名表示整个数组,计算的是整个数组的大小。
  2. &数组名:这里的数组名表示整个数组,取出的是整个数组的地址。
  3. 除此之外所有的数组名都表示首元素的地址。

6. 指针运算笔试题解析

6.1 题目1

#include <stdio.h>
int main()
{int a[5] = { 1, 2, 3, 4, 5 };int *ptr = (int *)(&a + 1);printf( "%d,%d", *(a + 1), *(ptr - 1));return 0;}
//程序的结果是什么?

6.2 题目2

//在X86环境下
//假设结构体的大小是20个字节
//程序输出的结果是啥?
struct Test
{int Num;char *pcName;short sDate;char cha[2];short sBa[4];}*p = (struct Test*)0x100000;int main()
{printf("%p\n", p + 0x1);printf("%p\n", (unsigned long)p + 0x1);printf("%p\n", (unsigned int*)p + 0x1);return 0;}

6.3 题目3

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

6.4 题目4

//假设环境是x86环境,程序输出的结果是啥?
#include <stdio.h>
int main()
{int a[5][5];int(*p)[4];p = a;printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);return 0;
}

6.5 题目5

#include <stdio.h>
int main()
{int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int *ptr1 = (int *)(&aa + 1);int *ptr2 = (int *)(*(aa + 1));printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));return 0;}

6.6 题目6

#include <stdio.h>
int main()
{char *a[] = {"work","at","alibaba"};char**pa = a;pa++;printf("%s\n", *pa);return 0;
}

6.7 题目7

#include <stdio.h>
int main()
{char *c[] = {"ENTER","NEW","POINT","FIRST"};char**cp[] = {c+3,c+2,c+1,c};char***cpp = cp;printf("%s\n", **++cpp);printf("%s\n", *--*++cpp+3);printf("%s\n", *cpp[-2]+3);printf("%s\n", cpp[-1][-1]+1);return 0;
}

指针知识到此结束,该部分知识难度偏大,希望读者勤加练习
文章参考:鹏哥C语言学习笔记

http://www.dtcms.com/a/445580.html

相关文章:

  • M-LLM Based Video Frame Selection for Efficient Video Understanding论文阅读
  • 福州建设高端网站wordpress中控制图片标签
  • Prometheus 05-01: 告警规则与Alertmanager配置
  • 【Linux】Mysql的基本文件组成和配置
  • 简单易用!NAS+Leantime,开源轻量级项目管理,高效协作一键开启
  • 大数据毕业设计选题推荐-基于大数据的全球用水量数据可视化分析系统-大数据-Spark-Hadoop-Bigdata
  • NLP:迁移学习关于领域自适应的基础讲解
  • 在运行中的 Kafka 集群渐进式启用安全零停机实战手册(KRaft/Broker 通用)
  • 网站手机版制作白嫖永久服务器
  • 用一个 Bash CLI 管理多款 AI 开发工具:jt-code-cli 实战与原理解析
  • Linux《线程同步和互斥(下)》
  • 百丽企业数字化转型失败案例分析及其AI智能名片S2B2C商城小程序的适用性探讨
  • 【STM32项目开源】基于STM32的智能宠物防丢监控系统
  • UV紫外相机在工业视觉检测中的应用
  • Redis-UV统计(HyperLogLog)
  • PHP 8.0+ 极限性能优化与系统级编程
  • Deep Learning Optimizer | Adam、AdamW
  • 【linux】linux的扩充指令的学习
  • vim保姆级使用,操作详解,快捷键大全总结
  • jmr119色带贵港seo
  • NLP:迁移学习基础讲解
  • 10.5 数位dp
  • 基于汽车钣金理念的门窗柔性生产系统重构方案
  • 做网站要哪些技术查企业法人信息查询平台
  • Go语言入门(20)-nil
  • Go基础:Go语言ORM框架GORM详解
  • 备案 网站备注网站用的服务器多少钱
  • 《API网关在智能制造产线协同中的定制化实践与可靠性重构》
  • 建设网站的调研报告校园电子商务网站建设规划书实例
  • 书生浦语第六期 L1-G2000