C语言学习笔记之指针(二)

news/2024/5/22 2:01:54

指针基础知识: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;
}


http://www.mrgr.cn/p/32407222

相关文章

实验一原型设计——不背单词app

一、实验题目:原型设计 二、实验目的:掌握产品原型设计方法和相应工具使用。 三、实验要求 (1)对比分析墨刀、Axure、Mockplus等原型设计工具的各自的适用领域及优缺点(至少3条)。 1.墨刀 适用领域:手机端项目。 优点: 简单易用:墨刀提供了直观的界面和简单的操作,适…

Axure RP中的相关概念及高保真原型构建方法

1 Axure RP中概念介绍 对于构建高保真原型来说&#xff0c;需要知道事件&#xff08;Event&#xff09;、Case、Action等概念。Axure RP中给出这些概念&#xff0c;是为了方便原型的构建&#xff0c;尤其是高保真原型的构建。 事件&#xff08;Event&#xff09;是附着于控件…

Python-数字取证秘籍(二)

Python 数字取证秘籍(二)原文:zh.annas-archive.org/md5/941c711b36df2129e5f7d215d3712f03 译者:飞龙 协议:CC BY-NC-SA 4.0第四章:提取嵌入式元数据配方 本章涵盖以下配方:提取音频和视频元数据大局观挖掘 PDF 元数据审查可执行文件元数据阅读办公文档元数据将我们的元…

Python-数字取证秘籍(三)

Python 数字取证秘籍(三)原文:zh.annas-archive.org/md5/941c711b36df2129e5f7d215d3712f03 译者:飞龙 协议:CC BY-NC-SA 4.0第六章:阅读电子邮件和获取名称的配方 本章涵盖了以下配方:解析 EML 文件查看 MSG 文件订购外卖盒子里有什么?解析 PST 和 OST 邮箱介绍 一旦计…

【Linux系统编程】第四弹---基本指令(二)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、echo指令 2、cat指令 3、more指令 4、less指令 4、head指令 5、tail指令 6、时间相关的指令 7、cal指令 8、find指…

Python-并行编程秘籍(二)

Python 并行编程秘籍(二)原文:zh.annas-archive.org/md5/e472b7edae31215ac8e4e5f1e5748012 译者:飞龙 协议:CC BY-NC-SA 4.0第三章:基于进程的并行处理 在上一章中,我们学习了如何使用线程来实现并发应用程序。本章将讨论我们在第一章中介绍的基于进程的方法,使用并行…

Learning-Scrapy-中文版(一)

Learning Scrapy 中文版(一) 零、序言序言 第 1 章 Scrapy 介绍 第 2 章 理解 HTML 和 XPath 第 3 章 爬虫基础 第 4 章 从 Scrapy 到移动应用 第 5 章 快速构建爬虫 第 6 章 Scrapinghub 部署 第 7 章 配置和管理 第 8 章 Scrapy 编程 第 9 章 使用 Pipeline 第 10 章 理解 …

Learning-Scrapy-中文版(三)

Learning Scrapy 中文版(三) 八、Scrapy 编程 到目前为止,我们创建爬虫的目的是抓取数据,并提取信息。除了爬虫,scrapy 可以让我们微调它的功能。例如,你会经常碰到以下状况: 你在同一个项目的爬虫间复制粘贴了很多代码。重复的代码更多是关于处理数据,而不是关于数据源…

Learning-Scrapy-中文版(二)

Learning Scrapy 中文版(二) 三、爬虫基础 本章非常重要,你可能需要读几遍,或是从中查找解决问题的方法。我们会从如何安装 Scrapy 讲起,然后在案例中讲解如何编写爬虫。开始之前,说几个注意事项。 因为我们马上要进入有趣的编程部分,使用本书中的代码段会十分重要。当你…

Android 车载应用开发概述

前言 介绍 Android 车载应用开发 文章目录 前言一、Android Automotive OS 概述二、Android Automotive OS 架构三、常见的车载应用1、系统应用1&#xff09;SystemUI是什么开发工作 2&#xff09;Launcher是什么开发工作 3&#xff09;Settings是什么开发工作 4&#xff09;多…

m基于yolov2深度学习的细胞检测系统matlab仿真,带GUI操作界面

1.算法仿真效果 matlab2022a仿真结果如下: 2.算法涉及理论知识概要基于YOLOv2的细胞检测系统是一种利用深度学习技术,特别是卷积神经网络(CNN),对显微镜图像中的细胞进行自动定位和识别的计算机视觉应用。YOLO(You Only Look Once)是一种单阶段的目标检测算法,其第二版…

数模 初见数建

文章目录 初见数学建模1.1 数学建模是什么1.2 数学建模的概述1.3 如何学习数学建模---分模块化1.4 数学建模前提了解1.5 数学建模的六个步骤1.6 如何备战建模比赛1.7 数学建模赛题类型1.8 数学建模算法体系概述 初见数学建模 1.1 数学建模是什么 1.原型与模型 原型&#xff…

使用FastDDS编译IDL文件

1.安装FastDDS环境 Ubuntu22.04 1.1安装依赖的软件 sudo apt-get update //基础工具安装 sudo apt install cmake g python3-pip wget git //Asio 是一个用于网络和低级 I/O 编程的跨平台C库&#xff0c;它提供了一致的 异步模型。 TinyXML2是一个简单&#xff0c;小巧&…

audition 音频 声音 变慢 减速 增加响度 增大音量

audition 音频 声音 变慢 减速 增加响度 增大音量 我这里audition版本是cs6 减速减速的 那个算法 选右边的选项,要不效果不好 减速的 那个算法 选右边的选项,要不效果不好 减速的 那个算法 选右边的选项,要不效果不好增大响度 显示窗口完工~-------------------------------…

4-02. 实现跟随游戏时间触发切换场景光效

修改 Settings修改 TimeManager修改 EventHandler修改 TimeManager修改 LightManager修改 LightControl修改 LightManager修改 LightControl修改 TimeManager给门灯添加 LightControl添加 LightPattern并把它拖动给 Light2D下面那个灯也要拷贝相同的 Light Control 组件 项目相…

Day91:API攻防-接口安全SOAPOpenAPIRESTful分类特征导入项目联动检测

目录 API分类特征-SOAP&OpenAPI&RESTful API分类特征 API常见漏洞 API检测流程 API检测项目-Postman&APIKit&XRAY 工具自动化-SOAP - WSDL Postman 联动burpxray APIKit插件(可联动xray) 工具自动化-OpenApi - Swagger Postman 联动burpxray APIKit…

RabbitMQ交换机的类型

交换机类型 可以看到&#xff0c;在订阅模型中&#xff0c;多了一个exchange角色&#xff0c;而且过程略有变化&#xff1a; Publisher&#xff1a;生产者&#xff0c;不再发送消息到队列中&#xff0c;而是发给交换机 Exchange&#xff1a;交换机&#xff0c;一方面&#xff…

vs2019 - detected memory leak

文章目录 vs2019 - detected memory leak概述笔记vs2019 consolevs2019 MFC Dlg但是&#xff0c;工程大了之后&#xff0c;VS2019提示的就变了样整好的内存泄漏侦测头文件和实现my_debug_new_define.hmy_debug_new_define.cpp在所有.cpp文件入口处包含my_debug_new_define.h包含…

[蓝桥杯 2018 国 C] 迷宫与陷阱

题目链接&#xff1a;迷宫与陷阱 这道题目跟我们平时做的bfs不同的是 多了一个“无敌状态” 那么也就需要我们去比较有无敌状态经过陷阱和不走陷阱的最少的步数。 先说说我之前的思路吧&#xff1a; 开一个vis[N][N]表示走到&#xff08;x,y) 这个点所需最小的步数&#xff…

wps使用Latex编辑公式没有Latex formula

wps使用Latex编辑公式没有Latex formula 1. 下载CTEX2. 下载LaTeXEE3. 配置Miktex4. 配置latexee5. 用管理员权限运行latexeqedit.exe6. wps插入latex公式 1. 下载CTEX 下载CTEX网址&#xff0c;我下载的下图这个&#xff0c;下载完了之后运行exe文件安装ctex。 2. 下载LaTe…