《C和指针》笔记(十)-- 高级指针

C/C++ 笔记

QQ : 1841545843
邮箱 : [email protected]

  1. 收集各种各样涉及指针的技巧
int (*f)()          // 函数指针
int *(*f)()         // 函数指针,返回值为int*
int *f[]            // f是一个数组, 元素类型是指向整型的指针
int (*f[])()        // 首先f是一个数组,其中的元素是某种类型的指针,最后函数调用符,所以f是一个数组,数组元素是函数指针,返回值是一个int

  1. 指向指针的指针

  2. 函数指针

    函数指针最常见的两个用途,转换表和作为参数传递给另一个函数。

    int f(int);
    // &不是必须的,可选的
    int (*pf)(int) = &f;
    
    // 调用
    // 通过f函数名调用函数,实质上f首先被转换为一个函数指针,该指针指向函数在内存中的位置,然后函数调用操作符调用该函数,执行开始于这个地址的代码
    int ans = f(25);
    // 将函数指针转换为函数名, 但是这种转换是不必要的,在编译器执行函数调用操作符之前又转换回函数指针
    ans = (*pf)(25);
    // 简介访问操作符为非必须, 因为编译器只需要一个函数指针
    ans = pf(25);
    
    • 回调函数

    比较list表中两个值,实现方式:调用者编写一个函数用于比较两个值,然后把一个指向这个函数的指针作为参数传递给查找函数,然后查找函数调用这个比较函数来进行比较。用户把一个函数指针作为参数传递给其他函数,后者将“回调用户的函数”。不确定类型全部声明为void*,一个指向未知类型的指针。

    // 查找函数
    #include 
    #include "node.h"
    
    Node* search_list(Node* node, void const *value, int (*compare)(void const * , void const * ))
    {
        while(node != NULL)
        {
            if (compare(&node->value, value) == 0)
            {
                break;
            	node = node->link;
            }
            
            return node;
        }
    }
    
    // 定义一个整数比较
    // 在这里做一个约定,相等返回0, 不相等返回非零, 这样就可以与标准库中的函数使用相兼容(小于返回负数, 相等为0, 大于返回正数)
    int compare_list (void const* a, void const* b)
    {
        if (*(int*)a == *(int*)b)        // 强制转换为整型
        {
            return 0;
        }
        else
        {
            return 1;
        }
    }
    
    // 使用
    desired_node = search_lis(root, &desired_node, cmpare_list);   // 使用时只需要传入函数名,不需要传参数,是在 if (compare(&node->value, value) == 0)这确定了参数使用的是哪个
    
  3. 转移表

    先看一个例子

    // 读入两个操作数, 一个操作符
    
    ...
    
    switch (opt)
    {
        case ADD:
        result = add(op1, op2);
        break;
        
        case SUB:
        result = sub(op1, op2);
        break;
        
        ....      /// 非常多
        
    }
    
    ···
    

    设计思想:把具体操作和选择操作的代码分开是一种良好的设计方案。

    转换表就是一个函数指针数组:

    创建一个转换表需要两个步骤:声明并初始化一个函数指针数组,函数的原型出现在数组声明之前

    double add(double, double);
    double sub(double, double);
    .....
    
    double (*oper_func[])(double, double) = {
        add,
        sub,
        ......
    };
    

    然后使用下面这条语句替换整个switch

    result = oper_func[oper](op1, op2);  // 操作符具体实现在别的地方实现
    

    oper从数组中选择正确的函数指针,而函数调用操作符将执行这个函数u

  4. 命令行参数

    int main (int argc, char **argv)
    {
        
    }
    
    /*
    ** argc 表示命令行参数的数目,
    ** argv 指向一组参数值,指向这组参数值得第一个元素这些元素的每个都指向一个参数文本的指针。指向字符的指针的指针。
    ** 如果程序需要访问命令行参数,main函数在声明的时候就要加上这些参数
    ** 这个数组的每个元素都是一个字符指针, 数组的末尾是一个NULL指针
    ** 第一个参数就是程序的名称
    */
    
    // 打印所有的参数
    
    
    // 打印所有的参数
    // 跳过程序名
    
    #include 
    #include 
    
    int main(int argc, char** argv)
    {
        // 打印参数,直到遇到NULL
        while (*++argv != NULL)
        {
            printf("%s \n", *argv); // printf 参数 %s 要求为一个指向字符的指针
            
        }
        return EXIT_SUCCESS;
    }
    
    
    // 处理命令行参数
    // 命令行为: rpog -a -b -c name1 name2 name3
    // 每个选项都是以 - 开头,后面是一个字母,每的文件名以何种方式进行处理,如果没有文件名,就对标准输入进行处理
    // 主要工作是区分选项参数和文件名参数
    
    #include 
    #define TRUE 1
    #define FALSE 0
    
    // 执行实际任务的函数原型
    void process_standard_input (void);
    void process_file(char* file_name);
    
    // 选项标志,缺省初始化为FALSE
    int option_a, option_b;
    
    void main(int argc, char** argv)
    {
        // 处理选项参数,跳到下一个参数,并检查它是否以一个横杠开头
        while (*++argv != NULL && **argv == '-')
        {
            // 检查横杠后面的字母
            switch (*++*argv)
            {
                case 'a':
                    option_a = TRUE;
                    break;
                    
                case 'b':
                    option_b = TRUE;
                    break;
            }
        }
        
        // 处理文件名参数
        if (*argv == NULL)  // 没有文件名, 对标准输入进行处理
        {
            process_standard_input();
        }
        else   // 有文件名
        {
            do 
            {
                process_file(*argv);
            }
            while(*++argv != NULL);
        }
    }
    
    // 总结:
    // 双重间接访问操作访问第一个字符
    // 测试**argv之前先测试*argv是非常有必要的
    
    // 对于一个 - 后放多个参数的
    // prog -abc name1 name2
    
    // 循环
    while (( opt = *++*argv) != '\0')
    {
        switch (opt)
        {
            case 'a':
                optin_a = TRUE;
                break;
        }
    }
    
  5. 字符串常量

    字符串常量出现在程序中时,它的值是个指针常量,

你可能感兴趣的:(C++)