C语言学习笔记之指针(二)
指针基础知识:C语言学习笔记之指针(一)-CSDN博客
目录
字符指针
代码分析
指针数组
数组指针
函数指针
代码分析(出自《C陷阱和缺陷》)
函数指针数组
指向函数指针数组的指针
回调函数
qsort()
字符指针
一般用法:

特殊用法:

上述代码的本质是把字符串 "hello bit." 的首字符的地址放到了pstr中。因为"hello bit."是一个常量字符串,是存放在代码段的数据,所以不能被修改,因此要用const 修饰来防止权限的放大。


代码分析

这里str3和str4指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4相同。
指针数组
指针数组是一种数组,数组内的每个元素的类型是指针类型。

用指针数组模拟实现一个二维数组:
#include <stdio.h>void print(int** arr, int row, int col)
{int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){printf("%d ", *(*(arr + i) + j)); //等价于 printf("%d ", arr[i][j]);//printf("%d ", arr[i][j]);}printf("\n");}}
int main()
{int arr1[] = { 1, 2, 3, 4, 5 };int arr2[] = { 2, 3, 4, 5, 6 };int arr3[] = { 3, 4, 5, 6, 7 };int* arr[] = { arr1, arr2, arr3 };print(arr, 3, 5);return 0;
}
注:模拟的二位数组在内存中并不一定连续存放,因此它不是真的二维数组。
数组指针
我们已经熟悉:
- 整形指针: int * pint; 能够指向整形数据的指针。
- 浮点型指针: float * pf; 能够指向浮点型数据的指针。
同理,数组指针就是指向数组的指针,即存放数组地址的指针变量。

写一个打印二维数组的函数,形参是数组指针:
#include <stdio.h>
void print_arr1(int arr[3][5], int row, int col)
{int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){printf("%d ", arr[i][j]);}printf("\n");}
}
void print_arr2(int(*arr)[5], int row, int col) //数组指针接收
{int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){printf("%d ", *(*(arr + i) + j));}printf("\n");}
}
int main()
{int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10 };print_arr1(arr, 3, 5);//数组名arr,表示首元素的地址//但是二维数组的首元素是二维数组的第一行(二维数组可以看成是一维数组的数组,即二维数组的每个元素是一个一维数组)//所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址//可以数组指针来接收printf("\n");print_arr2(arr, 3, 5);return 0;
}

类型分析:

函数指针
函数也是有地址的,顾名思义,函数指针就是指向函数的指针,即存放函数地址的指针变量。
函数指针类型:函数返回值类型 (*指针变量名)(函数参数)。
#include <stdio.h>
void test()
{printf("hehe\n");
}
int main()
{printf("%p\n", test);printf("%p\n", &test);return 0;
}

根据上述代码的执行结果我们可以看出,函数名表示函数地址,&地址函数名也表示函数地址,即 函数名 == &函数名,所以 *(&函数名)== * 函数名 ,而*(&函数名)== 函数名,因此 函数名 == &函数名 == * 函数名。

首先,能存储地址,就要求pfun1或者pfun2是指针,那哪个是指针? 答案是:pfun1可以存放。pfun1先和*结合,说明pfun1是指针,指针指向的是一个函数,指向的函数无参数,返回值类型为void。pfun2先和()结合,表示pfun2是一个没有参数,返回类型是void* 的函数。
代码分析(出自《C陷阱和缺陷》)
(*(void (*)())0)();

void (*signal(int , void(*)(int)))(int);

利用 typedef 简化上述代码:

函数指针数组
存放函数指针的数组就叫做函数指针数组。

parr1 先和 [] 结合,说明 parr1是数组,数组的内容是什么呢? 是 int (*)() 类型的函数指针。
函数指针数组的用途:转移表
示例(计算器):
#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;int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //转移表while (input){printf("*************************\n");printf(" 1:add 2:sub \n");printf(" 3:mul 4:div \n");printf(" 0:exit \n");printf("*************************\n");printf("请选择:");scanf("%d", &input);if ((input <= 4 && input >= 1)){printf("输入操作数:");scanf("%d %d", &x, &y);ret = (*p[input])(x, y);}else if (input == 0){printf("程序退出\n");break;}elseprintf("输入有误\n");printf("ret = %d\n", ret);}return 0;
}

指向函数指针数组的指针
顾名思义,指针指向的是一个每个元素是函数指针的数组。

回调函数
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。回调函数是一种泛型编程思维,库函数 qsort() 就运用了回调函数。
qsort()
qsort()可以给任意类型(整型,浮点型,结构体等)的数据排序,但是需要我们按要求提供一个比较函数。

用冒泡排序模拟实现一个类似 qsort() 的函数:
#include <stdio.h>void swap(char* p1, char* p2, size_t size) //交换arr[j],arr[j+1]这两个元素
{int i = 0;for (i = 0; i < size; i++){char tmp = *p1;*p1 = *p2;*p2 = tmp;p1++;p2++;}
}void bubble_sort(void* base, size_t num, size_t size, int (*cmp)(const void*, const void*))
{int i = 0;//趟数for (i = 0; i < num - 1; i++){int j = 0;//一趟内部比较的对数for (j = 0; j < num - 1 - i; j++){//假设需要升序cmp返回>0,交换if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0) //两个元素比较,需要将arr[j],arr[j+1]的地址要传给cmp{//交换swap((char*)base + j * size, (char*)base + (j + 1) * size, size);}}}
}int cmp_int(const void* p1, const void* p2) //回调函数
{return *(int*)p1 - *(int*)p2;
}//测试bubble_sort 排序整型数据
void test1()
{int arr[10] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(int), cmp_int);
}struct Stu
{char name[20];int age;
};int cmp_stu_by_age(const void* p1, const void* p2) //回调函数
{return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}//测试bubble_sort 排序结构体数据(比较年龄)
void test2()
{struct Stu arr[] = { {"zhangsan", 20}, {"lisi", 50},{"wangwu", 15} };int sz = sizeof(arr) / sizeof(arr[0]); bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
}int cmp_stu_by_name(const void* p1, const void* p2) //回调函数
{return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}//测试bubble_sort 排序结构体数据(比较名字)
void test3()
{struct Stu arr[] = { {"zhangsan", 20}, {"lisi", 50},{"wangwu", 15} };int sz = sizeof(arr) / sizeof(arr[0]);printf("%d\n", sizeof(struct Stu));bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
}int main()
{test1();test2();test3();return 0;
}



相关文章:
C语言学习笔记之指针(二)
指针基础知识:C语言学习笔记之指针(一)-CSDN博客 目录 字符指针 代码分析 指针数组 数组指针 函数指针 代码分析(出自《C陷阱和缺陷》) 函数指针数组 指向函数指针数组的指针 回调函数 qsort() 字符指针 一…...
在Debian 12系统上安装Docker
Docker 在 Debian 12 上的安装 安装验证测试更多信息 引言 在现代的开发环境中,容器技术发挥着至关重要的作用。Docker 提供了快速、可靠和易于使用的容器化解决方案,使开发人员和 DevOps 专业人士能够以轻松的方式将应用程序从一个环境部署到另一个环…...
策略者模式(代码实践C++/Java/Python)————设计模式学习笔记
文章目录 1 设计目标2 Java2.1 涉及知识点2.2 实现2.2.1 实现两个接口飞行为和叫行为2.2.2 实现Duck抽象基类(把行为接口作为类成员)2.2.3 实现接口飞行为和叫行为的具体行为2.2.4 具体实现鸭子2.2.5 模型调用 3 C(用到了大量C2.0的知识&…...
vue2/Vue3项目中,通过请求接口来刷新列表中的某个字段(如:Axios)
vue2/Vue3项目中,通过请求接口来刷新列表中的某个字段。可以使用 Vue 的异步请求库(如 Axios)来发送请求,并在请求成功后更新相应的字段。 示例如下(Vue2): 简单的示例如下,假设列…...
Java多线程锁定
前言 利用多线程编程虽然能极大地提升运行效率,但是多线程本身的不稳定也会带来一系列的问题,其中最经典莫过于售票问题;这时就需要人为地加以限制和干涉已解决问题,譬如今日之主题——锁定。 锁定是我们在多线程中用来解决售票…...
【C 数据结构】单链表
文章目录 【 1. 基本原理 】1.1 链表的节点1.2 头指针、头节点、首元节点 【 2. 链表的创建 】2.0 创建1个空链表(仅有头节点)2.1 创建单链表(头插入法)*2.2 创建单链表(尾插入法) 【 3. 链表插入元素 】【…...
[MAUI]集成富文本编辑器Editor.js至.NET MAUI Blazor项目
文章目录 获取资源从源码构建从CDN获取获取扩展插件 创建项目创建控件创建Blazor组件初始化保存销毁编写渲染逻辑 实现只读/编辑功能切换模式获取只读模式状态响应切换事件 实现明/暗主题切换项目地址 Editor.js 是一个基于 Web 的所见即所得富文本编辑器,它由CodeX…...
Spring Boot | Spring Boot 整合 “Servlet三大组件“ ( Servlet / Filter / Listene )
目录: Spring Boot 整合 "Servlet三大组件" :1. 使用 "组件注册" 的方式 "整合Servlet三大组件" ( 实际操作为 : 创建自定义的"三大组件"对象 结合刚创建"的自定义组件对象"来 将 XxxRegistrationBean对象 通过…...
错误分析 (Machine Learning研习十九)
错误分析 您将探索数据准备选项,尝试多个模型,筛选出最佳模型,使用 Grid SearchCV微调其超参数,并尽可能实现自动化。在此,我们假设您已经找到了一个有前途的模型,并希望找到改进它的方法。其中一种方法就…...
SQL系统函数知识点梳理(Oracle)
这里写目录标题 函数系统函数转换函数to_date()to_char()将数值转换成字符格式 添加货币符号将日期转换成字符 其他不常用的转换函数 字符型函数连接函数大小写转换函数大写转换小写转换首字母大写,其余的小写 替换函数去除空格函数截取函数填充函数获取字符长度函数…...
面试突击---MySQL索引
面试突击---MYSQL索引 面试表达技巧:1、谈一下你对于mysql索引的理解?(为什么mysql要选择B树来存储索引)2、索引有哪些分类?3、聚簇索引与非聚簇索引4、回表、索引覆盖、最左匹配原则、索引下推(1ÿ…...
关注 | 我国已对百种产品实施强制性产品认证
市场监管总局在7日举行的新闻发布会上介绍,该局日前发布《市场监管总局关于对商用燃气燃烧器具等产品实施强制性产品认证管理的公告》,对具有较高安全风险的商用燃气燃烧器具、阻燃电线电缆、电子坐便器、电动自行车乘员头盔、可燃气体探测报警产品、水性…...
虚幻引擎架构自动化及蓝图编辑器高级开发进修班
课程名称:虚幻引擎架构自动化及蓝图编辑器高级开发进修班 课程介绍 大家好 我们即将推出一套课程 自动化系统开发。 自动化技术在项目开发的前中后期都大量运用。如何您是一家游戏公司,做的是网络游戏,是不是经常会遇到程序员打包加部署需…...
Weakly Supervised Audio-Visual Violence Detection 论文阅读
Weakly Supervised Audio-Visual Violence Detection 论文阅读 摘要III. METHODOLOGYA. Multimodal FusionB. Relation Modeling ModuleC. Training and Inference IV. EXPERIMENTSV. CONCLUSION阅读总结 文章信息: 发表于:IEEE TRANSACTIONS ON MULTIME…...
华为海思数字芯片设计笔试第六套
声明 下面的题目作答都是自己认为正确的答案,并非官方答案,如果有不同的意见,可以评论区交流。 这些题目也是笔者从各个地方收集的,感觉有些题目答案并不正确,所以在个别题目会给出自己的见解,欢迎大家讨论…...
重绘和重排:概念、区别和应用示例
还是大剑师兰特:曾是美国某知名大学计算机专业研究生,现为航空航海领域高级前端工程师;CSDN知名博主,GIS领域优质创作者,深耕openlayers、leaflet、mapbox、cesium,canvas,webgl,ech…...
创建k8s deploy yaml文件的imagePullSecrets语句
镜像仓库是harbor kubectl create secret docker-registry key --docker-server192.168.0.190 --docker-usernameadmin --docker-passwordHarbor12345...
大模型预测结果导入到Doccano,人工修正预测不准的数据
背景 使用大语言模型做实体识别的实验时,发现大模型关于实体的边界预测一直不准。 主要原因在于当时找了很多同学标注数据,由于不同组同学关于实体的边界没有统一,故导致数据集中实体边界也没统一。 (找太多人标,会有…...
python三方库_ciscoconfparse学习笔记
文章目录 介绍使用基本原理父子关系 属性ioscfg 获取配置信息,返回列表is_config_line 判断是否是配置行is_intf 判断IOSCfgLine是不是interfaceis_subintf 判断IOSCfgLine是不是子接口lineage 不知道用法is_ethernet_intf 判断IOSCfgLine是否是以太网接口is_loopback_intf 判断…...
HDFS详解(Hadoop)
Hadoop 分布式文件系统(Hadoop Distributed File System,HDFS)是 Apache Hadoop 生态系统的核心组件之一,它是设计用于存储大规模数据集并运行在廉价硬件上的分布式文件系统。 1. 分布式存储: HDFS 将文件分割成若干块…...
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...
