Head First C 笔记 - 高级函数

高级函数

函数指针

继续看例子,这个案例用于给不同的人发送不同的消息。

#include <stdio.h>

enum response_type {
    DUMP, SECOND_CHANGE, MARRAGE
};

typedef struct {
    char *name;
    enum response_type type;
} response;

void dump(response r)
{
    printf("Dear: %s ", r.name);
    puts("dump");
}

void second_change(response r)
{
    printf("Dear: %s ", r.name);
    puts("second_change");
}

void marrage(response r)
{
    printf("Dear: %s ", r.name);
    puts("marrage");
}

void (*replies[])(response) = {dump, second_change, marrage};

int main()
{
    response res[] = {
        {"Mike", DUMP}, {"Tom", SECOND_CHANGE}, {"Jim", MARRAGE}, {"KangKang", SECOND_CHANGE}
    };

    int i;
    int len;

    len = sizeof(res) / sizeof(response); // 计算数组长度
    for (i = 0; i < len; i++) {
        (replies[res[i].type])(res[i]);
        // switch(res[i].type) {
        // case DUMP:
        // dump(res[i]);
        // break;
        // case SECOND_CHANGE:
        // second_change(res[i]);
        // break;
        // default:
        // marrage(res[i]);
        // break;
        // }
    }
    return 0;
}

函数名就是指向函数的指针,但跟指针又不完全相同,在底层,函数名是L-value,指针是R-value。比如:int类型的指针可以表示成int *,但函数指针不能写成function *,因为在C语言中没有函数类型,函数的类型是由参数,返回值这些东西组合定义的。所以函数指针的定义更复杂,如下:

返回类型(*指针变量)(参数类型)

上面案例中最核心的是这样代码:void (*replies[])(response) = {dump, second_change, marrage};,它创建了一个函数指针的数组,优化了后面的switch调用。

排序

#include <stdio.h>
#include <string.h>
#include <stdio.h>

int compare_scores(const void* score_a, const void* score_b)
{
    int a = *(int*)score_a;
    int b = *(int*)score_b;
    return a - b;
}

int compare_names(const void* a, const void* b)
{
    char** sa = (char**)a;
    char** sb = (char**)b;
    return strcmp(*sa, *sb);
}

int main(int argc, char const *argv[])
{
    int scores[] = {2,4,1,9,8};
    int i;
    // 升序
    qsort(scores, 5, sizeof(int), compare_scores);
    for (i = 0; i < 5; i++) {
        printf("%i ", scores[i]);
    }

    // 字典序
    char *names[] = {"Karen", "Mark", "Ada", "Brett"};
    qsort(names, 4, sizeof(char*), compare_names);
    for (i = 0; i < 4; i++) {
        printf("%s ", names[i]);
    }

    return 0;
}

有了函数指针,我们就可以将函数当成参数传递了,qsort()函数用于排序,它会接收一个比较器函数指针,用于判断两个数据的大小。它的定义如下:

qsort(void *array, size_t length, size_t item_size, int (*compare)(const void *, const void *))

最后一个参数是比较器函数指针,注意其中的参数void *可以保存任意类型的指针。

由于比较器的参数类型是void *,所以需要做下类型转换。上面案例中的int a = *(int*)score_a;char** sa = (char**)a;,就是将void指针转换为相应类型的变量,然后再做比较。

可变参数

可变参数函数使用到了标准库中的(预处理会被替换成其他代码),位于stdarg.h中。

#include <stdio.h>
#include <stdarg.h>

void print_ints(int args, ...)
{
    va_list ap;
    va_start(ap, args);
    int i;
    for (int i = 0; i < args; ++i) {
        printf("%i\n", va_arg(ap, int));
    }
    va_end(ap);
}

int main(int argc, char const *argv[])
{
    print_ints(3, 111, 222, 333);
    return 0;
}
  • args报错了参数的数量,va_list用于保存传过来的其他参数
  • va_start说明可变参数从哪里开始
  • va_arg用于读取参数
  • va_end用于销毁va_list

标签: c

添加新评论