zoukankan      html  css  js  c++  java
  • 当罗密欧遇到朱丽叶... ...当指针遇到数组

    题目是扯淡. 无视

    他们说, 题目要长长长长....



    当罗密欧遇到朱丽叶的时候, 看官们都非常happy... 古典唯美悲情爱情嘛~


    然而捏. 数组遇到指针的时候, 我就差点panic了...


    这里特别感谢 @Fantasy @凯旋冲锋 另一起关注问题讨论问题的Essential On Linux的道友们


    事情的起因源于这里的一个hash表的实现,里面用到了二级指针(还有三次解引用...)

    第一感觉不科学, 然后debug, 程序没有挂 ...他竟然没有挂...

    -----------------------------

    看官假设不知道hash表都没有关系, 我们这里只分析C语言的语法问题.

    #include <stdlib.h>
    #define SIZE 1024
    static int (**hnew())[2] {
        return calloc(sizeof(int**), SIZE);
    }
    static void hdel(int (**e)[2]) {
        for (int i = 0; i < SIZE; i++) free(e[i]); free(e);
    }
    static int (**hget(int (**t)[2], int k))[2] {
        for (int h = k & (SIZE - 1); **t && ***t != k; h = ((h + 1) & (SIZE - 1)), t += h);
        return t;
    }
    static void hset(int (**t)[2], int k, int v) {
        for (int (**a)[2] = hget(t, k); !*a && (*a=malloc(sizeof(**t))); (**a)[0]=k,(**a)[1]=v);
    }
    
    // TEST DRIVER
    #include <stdio.h>
    int main() {
        int (**table)[2] = hnew();
    
        hset(table, 10, 20);
        hset(table, 20, 30);
        hset(table, 30, 40);
    
        int (**a)[2] = hget(table, 10);
        int (**b)[2] = hget(table, 20);
        int (**c)[2] = hget(table, 30);
    
        printf("%d:%d
    ", (**a)[0], (**a)[1]);
        printf("%d:%d
    ", (**b)[0], (**b)[1]);
        printf("%d:%d
    ", (**c)[0], (**c)[1]);
    
        hdel(table);
        return 0;
    }
    不得不佩服这样的神人, 对于C语言的掌握差点儿到了出神入化的境地.


    static int (**hnew())[2] {
        return calloc(sizeof(int**), SIZE);
    }
    首先这里构造了一个函数, 来申请内存空间, 并且函数的返回值是一个二级指针

    这个指针一个int数组, static是用来修饰函数的作用域的,把external改动为internal

    作者巧妙的利用了堆上的数据默觉得0

    把calloc申请来的指针所有初始化为0x0000

    在函数内部假设这样写

    static int (**pp_array)[2] = malloc(sizeof(int**) * 13);

    这都是违法的!



    作者则是把它直接作为函数返回值.

    int (**table)[2] = hnew();

    而后又赋值给了int类型的指针( 假设对于数组-指针,指针-数组有困惑的看官能够再翻翻<<C和指针>>这本书,里面有非常具体的辨析).


    之前和数组有关的一些讨论基本上在以下两个link里面:

    <<Do you really master on array ?>>

    数组取地址所数值运算

    话唠继续,

    static int (**hget(int (**t)[2], int k))[2] {
        for (int h = k & (SIZE - 1); **t && ***t != k; h = ((h + 1) & (SIZE - 1)), t += h);
        return t;
    }
    这里对于t的解引用我一度非常不理解.

    可是特殊就特殊在t是指向一个数组的指针.而不是什么别的变量.

    int array[2] = {10, 20};

    int (*p)[2] = array;

    那么p == *p是为真的!!

    看以下的demo:


    #include <stdio.h>
    
    int main()
    {
        int temp[100] = {1000};
    
        int array = {10, 20};
    
        int (*p_array)[2] = array;
    
        printf("&array : 0x%x array:0x%x p_array:0x%x *p_array:0x%x
    ", &array, array,p_array, *p_array);
    
        return 0;
    }



    程序输出如图.

    还有个有意思的现象.这里打印的时候,

    &array : array : p_array : *p_array四个变量

    后面三个变量在数值上,利用printf函数打印时是一样的

    骚安勿躁,假设你认为有什么不科学的话,我也发现了,我们再看另外一个demo:

    唯一的差别就是把p_array初始化的数据由array变成了&array.

    #include <stdio.h>
    
    int main()
    {
        int array = {10, 20};
    
        int (*p_array)[2] = &array;
        //int (*p_array)[2] = array;
    
        printf("&array : 0x%x array:0x%x p_array:0x%x *p_array:0x%x
    ", &array, array,p_array, *p_array);
    
        return 0;
    }



    &array p_array *p_array的值都是数组的地址,

    而仅仅有array是第一个数据的值.

    我printf打印数据的时候是会强制类型转换的.

    所以我这里特意选择了%x,直接解释提供变量地址处的数据的16进制的值.


    千万注意,这里指针表现出来的特性都是指向数组的指针表现出来的.不是常规的指向基础元素的指针.

    以下是个常规指针的demo

    #include <stdio.h>
    
    int main()
    {
        int array[10] = {100};
    
        int *p_array = array;
    
        printf("%x %x
    ", p_array, *p_array);
    
        return 0;
    }

    打印的数据也都不用猜了.


    这里我们讨论所遇到的问题,亦或说指针的特性都是指向数组的指针所遇到的(翻了几本书,这东西都讲得少).


    假设有什么错漏, 或者新发现, 欢迎联系我, 博客随时更新.


    最后,再次向一起讨论问题的道友致谢!



    2015年3月16日, @凯旋冲锋 提出修正. 丢脸(要勇于承认嘛~),static 作用于函数,改动函数的作用域



  • 相关阅读:
    弱鸡儿长乐爆肝旅Day8
    弱鸡儿终于没爆零Day7
    弱鸡儿长乐爆零旅Day6
    弱鸡儿长乐爆零旅Day5
    弱鸡儿长乐爆零旅Day4
    D1字符串哈希
    Tarjan算法
    弱鸡儿长乐爆零旅Day3
    弱鸡儿长乐爆零旅Day2
    弱鸡儿长乐爆零旅Day1
  • 原文地址:https://www.cnblogs.com/wzjhoutai/p/7119702.html
Copyright © 2011-2022 走看看