您的位置:首页 > 教育 > 锐评 > 网络规划设计师教程第二版_网页设计素材的制作与收集_全世界足球排名国家_抖音流量推广神器软件

网络规划设计师教程第二版_网页设计素材的制作与收集_全世界足球排名国家_抖音流量推广神器软件

2025/8/21 22:04:44 来源:https://blog.csdn.net/weixin_52342399/article/details/144605107  浏览:    关键词:网络规划设计师教程第二版_网页设计素材的制作与收集_全世界足球排名国家_抖音流量推广神器软件
网络规划设计师教程第二版_网页设计素材的制作与收集_全世界足球排名国家_抖音流量推广神器软件

函数指针

函数指针的格式类似这样:

int (*POINTER_NAME)(int a, int b)

值得区别一下三种声明的区别:
1、char *make_coolness(int awesome_levels)
2、char (*make_coolness)(int awesome_levels)
3、char *(*make_coolness)(int awesome_levels)

        第一种是一个普通的函数声明,表示make_coolness是一个函数,它接受一个int类型的参数 awesome_levels,并返回一个char *类型的结果。它的含义是:这是一个函数,能够根据给定的awesome_levels生成并返回一个字符指针。

        第二种是一个函数指针声明,它表示make_coolness是一个指针,指向一个接受int类型参数并返回char类型结果的函数。这意味着make_coolness本身是一个指向函数的指针,而不是直接的函数。

        第三种与第二种类似,区别就是指向函数的返回类型的不同,指向一个接受int类型参数返回char* 类型结果的函数。

函数指针用于传递回调的例子:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>/** Our old friend die from ex17. */
void die(const char *message)
{if(errno) {perror(message);} else {printf("ERROR: %s\n", message);}exit(1);
}// a typedef creates a fake type, in this
// case for a function pointer
typedef int (*compare_cb)(int a, int b);/*** A classic bubble sort function that uses the* compare_cb to do the sorting.*/
int *bubble_sort(int *numbers, int count, compare_cb cmp)
{int temp = 0;int i = 0;int j = 0;int *target = malloc(count * sizeof(int));if(!target) die("Memory error.");memcpy(target, numbers, count * sizeof(int));for(i = 0; i < count; i++) {for(j = 0; j < count - 1; j++) {if(cmp(target[j], target[j+1]) > 0) {temp = target[j+1];target[j+1] = target[j];target[j] = temp;}}}return target;
}int sorted_order(int a, int b)
{return a - b;
}int reverse_order(int a, int b)
{return b - a;
}int strange_order(int a, int b)
{if(a == 0 || b == 0) {return 0;} else {return a % b;}
}/*** Used to test that we are sorting things correctly* by doing the sort and printing it out.*/
void test_sorting(int *numbers, int count, compare_cb cmp)
{int i = 0;int *sorted = bubble_sort(numbers, count, cmp);if(!sorted) die("Failed to sort as requested.");for(i = 0; i < count; i++) {printf("%d ", sorted[i]);}printf("\n");free(sorted);// 打印回调函数的地址unsigned char *data = (unsigned char *)cmp;for(i = 0; i < 25; i++) {printf("%02x:", data[i]);}printf("\n");
}int main(int argc, char *argv[])
{if(argc < 2) die("USAGE: ex18 4 3 1 5 6");int count = argc - 1;int i = 0;char **inputs = argv + 1;int *numbers = malloc(count * sizeof(int));if(!numbers) die("Memory error.");for(i = 0; i < count; i++) {numbers[i] = atoi(inputs[i]);}test_sorting(numbers, count, sorted_order);test_sorting(numbers, count, reverse_order);test_sorting(numbers, count, strange_order);free(numbers);return 0;
}

其中:

typedef int (*compare_cb)(int a, int b);

        只是定义了一个类型 compare_cb,该类型表示指向一个接受两个 int 参数并返回一个 int 的函数的指针。

void test_sorting(int *numbers, int count, compare_cb cmp)
{...
}int *bubble_sort(int *numbers, int count, compare_cb cmp){...
}

        结合typedef传递函数地址,它不会创建新的类型,而是为已经存在的类型提供一个新的名字,简化代码的可读性和可维护性。
例如:

typedef int (*compare_cb)(int a, int b);int ascending(int a, int b) {return a - b;
}int descending(int a, int b) {return b - a;
}int main() {compare_cb cmp = ascending;  // 使用别名声明函数指针printf("%d\n", cmp(3, 2));   // 调用函数
}

typedef语法为:

typedef existing_type new_type_name;
// 可以分离为俩段// 例如:
// example1:
typedef struct {int x;int y;
} Point;Point p1;  // 相当于 struct Point p1;// example2:
typedef int (*compare_cb)(int a, int b);
compare_cb cmp = ascending; 

  • 用十六进制编辑器打开ex18,接着找到函数起始处的十六进制代码序列,看看是否能在原始程序中找到函数。

    使用xxd命令以16进制打印出ex18的机器码内容:
    $ xxd ex18 | grep "..."
  • 在你的十六进制编辑器中找到更多随机出现的东西并修改它们。重新运行你的程序看看发生了什么。字符串是你最容易修改的东西。

    我们找到main函数中的一段字符串进行修改测试:
        if(argc < 2) die("USAGE: ex18 4 3 1 5 6");
    // "USAGE: ex18 4 3 1 5 6"十六进制形式为:55 53 41 47 45 3A 20 65 78 31 38 20 34 20 33 20 31 20 35 20 36 00
    // 找到对应的行内容为 00002040: 3278 3a00 5553 4147 453a 2065 7831 3820  2x:.USAGE: ex18
    用vim编辑器打开并且输入":%!xxd"以16进制显示,然后查找到相应行处:

    我们将USAGE改成小写的usage:
    U  ->  85 (0x55)
    S  ->  83 (0x53)
    A  ->  65 (0x41)
    G  ->  71 (0x47)
    E  ->  69 (0x45)
    改为:
    u  ->  117 (0x75)
    s  ->  115 (0x73)
    a  ->  97  (0x61)
    g  ->  103 (0x67)
    e  ->  101 (0x65)
    
    结果如下:
  • 将错误的函数传给compare_cb,并看看C编辑器会报告什么错误。
  • NULL传给它,看看程序中会发生什么。然后运行Valgrind来看看它会报告什么。
    $ valgrind ./ex18 4 6 7 9 5 3
    ==6470== Memcheck, a memory error detector
    ==6470== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
    ==6470== Using Valgrind-3.24.0 and LibVEX; rerun with -h for copyright info
    ==6470== Command: ./ex18 4 6 7 9 5 3
    ==6470==
    ==6470== Jump to the invalid address stated on the next line
    ==6470==    at 0x0: ???
    ==6470==    by 0x10947E: test_sorting (ex18.c:76)
    ==6470==    by 0x109612: main (ex18.c:113)
    ==6470==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
    ==6470==
    ==6470==
    ==6470== Process terminating with default action of signal 11 (SIGSEGV)
    ==6470==  Bad permissions for mapped region at address 0x0
    ==6470==    at 0x0: ???
    ==6470==    by 0x10947E: test_sorting (ex18.c:76)
    ==6470==    by 0x109612: main (ex18.c:113)
    ==6470==
    ==6470== HEAP SUMMARY:
    ==6470==     in use at exit: 48 bytes in 2 blocks
    ==6470==   total heap usage: 2 allocs, 0 frees, 48 bytes allocated
    ==6470==
    ==6470== LEAK SUMMARY:
    ==6470==    definitely lost: 0 bytes in 0 blocks
    ==6470==    indirectly lost: 0 bytes in 0 blocks
    ==6470==      possibly lost: 0 bytes in 0 blocks
    ==6470==    still reachable: 48 bytes in 2 blocks
    ==6470==         suppressed: 0 bytes in 0 blocks
    ==6470== Rerun with --leak-check=full to see details of leaked memory
    ==6470==
    ==6470== For lists of detected and suppressed errors, rerun with: -s
    ==6470== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
    段错误 (核心已转储)
    

    报告了Jump to the invalid address stated on the next line   at 0x0: ???(提示在程序执行的下一行跳转到了无效的地址)以及 Address 0x0 is not stack'd, malloc'd or (recently) free'd(0x00地址不是栈也不是堆或者最近已经释放的内存地址)、 Bad permissions for mapped region at address 0x0(0x00地址映射区域限权错误)

  • 编写另一个排序算法,修改test_sorting使它接收任意的排序函数和排序函数的比较回调。并使用它来测试两种排序算法。
    /*插入排序算法*/
    int *insertion_sort(int *numbers, int count, compare_cb cmp)
    {int i, j, temp;int *target = malloc(count * sizeof(int));if(!target) die("Memory error.");memcpy(target, numbers, count * sizeof(int));for(i = 1; i < count; i++) {temp = target[i];j = i - 1;while(j >= 0 && cmp(target[j], temp) > 0) {target[j + 1] = target[j];j = j - 1;}target[j + 1] = temp;}return target;
    }// 修改test_sorting函数
    void test_sorting(int *numbers, int count, compare_cb cmp, int *(*sort_function)(int *, int, compare_cb))
    {int i = 0;int *sorted = sort_function(numbers, count, cmp);if(!sorted) die("Failed to sort as requested.");for(i = 0; i < count; i++) {printf("%d ", sorted[i]);}printf("\n");free(sorted);// 打印回调函数的地址unsigned char *data = (unsigned char *)cmp;for(i = 0; i < 25; i++) {printf("%02x:", data[i]);}printf("\n");
    }

    main函数中添加:

        // 测试排序算法printf("Bubble Sort (Sorted Order):\n");test_sorting(numbers, count, sorted_order, bubble_sort);printf("Bubble Sort (Reverse Order):\n");test_sorting(numbers, count, reverse_order, bubble_sort);printf("Bubble Sort (Strange Order):\n");test_sorting(numbers, count, strange_order, bubble_sort);printf("Insertion Sort (Sorted Order):\n");test_sorting(numbers, count, sorted_order, insertion_sort);printf("Insertion Sort (Reverse Order):\n");test_sorting(numbers, count, reverse_order, insertion_sort);printf("Insertion Sort (Strange Order):\n");test_sorting(numbers, count, strange_order, insertion_sort);

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com