当罗密欧遇到朱丽叶... ...当指针遇到数组

题目是扯淡. 无视

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

当罗密欧遇到朱丽叶的时候, 看官们都很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\n", (**a)[0], (**a)[1]);
    printf("%d:%d\n", (**b)[0], (**b)[1]);
    printf("%d:%d\n", (**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\n", &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\n", &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\n", p_array, *p_array);

    return 0;
}

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

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

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

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

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

时间: 2024-07-28 18:06:13

当罗密欧遇到朱丽叶... ...当指针遇到数组的相关文章

指针和数组

指针的几个要点: 一 指针的定义,赋值 要区分: int a; int *p = &a; 这是定义的时候初始化,即赋值 ======================= int a; int *p; p = &a; 定义,初始化分开,  就这里我迷惑了好久 ========================== 多个(修饰符)修饰变量,看变量名先和谁结合(先看后缀)(ps:符号和变量之间的空格不要计算,和距离无关 int*和int *....... int * p [5]    先和[ ]结合

C---通过指针访问数组

C语言规定:如果指针变量P已指向数组中的一个元素,则P+1指向同一数组中的下一个元素. 引入指针变量后,就可以用俩种方法来访问数组元素了. 如果p的初值为&a[0],则: P+i 和a+i 就是a[i]的地址,或者说它们指向a数组的第i个元素. *(p+i)或*(a+i)就是p+i或a+i所指向的数组元素,即a[i].例如,*(p+5)或*(a+5)就是a[5]. 指向数组的指针变量也可以带下标,如p[i]与*(p+i)等价. 根据以上叙述,引用一个数组元素可以用: 1.下标法:即用a[i]形式

指针、数组的理解与关系

一.指针的本质:变量,指针变量就是指针变量int *p:两个变量,一个p(指针变量本身)是int *类型的 另一个是*p(指针指向的那个变量)是int类型的注:指针说白了就是指针类型,前面定义的int类型是为了说明指针指向的那个数的类型,所以指针的解析方式都是按地址来解析的(不管你是char *还是double *,解析方式都是地址)而指向的那个数的类型就要看你怎么定义的了例如:int *aa是按照地址来解析的:*a则是按照int类型来解析的. (1)所有的类型的数据存储在内存中,都是按照二进制

程序设计基石与实践之C语言指针和数组基础

英文出处:Dennis Kubes:  <Basics of Pointers and Arrays in C>. 关于C语言中指针和数组的争论就像是一场恶战.一方面,有些人觉得,所有人都必须承认指针与数组是不同的.而另一些人则认为数组被当成指针来处理,因此它们不应该有什么区别.这种现象让人迷惑.然而,这两种说法其实都是正确的. 数组不是指针,指针也不能说是数组.在C语言中,指针仅在内存中代表一个地址,而数组是许多连续的内存块,多个类型相似的元素存储在其中.更深入的解释,请参考我之前的博文&l

C语言--&gt;(十一)指针于数组

知识点: • 指针与变量 (指向变量的指针)• 指针与函数 (地址传递) • 指针与数组 (指向数组的指针) • 指针与字符串 =================================数组的指针 1.什么是数组指针 1)数组的指针是指数组在内存的的起始位置 2)数组的第一个元素和数组的起始地址一致 2.数组名的本质 1)数组名本质上是一个地址常量,代表的是数组的首地址也就是第一个元素的地址 数组名表示表示数组的起始地址,不表示整个数组,不能对数组整体赋值. 3.数组名为一个指针常量,可

指针的数组

前言:上一篇,提到了栈和堆,想必你也清楚了栈和堆的区别,现在 通过指针的数组来看一下,指针是如何操作栈和堆的. 栈里面的数组: <span style="font-size:18px;"> int a[10]; //这个空间实在栈内存中申请的 int *p =NULL: p =a; //a是数组的首地住所以可以直接赋值给指针p p[0]=10; //就等同于a[0]=10;</span> 这个是堆里面的数组: <span style="font-

转: 浅谈C/C++中的指针和数组(二)

转自:http://www.cnblogs.com/dolphin0520/archive/2011/11/09/2242419.html 浅谈C/C++中的指针和数组(二) 前面已经讨论了指针和数组的一些区别,然而在某些情况下,指针和数组是等同的,下面讨论一下什么时候指针和数组是相同的. C语言标准对此作了说明: 规则1:表达式中的数组名被编译器当做一个指向该数组第一个元素的指针: 注:下面几种情况例外 1)数组名作为sizeof的操作数 2)使用&取数组的地址 规则2:下标总是与指针的偏移量

转:浅谈C/C++中的指针和数组(一)

转自:http://www.cnblogs.com/dolphin0520/archive/2011/11/09/2242138.html 浅谈C/C++中的指针和数组(一) 指针是C/C++的精华,而指针和数组又是一对欢喜冤家,很多时候我们并不能很好的区分指针和数组,对于刚毕业的计算机系的本科生很少有人能够熟练掌握指针以及数组的用法和区别.造成这种原因可能跟现在大学教学以及现在市面上流行的很多C或者C++教程有关,这些教程虽然通俗易懂,但是在很多关键性的地方却避而不谈或者根本阐述不清楚,甚至很

1、打印二进制机器码,程序内存分析,大端序小端序,指针数组,数组指针,数组的三种访问方式,typedef,#if-0-#endif,求数组大小,括号表达式

 1.打印二进制机器码(分别表示32位的和64位的) #include <stdio.h> /*按照8位的长度打印一个数值*/ void dis8bit(char val) { int bit = 8; while(bit--) { if(1<<bit&val){ printf("1"); } else { printf("0"); } if(!(bit%4)) printf(" "); } putchar(1