zoukankan      html  css  js  c++  java
  • C和指针 第十三章 高级指针话题

    高级声明:

    int (*f)();
    

    这里声明有两个括号,第二个括号是函数调用,第一个括号是聚组作用。(*f)是一个函数,所以f是指向返回整型的函数的指针。程序中的每个函数都位于,内存中某个位置,所以存在指向那个位置的指针。

    int *f[];
    

    下标的优先级高,所以f是个数组,数组中元素为指向int的指针。

    int (*f[])()
    

    首先按照优先级进行分析,括号内(*f[])先求值,所以*f[], f是数组,数组元素是指向某种类型的指针,结合外面的看,f是一个数组,数组元素是指向返回int类型的函数的指针。

    函数指针:

    指针在使用前需要进行初始化,对于函数指针,访问前需要初始化为指向摸个函数。

    int fuc(int);
    
    int (*fPtr)(int) = &fuc;
    //在函数初始化之前需要具有fuc的原型,否则,编译器无法检查fuc的类型是否与fPtr一致。
    

    初始表达式中的&操作符是可选的,因为函数名被使用时,总是由编译器把它转换为函数指针,&操作符只是显示的说明了编译器将隐式执行任务。

    函数指针被声明后有三种方式调用函数:

    int result;
    
    result = func(25);
    result = (*fPtr)(25);
    result = fPtr(25);
    

    第一种方法,直接调用,执行时函数名首先被转换成一个函数指针,该指针指向函数在内存中的位置。然后,函数调用操作符调用该函数,执行位于这个地址的代码

    第二种方法,先间接访问,把函数指针转换成函数名,这个转换时不必要的,执行时还会像第一种方法一样被转换到函数指针。

    第三种方法,间接访问时不必要的,编译器需要的是一个函数指针,这里直接使用函数指针。

    函数指针也可以作为值,传入其他函数,叫做回调函数。例如下面的类型无关的链表查询函数。

    #include <stdio.h>
    
    typedef struct Node {
        struct Node *next;
        int value;
    }Node;
    
    /*
     * 这里值以及比较函数均是void类型,需要在使用时根据类型自己进行转换
     * */
    Node *search_list(Node *root, void const *value, int (*compare)(void const *, void const *))
    {
        Node *current = root;
        while(current != NULL){
            //回调函数进行比较
            if(compare(&current -> value, value) == 0){
                break;
            }
            current = current -> next;
        }
    
        return current;
    }
    //声明为void *类型,和compare保持一致
    int int_compare(void const *num1, void const * num2){
        //根据类型进行转换
        if(*(int *)num1 == *(int *)num2){
            return 0;
        }else {
            return 1;
        }
    }
    
    int main()
    {
        Node third = {NULL, 3};
        Node second = {&third, 2};
        Node first = {&second, 1};
        int target = 2;
    
        Node *result = search_list(&first, &target, int_compare);
        
        if(result == NULL){
            printf("No Found
    ");
        }else{
            printf("got it: %d", result -> value);
        }
    
        return 0;
    }
    

    运行:

    如果希望在value为字符的链表中查找,只需要将比较函数改为字符类型既可以。

    指针数组的第二个应用就是转移表:

    #include <stdio.h>
    
    double add(double, double);
    double sub(double, double);
    double mul(double, double);
    double div(double, double);
    
    //转移表中保存函数的指针,确保指针类型相同
    double (*transTable[])(double, double) = {add, sub, mul, div};
    
    int main()
    {
        printf("%g
    ", transTable[0](1, 1));
        printf("%g
    ", transTable[1](2, 1));
        printf("%g
    ", transTable[2](3, 5));
        printf("%g
    ", transTable[3](4, 3));
    
        return 0;
    }
    
    double add(double a, double b)
    {
        return a + b;
    }
    
    double sub(double a, double b)
    {
        return a - b;
    }
    
    double mul(double a, double b)
    {
        return a * b;
    }
    
    double div(double a, double b)
    {
        return a / b;
    }
    

    运行结果:

    要注意转移表使用时,越界访问。

    命令行参数:

    命令行参数是指向指针的指针的另一个用武之地,参数传给C程序main时包含两个形参,argc和argv,argc是命令行参数的数目,argv是保存参数指针的数组。第一个是指向程序名称,末尾是一个NULL指针。

    #include <stdio.h>
    
    int main(int argc, char **argv)
    {
        int count = argc;
        printf("count: %d
    ", count);
    
        for(int idx = 0; idx < count; idx++)
        {
            printf("[%s]
    ", argv[idx]);
        }
    
        return 0;
    }

    编译选项添加两个参数

    运行结果:

    字符串常量:

    字符串常量出现于表达式中,它的值是一个指针常量,编译器把这些指定字符拷贝一份储存在内存的某个位置,并储存一个指向第一个字符的指针。我们可以对他进行下标引用。

    char *ch = "abcd"  + 1;
    

    ch为指向b的指针。可以把字符串常量和数组名一样看待。

  • 相关阅读:
    来自1068
    耻辱的时间戳(笑哭)
    依然排序
    呵呵
    好吧,第二篇
    来自机房的第一篇博客
    Shader-水流效果
    unity中虚拟摇杆的实现
    (转载)Unity3d中的属性(Attributes)整理
    C#冒泡排序法及优化
  • 原文地址:https://www.cnblogs.com/yangxunwu1992/p/5854262.html
Copyright © 2011-2022 走看看