函数指针;回调函数; 预处理;静态库、动态库;递归函数;面向接口编程

 函数指针

复制代码
函数指针

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

void func(int a ,char c)
{
    printf("hello world\n");
}

void test01()
{
    //1、先定义出函数类型,再通过类型定义函数指针
    typedef void(FUNC_TYPE)(int, char);

    FUNC_TYPE * pFunc = func;
    //pFunc(10, 'a');

    //2、定义出函数指针类型,通过类型定义函数指针变量
    typedef void( * FUNC_TYPE2)(int, char);

    FUNC_TYPE2 pFunc2 = func;
    //pFunc2(20, 'b');

    //3、直接定义函数指针变量
    void(*pFunc3)(int, char) = func;
    pFunc3(30, 'c');
}
函数指针
复制代码
函数指针 和 指针函数 区别:
    函数指针:这是一个指针,是指向了函数的指针
    指针函数:这时一个函数,函数返回值是指针
函数指针 和 指针函数 区别
复制代码
函数指针的数组
void func1()
{
    printf("func1 调用了\n");
}

void func2()
{
    printf("func2 调用了\n");
}

void func3()
{
    printf("func3 调用了\n");
}

void test02()
{
    void(*pArray[3])(); 

    pArray[0] = func1;
    pArray[1] = func2;
    pArray[2] = func3;

    for (int i = 0; i < 3;i++)
    {
        pArray[i]();
    }
}

int main(){
    //test01();
    test02();

    system("pause");
    return EXIT_SUCCESS;
}
函数指针的数组
复制代码

回调函数

回调函数:函数指针作为函数参数

复制代码
回调函数示例
========================================================
//提供一个打印函数,可以打印任意类型的数据
void printText( void * data , void(*myPrint)(void *) )
{
    myPrint(data);
}

void myPrintInt(void * data)
{
    int * num = data;
    printf("%d\n", *num);
}

//------------------------------------------------------
struct Person
{
    char name[64];
    int age;
};

void myPrintPerson(void * data)
{
    struct Person * p = data;
    printf("姓名: %s 年龄: %d\n", p->name, p->age);
}

//------------------------------------------------------
int main(){
    int a = 10;
    printText(&a, myPrintInt);  //回调函数,手动传入函数指针
    //------------------------------------------------------
    struct Person p = { "Tom", 18 };
    printText(&p, myPrintPerson);   //打印了另一种类型
    
    
    system("pause");
    return EXIT_SUCCESS;
}
回调函数示例
复制代码
复制代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h> 
#include <math.h> 
#include <time.h> 

//提供一个函数,实现对任意类型的数组进行排序,排序规则利用选择排序,排序的顺序 用户可以自己指定
void sort_int_arr(void* arr,int size,int arr_len) {
    //使用选择排序
    int min;
    int tmp;
    for (int i = 0; i < arr_len; i++)
    {
        min = i;
        for (int j = 1; j + i < arr_len; j++)       //循环获取最小下标
        {
            if (*((int*)arr + min) > *((int*)arr + i + j))
            {
                min = i + j;
            }
        }
        if (min != i)                               //如果当前下标的数有变化,那么说明不是最小数,需要进行交换
        {
            tmp = *((int*)arr + i);
            *((int*)arr + i) = *((int*)arr + min);
            *((int*)arr + min) = tmp;
        }
    }
}
void sort_double_arr(void* arr, int size, int arr_len) {    //其实和sort_int_arr是基本相同的,完全是可以写在同一个函数里的;这里只是为了展示回调函数的功能,特别写成了2个函数
    //使用选择排序
    int min;
    int tmp;
    for (int i = 0; i < arr_len; i++)
    {
        min = i;
        for (int j = 1; j + i < arr_len; j++)       //循环获取最小下标
        {
            if (*((double*)arr + min) > *((double*)arr + i + j))
            {
                min = i + j;
            }
        }
        if (min != i)                               //如果当前下标的数有变化,那么说明不是最小数,需要进行交换
        {
            tmp = *((double*)arr + i);
            *((double*)arr + i) = *((double*)arr + min);
            *((double*)arr + min) = tmp;
        }
    }
}


void my_sort_array(void (*my_sort_arr)(void* arr, int size, int arr_len), int arr[], int size, int arr_len) {
    my_sort_arr(arr,size,arr_len);
}

int main() {
    int arr[] = { 444,555,999,53523,4327948,33,4 };
    int size = 4;
    int arr_len = sizeof(arr) / size;
    printf("排序前:");
    for (size_t i = 0; i < arr_len; i++)
    {
        printf("%d\t",arr[i]);
    }
    printf("\n");
    my_sort_array(sort_int_arr,arr,size,arr_len);//对int类型数组进行排序
    printf("排序后:");
    for (size_t i = 0; i < arr_len; i++)
    {
        printf("%d\t", arr[i]);
    }
    printf("\n");
    //-------------------------------------------------
    double arr2[] = {1111111.3,2222.2,200,500,333.333,9666.345566};
    int size2 = 8;
    int arr_len2 = sizeof(arr2) / size2;
    printf("排序前:");
    for (size_t i = 0; i < arr_len2; i++)
    {
        printf("%lf\t", arr2[i]);
    }
    printf("\n");
    my_sort_array(sort_double_arr, arr2, size2, arr_len2);//对double类型数组进行排序
    printf("排序后:");
    for (size_t i = 0; i < arr_len2; i++)
    {
        printf("%lf\t", arr2[i]);
    }
    printf("\n");


    system("pause");
    return EXIT_SUCCESS;
}
回调函数示例2:提供一个函数,实现对任意类型的数组进行排序,排序规则利用选择排序,排序的顺序 用户可以自己指定
复制代码

 预处理

复制代码
include;宏定义;条件编译;一些特殊的预定宏
===================================================================================
C语言对源程序处理的四个步骤:预处理、编译、汇编、链接。
预处理是在程序源代码被编译之前,由预处理器(Preprocessor)对程序源代码进行的处理。
    预处理阶段会将#include、宏定义等进行展开,即将import头文件内所有内容、展开宏定义
#include <>常用于包含库函数的头文件;
#include ""常用于包含自定义的头文件;

-------------------------------------------------------------------------------------
宏展开:在预编译时将宏名替换成字符串的过程
宏定义
    宏定义,只在宏定义的文件中起作用。
    说明:
        1)    宏名一般用大写,以便于与变量区别;
        2)    宏定义可以是常数、表达式等;
        3)    宏定义不作语法检查,只有在编译被宏展开后的源程序才会报错;
        4)    宏定义不是C语言,不在行末加分号;
        5)    宏名有效范围为从定义到本源文件结束;
        6)    可以用#undef命令终止宏定义的作用域;
        7)    在宏定义中,可以引用已定义的宏名;

无参数的宏定义(宏常量)
    #define NUM 100     //在编译预处理时,将程序中在该语句以后出现的所有的num都用100代替。

带参数的宏定义(宏函数)
    在项目中,经常把一些短小而又频繁使用的函数写成宏函数,这是由于宏函数没有普通函数参数压栈、跳转、返回等的开销,可以调高程序的效率。
    #define SUM(x,y) (( x )+( y ))
    注意:
        1)    宏的名字中不能有空格,但是在替换的字符串中可以有空格。ANSI C允许在参数列表中使用空格;
        2)    用括号括住每一个参数,并括住宏的整体定义。
        3)    用大写字母表示宏的函数名。
        4)    如果打算宏代替函数来加快程序运行速度。假如在程序中只使用一次宏对程序的运行时间没有太大提高。


===================================================================================
条件编译
测试存在:
#ifdef 标识符
    程序段1
#else
    程序段2
#endif
-------------------------------
测试不存在
#ifndef 标识符
    程序段1
#else
    程序段2
#endif
--------------------------------
根据表达式定义
#if 表达式
    程序段1
#else
    程序段2
#endif

----------------------------------------------------------------------------------------------
一些特殊的预定宏
C编译器,提供了几个特殊形式的预定义宏,在实际编程中可以直接使用,很方便。
//    __FILE__            宏所在文件的源文件名 
//    __LINE__            宏所在行的行号
//    __DATE__            代码编译的日期
//    __TIME__            代码编译的时间
include;宏定义;条件编译;一些特殊的预定宏
复制代码

静态库、动态库

复制代码
静态库配置、使用;动态库配置、使用
====================================================================================================
静态库、动态库
库是已经写好的、成熟的、可复用的代码。每个程序都需要依赖很多底层库,不可能每个人的代码从零开始编写代码,因此库的存在具有非常重要的意义。
在我们的开发的应用中经常有一些公共代码是需要反复使用的,就把这些代码编译为库文件。

----------------------------------------------------------------------------------------
静态库配置:
    1.配置过程其实和写C项目大体上是相同的,也需要些.h和.c文件
    2.生成项目时,生成.lib文件
    3.将.lib、.h文件交给用户,即放在用户编写的C项目中(这个.h文件仅仅只是相当于一个说明文件)
    4.用户将自己的C项目生成exe后,该exe可以独立运行(.lib文件的内容已经被打包进exe)

-----------------------------------------------------------------------------------------
动态库配置:
    1.配置过程其实和写C项目大体上是相同的,也需要些.h和.c文件
    2.生成项目时,生成.lib文件、.dll文件
        .lib文件和静态库.lib文件不同:动态库的.lib文件只会放变量的声明和导出函数的声明;函数实现提放在.dll文件中
    3.将.lib文件、.dll文件、.h文件交给用户,即放在用户编写的C项目中(这个.h文件仅仅只是相当于一个说明文件)
    4.用户将自己的C项目生成exe后,该exe不能独立运行(因为依赖.dll文件)

    #C高级编程讲义.doc
    02.C语言高级编程--》C高级编程day07
静态库配置、使用;动态库配置、使用
复制代码

递归函数

C通过运行时堆栈来支持递归函数的实现。递归函数就是直接或间接调用自身的函数。

面向接口编程

 C高级编程讲义.doc

posted @   雲淡風輕333  阅读(43)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示