C语言_指针进阶(下)

news2024/11/24 14:09:23

文章目录

  • 前言
  • 一、函数指针数组
  • 二、指向函数指针数组的指针
  • 三. 回调函数
  • 四. qsort 函数
  • 五. 数组名的理解 sizeof
    • 5.1 数组名的理解(二维数组)
      • 5.1.1 数组名的理解 strlen
      • 5.1.2 例题:
        • 例一.
        • 例二.
        • 例三.
        • 例四.


前言


一、函数指针数组

数组是一个存放相同类型数据的存储空间,
那把函数的地址存放到一个数组中,那这个数组就叫函数指针数组
提示:以下是代码样例,下面案例可供参考

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()
{
    printf("************************\n");
    printf("*****1. Add 2. Sub *****\n");
    printf("*****3. Mul 4. Div *****\n");
    printf("*****  0. exit  ********\n");
    printf("************************\n");
}

int main()
{
    int x = 0;
    int y = 0;
    int ret = 0;
    int input = 0;
    //定义一个函数指针数组
    int (*pfArr[5])(int, int) = { NULL,Add,Sub,Mul,Div };
    //                             0     1   2   3   4
    do
    {
        menu();
        printf("请选择:>\n");
        scanf("%d", &input);
        if (input >= 1 && input <= 4)
        {
            printf("请输入两个操作数:");
            scanf("%d %d", &x, &y);
            ret = pfArr[input](x, y);
            printf("ret = %d\n", ret);
        }
        else if (input = 0)
        {
            printf("退出计算器\n");
        }
        else
        {
            printf("选择错误,重新选择\n");
        }
    } while (input);

    return 0;
}

二、指向函数指针数组的指针

三. 回调函数

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

四. qsort 函数

qsort 是标准库函数,用于对数组中的元素进行快速排序。它通过比较两个元素的大小来确定它们的顺序。以下是 qsort 函数的定义:

void qsort(void *base, size_t count, size_t size, int (*compare)(const void *, const void *));

参数说明:

  • base:指向要排序的数组的第一个元素的指针。
  • count:要排序的元素数量。
  • size:每个元素的字节数。
  • compare:一个比较函数,用于比较两个元素的大小。该函数返回一个整数值,指示两个元素的顺序关系。如果返回负数,则表示第一个元素应该排在第二个元素的前面;如果返回正数,则表示第一个元素应该排在第二个元素的后面;如果返回 0,则表示两个元素相等。

使用 qsort 函数时,需要自定义一个比较函数,根据实际需要对元素进行比较。以下是一个简单的示例:

#include <stdio.h>
#include <stdlib.h>

int compare(const void *a, const void *b) {
    return (*(int*)a - *(int*)b);
}

int main() {
    int arr[] = {3, 1, 4, 2, 5};
    int n = sizeof(arr) / sizeof(int);

    qsort(arr, n, sizeof(int), compare);

    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

输出结果为:1 2 3 4 5,表示数组已经按从小到大的顺序排好了序。qsort 是标准库函数,用于对数组中的元素进行快速排序。它通过比较两个元素的大小来确定它们的顺序。以下是 qsort 函数的定义:

void qsort(void *base, size_t count, size_t size, int (*compare)(const void *, const void *));

参数说明:

  • base:指向要排序的数组的第一个元素的指针。
  • count:要排序的元素数量。
  • size:每个元素的字节数。
  • compare:一个比较函数,用于比较两个元素的大小。该函数返回一个整数值,指示两个元素的顺序关系。如果返回负数,则表示第一个元素应该排在第二个元素的前面;如果返回正数,则表示第一个元素应该排在第二个元素的后面;如果返回 0,则表示两个元素相等。

使用 qsort 函数时,需要自定义一个比较函数,根据实际需要对元素进行比较。以下是一个简单的示例:

#include <stdio.h>
#include <stdlib.h>

int compare(const void *a, const void *b) {
    return (*(int*)a - *(int*)b);
}

int main() {
    int arr[] = {3, 1, 4, 2, 5};
    int n = sizeof(arr) / sizeof(int);

    qsort(arr, n, sizeof(int), compare);

    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

输出结果为:1 2 3 4 5,表示数组已经按从小到大的顺序排好了序。qsort 是标准库函数,用于对数组中的元素进行快速排序。它通过比较两个元素的大小来确定它们的顺序。以下是 qsort 函数的定义:

void qsort(void *base, size_t count, size_t size, int (*compare)(const void *, const void *));

参数说明:

  • base:指向要排序的数组的第一个元素的指针。
  • count:要排序的元素数量。
  • size:每个元素的字节数。
  • compare:一个比较函数,用于比较两个元素的大小。该函数返回一个整数值,指示两个元素的顺序关系。如果返回负数,则表示第一个元素应该排在第二个元素的前面;如果返回正数,则表示第一个元素应该排在第二个元素的后面;如果返回 0,则表示两个元素相等。

使用 qsort 函数时,需要自定义一个比较函数,根据实际需要对元素进行比较。以下是一个简单的示例:

#include <stdio.h>
#include <stdlib.h>

int compare(const void *a, const void *b) {
    return (*(int*)a - *(int*)b);
}

int main() {
    int arr[] = {3, 1, 4, 2, 5};
    int n = sizeof(arr) / sizeof(int);

    qsort(arr, n, sizeof(int), compare);

    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

输出结果为:1 2 3 4 5,表示数组已经按从小到大的顺序排好了序。

五. 数组名的理解 sizeof

提示:以下是代码样例,下面案例可供参考

char arr[] = "abcdef";//[a b c d e f \0]
 
    printf("%d\n", sizeof(arr));//7
    //char [7]
    printf("%d\n", sizeof(arr + 0));//arr + 0是首元素的地址   4
    printf("%d\n", sizeof(*arr));//*arr其实就是首元素,1个字节   
    //*arr--> *(arr+0) -- arr[0]
    printf("%d\n", sizeof(arr[1]));//arr[1]是第二个元素,1个字节   
    printf("%d\n", sizeof(&arr));//&arr是数组的地址,是地址就是4/8个字节
    printf("%d\n", sizeof(&arr + 1));//&arr + 1是跳过一个数组的地址,4/8
    printf("%d\n", sizeof(&arr[0] + 1));//&arr[0] + 1是第二个元素的地址 4/8

 printf("%d\n", sizeof(p));//p是一个指针变量 大小就是4/8
    printf("%d\n", sizeof(p + 1));//p+1是'b'的地址,是地址大小就是4/8个字节
    
    printf("%d\n", sizeof(*p));//*p 就是'a',就是1个字节
    printf("%d\n", sizeof(p[0]));//p[0]--> *(p+0) --> *p  1个字节

    printf("%d\n", sizeof(&p));//4/8   &p -- char**
    printf("%d\n", sizeof(&p + 1));//4/8
    printf("%d\n", sizeof(&p[0] + 1));//4/8 , &p[0] + 1得到是'b'的地址 

5.1 数组名的理解(二维数组)

5.1.1 数组名的理解 strlen

特点


提示:以下是代码样例,下面案例可供参考

int main()
{
    char arr[] = { 'a','b','c','d','e','f' };
        printf("%d\n", strlen(arr));//因为字符数组arr中没有\0,所以在求字符串长度的时候,会一直往后找,产生的结构就是随机值
        printf("%d\n", strlen(arr + 0));//arr + 0是首元素的地址,和第一个一样,也是随机值
        printf("%d\n", strlen(*arr));//err(错误的写法), arr是数组首元素的地址,*arr就是数组首元素,就是'a'-97
        //strlen函数参数的部分需要传一个地址,当我们传递的是'a'时,'a'的ASCII码值是97,那就是将97作为地址传参
        //strlen就会从97这个地址开始统计字符串长度,这就非法访问内存了
        //printf("%d\n", strlen(arr[1]));//err
        printf("%d\n", strlen(&arr));//&arr是数组的地址,数组的地址和数组首元素的地址,值是一样的,那么传递给strlen函数后,依然是从数组的第一个元素的位置开始往后统计
    
        printf("%d\n", strlen(&arr + 1));//随机值
        printf("%d\n", strlen(&arr[0] + 1));//&arr[0] + 1是第二个元素的地址。结果也是随机值

        return 0;
}
char* p = "abcdef";
        //     012345
        
        printf("%d\n", strlen(p));//6
        printf("%d\n", strlen(p + 1));//5
        //printf("%d\n", strlen(*p));//err
        //printf("%d\n", strlen(p[0]));//err
        printf("%d\n", strlen(&p));//随机值  编译器会随机给他分配地址
        printf("%d\n", strlen(&p + 1));//随机值  &p+1  与  &p  没有差异,没啥关系
        printf("%d\n", strlen(&p[0] + 1));//5

int a[3][4] = { 0 };
    
        printf("%d\n", sizeof(a));//3*4*4 = 48
        printf("%d\n", sizeof(a[0][0]));//4  零行零列的元素
    
        printf("%d\n", sizeof(a[0]));//a[0]是第一行这个一维数组的数组名
        //数组名算是单独放在sizeof内部了,计算的是整个数组的大小,大小是16个字节
    
        printf("%d\n", sizeof(a[0] + 1));//?
        //a[0]作为第一行的数组名,没有单独放在sizeo内部,没有&
        //a[0]表示数组首元素的地址,也就是a[0][0]的地址
        //所以a[0]+1是第一行第二个元素的地址,是地址就是4/8个字节
        
        printf("%d\n", sizeof(*(a[0] + 1)));//4
        //计算的是就是第一行第2个元素的大小
    
        printf("%d\n", sizeof(a + 1));//4 / 8
        //a是数组首元素的地址,是第一行的地址 int(*)[4]
        //a+1 就是第二行的地址
    
        printf("%d\n", sizeof(*(a + 1)));//16
        //*(a+1) --> a[1] -> sizeof(*(a+1))->sizeof(a[1]) 计算的是第二行的大小
        //a+1 --> 是第二行的地址,int(*)[4]
        //*(a+1) 访问的第二行的数组
    
        printf("%d\n", sizeof(&a[0] + 1));//4/8
        //&a[0]是第一行的地址 int(*)[4]
        //&a[0]+1 是第二行的地址 int(*)[4]
    
        printf("%d\n", sizeof(*(&a[0] + 1)));//16 计算的是第二行的大小
    
        printf("%d\n", sizeof(*a));//计算的是第一行的大小-16
        //a是数组首元素的地址,就是第一行的地址
        //*a 就是第一行
        //*a --> *(a+0) --> a[0]
    
        printf("%d\n", sizeof(a[3]));//16
        //a[3]--> int [4]

5.1.2 例题:

例一.

例二.

例三.

例四.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1005775.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LVS负载均衡群集(NAT模式、IP隧道模式、DR模式)

目录 一、集群 1.1 含义即特点 1.2 群集的类型 1.3 LVS 的三种工作模式&#xff1a; 1.4 LVS 调度算法 1.5 负载均衡群集的结构 1.6 ipvsadm 工具 二、NAT模式 LVS-NAT模式配置步骤&#xff1a; 实例&#xff1a; 配置NFS服务器192.168.20.100 配置web1服务器192.168…

C++ istringstream类学习

istringstream类用于执行C风格的串流的输入操作&#xff1b; ostringstream类用于执行C风格的串流的输出操作&#xff1b; strstream类同时可以支持C风格的串流的输入输出操作&#xff1b; istringstream的构造函数原形如下&#xff1a; istringstream::istringstream(strin…

Tomcat Arbitrary Write-file Vulnerability through PUT Method (CVE-2017-12615)

漏洞描述 CVE-2017-12615 对应的漏洞为任意文件写入&#xff0c;由于配置不当&#xff08;非默认配置&#xff09;&#xff0c;导致可以使用 PUT 方法上传任意文件 。Tomcat设置了写权限&#xff08;readonlyfalse&#xff09;&#xff0c;导致可以使用PUT方法上传任意文件 影…

mysql 快速上传数据

快速上传数据 这个应该是比inset into values更快的插入数据的办法了。 不过要求挺苛刻的&#xff0c;数据要整理成和表格一致&#xff0c;也就是说每条数据都是完整的一条&#xff0c;而不是一部分。 下面的示例我以***为分割符划分字段&#xff0c;以 \n来分割每条数据。 LO…

代码随想录笔记--贪心算法篇

1--贪心算法 主要思路&#xff1a; 通过局部最优推导全局最优&#xff1b; 2--分发饼干 主要思路&#xff1a; 基于贪心算法&#xff0c;每次都尽可能用大的饼干去喂胃口大的孩子&#xff0c;贪心地节省饼干&#xff1b; #include <iostream> #include <vector> #i…

5.后端·新建子模块与开发(自动模式)

文章目录 学习资料自动生成模式创建后端三层 学习资料 https://www.bilibili.com/video/BV13g411Y7GS?p11&spm_id_frompageDriver&vd_sourceed09a620bf87401694f763818a31c91e 自动生成模式创建后端三层 首先&#xff0c;运行起来若依的前后端整个项目&#xff0c;…

【Java 基础篇】Java 自然排序:使用 Comparable 接口详解

在 Java 编程中&#xff0c;我们经常需要对对象进行排序。为了实现排序&#xff0c;Java 提供了 java.lang.Comparable 接口&#xff0c;它允许我们定义对象之间的自然顺序。本篇博客将深入探讨如何使用 Comparable 接口来进行自然排序&#xff0c;包括接口的基本概念、使用示例…

【2023年11月第四版教材】第12章《质量管理》(第三部分)

第12章《质量管理》&#xff08;第三部分&#xff09; 5 管理质量5.1 管理质量★★★ &#xff08;17下9&#xff09;5.2 数据分析★★★5.3 数据表现★★★5.4 审计★★★ 6 控制质量6.1 控制质量6.2 数据收集★★★6.3 数据分析 ★★★6.4 数据表现★★★ 5 管理质量 组过程…

《gRPC vs REST:何时选择哪一个》

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f405;&#x1f43e;猫头虎建议程序员必备技术栈一览表&#x1f4d6;&#xff1a; &#x1f6e0;️ 全栈技术 Full Stack: &#x1f4da…

C++--day5

实现一个图形类&#xff08;Shape&#xff09;&#xff0c;包含受保护成员属性&#xff1a;周长、面积&#xff0c; 公共成员函数&#xff1a;特殊成员函数书写 定义一个圆形类&#xff08;Circle&#xff09;&#xff0c;继承自图形类&#xff0c;包含私有属性&#xff1a;半…

Pytorch从零开始实战02

Pytorch从零开始实战——彩色图像识别 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——彩色图像识别环境准备数据集模型选择模型训练数据可视化 环境准备 本文基于Jupyter notebook&#xff0c;使用Python3.8&#xff0c;Pytorch2.0.1cu118…

【大数据】美团 DB 数据同步到数据仓库的架构与实践

美团 DB 数据同步到数据仓库的架构与实践 1.背景2.整体架构3.Binlog 实时采集4.离线还原 MySQL 数据5.Kafka2Hive6.对 Camus 的二次开发7.Checkdone 的检测逻辑8.Merge9.Merge 流程举例10.实践一&#xff1a;分库分表的支持11.实践二&#xff1a;删除事件的支持12.总结与展望 1…

Powdersigner + PostgreSql 同步表结构到pg数据库

要用Powdersigner同步表结构到PostgreSql数据库&#xff0c; Powdersigner 版本是 16.5&#xff0c;当前模型是mysql的 1&#xff0c;修改当前模型内容为postgresql的 Database --> Change Current DBMS 选择PostgreSQL 最大版本的&#xff08;因为Powdersigner内置版本一…

Python3 XML处理模块详解

目录 一&#xff1a;XML文件格式 二&#xff1a;ElementTree解析XML文件 三&#xff1a;Element之查找 四&#xff1a;Element之修改 五&#xff1a;Element之删除 六&#xff1a;Element之增加 xml是一种固有的分层数据格式&#xff0c;最自然的表示方式是解析成树状&am…

基于springboot实现的最便捷的解析word文档

概述 导入excel或word是一些web应用常见的需求&#xff0c;本demo详细介绍怎么导入word,读取word里面的数据 详细 一、运行效果 二、实现过程 ①、首先用maven快速搭建一个spring boot 项目 <properties><project.build.sourceEncoding>UTF-8</project.buil…

unity 使用Photon进行网络同步

Pun使用教程 第一步&#xff1a;请确保使用的 Unity 版本等于或高于 2017.4&#xff08;不建议使用测试版&#xff09;创建一个新项目。 第二步&#xff1a;打开资源商店并找到 PUN 2 资源并下载/安装它。 导入所有资源后&#xff0c;让 Unity 重新编译。 第三步&#xf…

stm32---外部中断

一、EXTI STM32F10x外部中断/事件控制器&#xff08;EXTI&#xff09;包含多达20个用于产生事件/中断请求的边沿检测器。EXTI的每根输入线都可单独进行配置&#xff0c;以选择类型&#xff08;中断或事件&#xff09;和相应的触发事件&#xff08;上升沿触发、下降沿触发…

深入理解JVM虚拟机第四篇:一些常用的JVM虚拟机

一&#xff1a;Sun Classic VM虚拟机 早在1996年Java1.0版本的时候&#xff0c;Sun公司发布了一款名为Sun classic VM的Java虚拟机&#xff0c;它同时也是世界上第一款商用Java虚拟机&#xff0c;JDK1.4时完全被淘汰。 现在hotspot内置了此虚拟机。 这款虚拟机内部只提供解释器…

入门人工智能 ——使用 tensorflow 训练一个新闻分类模型(6)

入门人工智能 ——使用 tensorflow 训练一个新闻分类模型&#xff08;6&#xff09; 入门人工智能 ——使用 tensorflow 训练一个新闻分类模型使用 tensorflow 训练一个新闻分类模型1. 安装TensorFlow和所需的依赖项。2. 打开收集的新闻数据集构建模型模型训练模型评估保存模型…

hadoop启动报错:Attempting to operate on hdfs namenode as root

在hadoop安装路径的 /hadoop/sbin路径下&#xff1a; 将start-dfs.sh&#xff0c;stop-dfs.sh两个文件顶部添加以下参数 #!/usr/bin/env bash HDFS_DATANODE_USERroot HADOOP_SECURE_DN_USERhdfs HDFS_NAMENODE_USERroot HDFS_SECONDARYNAMENODE_USERroot还有&#xff0c;star…