首页 > 学技术 > 技术网文 > C/C++ > 正文

[原创] [code] C简单实现动态2维数组 :)


来源 chinaunix.net kuqin整理

这也是近期编写 libscws 时用到的一个小功能,动态2维数组。

struct xxx **x;
x = (struct xxx **) darray_new(5, 4, sizeof(struct xxx));

...
这里就可以用 x[1][3]  ... x[0][3] ... 来操作了:)
...

darray_free(x);



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

void **darray_new(int row, int col, int size)
{
void **arr;

arr = (void **) malloc(sizeof(void *) * row + size * row * col);
if (arr != NULL)
{
void *head;

head = (void *) arr + sizeof(void *) * row;
memset(arr, 0, sizeof(void *) * row + size * row * col);
while (row--)
arr[row] = head + size * row * col;
}
return arr;
}

void darray_free(void **arr)
{
if (arr != NULL)
free(arr);
}





 while(1) 回复于:2007-06-08 16:40:27

你是牛人


 doctorjxd 回复于:2007-06-08 17:11:30

libscws 简易中文分词模块?


 yuanchengjun 回复于:2007-06-08 17:12:25

我能想到只能到这个程度,达不到LZ的效果。
int (*ap)[3];
ap = (int (*)[3])malloc(sizeof(int) * 3 * 4);
ap[2][1] = 99;


不过c99里面可以这么干:

int col = 2;
int row = 3;
typedef int tp;

tp (*ap)[row];
ap = (tp (*)[row])malloc(sizeof(tp) * col * row);
ap[0][1] = 9;

[ 本帖最后由 yuanchengjun 于 2007-6-8 18:02 编辑 ]


 nully 回复于:2007-06-08 18:54:51

引用:原帖由 yuanchengjun 于 2007-6-8 17:12 发表
我能想到只能到这个程度,达不到LZ的效果。
int (*ap)[3];
ap = (int (*)[3])malloc(sizeof(int) * 3 * 4);
ap[2][1] = 99;


不过c99里面可以这么干:

int col = 2;
int row = 3;
typedef int tp;

 ... 



何苦呢?

 int a, b;
 scanf("%d %d", &a, &b);
 int x[a];



 hightman 回复于:2007-06-08 19:10:20

引用:原帖由 doctorjxd 于 2007-6-8 17:11 发表
libscws 简易中文分词模块? 



是的. API 说明已经编写完毕,源码整理中待发布...
http://www.hightman.cn/bbs/viewthread.php?tid=37&extra=page%3D1


 ailantian 回复于:2007-06-08 19:16:14

引用:原帖由 nully 于 2007-6-8 18:54 发表


何苦呢?

 int a, b;
 scanf("%d %d", &a, &b);
 int x[a];
 



?这个代码能执行吗,怀疑中。编译一下看看?


 antigloss 回复于:2007-06-08 19:17:27

C99支持


 ailantian 回复于:2007-06-08 19:22:04

引用:原帖由 antigloss 于 2007-6-8 19:17 发表
C99支持 


恩,开始感觉很奇怪,试了一下,是可以的。
:)


 doctorjxd 回复于:2007-06-08 19:28:32

引用:原帖由 hightman 于 2007-6-8 19:10 发表


是的. API 说明已经编写完毕,源码整理中待发布...
http://www.hightman.cn/bbs/viewthread.php?tid=37&extra=page%3D1 



支持楼主!


 飞灰橙 回复于:2007-06-08 22:02:10

楼主的代码是错的,因为在这个函数原型下,不可能写出符合楼主要求的代码。


 飞灰橙 回复于:2007-06-08 22:12:01

引用:原帖由 飞灰橙 于 2007-6-8 22:02 发表
楼主的代码是错的,因为在这个函数原型下,不可能写出符合楼主要求的代码。 



我倒!检讨一下,您的代码没有错,我没看好,
还加了一行sizeof(void *) * row,作为指针数组。
真是个好办法! 赞


 tyc611 回复于:2007-06-09 00:43:20

很不错,赞


 zhangxianxiang 回复于:2007-06-10 10:15:52

问一下,c++中的模板类也是用lz这个思路实现的吗? 大量的使用void*之类的指针吗?


 福瑞哈哥 回复于:2007-06-10 10:29:33

引用:原帖由 zhangxianxiang 于 2007-6-10 10:15 发表
问一下,c++中的模板类也是用lz这个思路实现的吗? 大量的使用void*之类的指针吗? 



模板不使用void *。它使用類型T。


 2eye 回复于:2007-06-10 21:05:29

可否略作解释。
为什么在分配空间时,多加了sizeof(void *) * row?


 hiwoody 回复于:2007-06-11 10:18:00

有教材上有这个做法   早先也写过类似的程序


 zhangxianxiang 回复于:2007-06-11 10:21:25

引用:原帖由 2eye 于 2007-6-10 21:05 发表
可否略作解释。
为什么在分配空间时,多加了sizeof(void *) * row? 



存在指向一维数组的指针,


 sunceenjoy 回复于:2007-06-11 11:38:25

arr[0]表示 所分配内存 的第一个sizeof(void *) 吗?为什么啊


 fdog 回复于:2007-06-11 16:53:14

请教,用下面类似的方法是否通用一些:



int ** array;


array = (int **)malloc(sizeof(int)*one);

for(i=0;i<one;i++)
{
*(array+i)=(int *)malloc(sizeof(int)*two);
}



 ailantian 回复于:2007-06-11 19:28:38

引用:原帖由 fdog 于 2007-6-11 16:53 发表
请教,用下面类似的方法是否通用一些:



int ** array;


array = (int **)malloc(sizeof(int)*one);

for(i=0;i<one;i++)
{
*(array+i)=(int *)malloc(sizeof(int)*two);
}
 



通用?
楼主那个代码要好一些,因为你是用两块分离的内存来存储的,楼主那个是一块内存,
另外楼主那个只需要一个malloc,你的代码也是能用的。看到楼主的代码的时候我也写过你这样的测试代码。
不过感觉没有楼主的好。


 lifanxi 回复于:2007-06-12 01:15:24

引用:原帖由 fdog 于 2007-6-11 16:53 发表
请教,用下面类似的方法是否通用一些:



int ** array;


array = (int **)malloc(sizeof(int)*one);

for(i=0;i<one;i++)
{
*(array+i)=(int *)malloc(sizeof(int)*two);
}
 


这种做法也是很常见的做法,比较直观。但存在的问题就是分配的“二维”数组空间不是连续的,这在很多应用场合会很不方便(比如图像处理)。这种作法相当于C#中的“锯齿”数组,其实它每一维的长度是可以不同的,与“方方正正”的二维数组还是有差别的。


 lonix 回复于:2007-06-12 08:47:51

既然搂主这么写了,也把我的拿出来,参考su的

/* allocate a 2-d array */
void **alloc2 (size_t n1, size_t n2, size_t size)
{
        size_t i2;
        void **p;

        if ((p=(void**)malloc(n2*sizeof(void*)))==NULL)
                return NULL;
        if ((p[0]=(void*)malloc(n2*n1*size))==NULL) {
                free(p);
                return NULL;
        }
        for (i2=0; i2<n2; i2++)
                p[i2] = (char*)p[0]+size*n1*i2;
        return p;
}

/* free a 2-d array */
void free2 (void **p)
{
        free(p[0]);
        free(p);
}


 maths 回复于:2007-06-12 10:51:42

对于"二维"数组p[][N],p[j] = *(p+i*N+j)
所以一维数组就可以当作二维数组来用吧
如:
char (*ptr)[col] = (char (*)[col])malloc(row * col * sizeof(char));
然后就可以直接ptr[j]


 ben1978 回复于:2007-06-12 11:50:17

不解为什么要这样做,能实现relloc才有更大价值


 lengxb 回复于:2007-06-12 14:56:19

内存分配,就只有动态和静态分配两种吧??
操作系统里面最难管理的是内存分配啦


 lengxb 回复于:2007-06-12 14:57:16

比较头疼。呵呵,大家多发这些贴很有用,谢谢


 bleem1998 回复于:2007-06-12 15:27:01


学习了


 from2005on 回复于:2007-06-14 00:20:16

我的水平比较差,哪位能详细解释一下?
1、为什么在分配空间时,多加了sizeof(void *) * row,有什么作用?
2、arr和&arr[0]   应该不相等吧?那如何访问这部分sizeof(void *) * row?


 shihyu 回复于:2007-06-14 07:23:40

请问一下我用 vc2005 编译无法编译过去出现

#include <stdio.h>

#include <stdlib.h>
#include <string.h>

void **darray_new(int row, int col, int size)
{        
        void **arr;

        arr = (void **) malloc(sizeof(void *) * row + size * row * col);
        if (arr != NULL)
        {
                void *head;

                head = (void *) arr + sizeof(void *) * row;
                memset(arr, 0, sizeof(void *) * row + size * row * col);
                while (row--)                
                        arr[row] = head + size * row * col;                
        }
        return arr;
}

void darray_free(void **arr)
{
        if (arr != NULL)
                free(arr);        
}








[color=Blue]head = (void *) arr + sizeof(void *) * row;
arr[row] = head + size * row * col;    [/color]
上面两行编译器出现下面错误讯息 , 请问为什么在vc++ 2005 无法编译过 , 我用gcc 就可以顺利编译成功? 

.\test.c(14) : error C2036: 'void *' : 未知的大小
.\test.c(17) : error C2036: 'void *' : 未知的大小


 太平绅士 回复于:2007-06-14 08:51:09

引用:原帖由 shihyu 于 2007-6-14 07:23 发表
请问一下我用 vc2005 编译无法编译过去出现


head = (void *) ( (size_t) arr + sizeof(void *) * row );



 太平绅士 回复于:2007-06-14 09:07:24

楼主的思想真好,用同样的想法,C实现动态N维数组也是可以的。谁来做这个作业?


 太平绅士 回复于:2007-06-14 09:52:53

引用:原帖由 太平绅士 于 2007-6-14 09:07 发表
楼主的思想真好,用同样的想法,C实现动态N维数组也是可以的。谁来做这个作业? 



:oops:没人响应?看来太平绅士只好自己出题自己做了


 shihyu 回复于:2007-06-14 09:58:06

太平绅士 你好:

head = (void *) ( (size_t) arr + sizeof(void *) * row ); // 可以跟我说一下为何 vc++ 2005 要多加上[color=Blue]() [/color]跟  [color=Blue](size_t)[/color] 才可以 , gcc 为何不需要?

arr[row] = head + size * row * col;      // 这行vc++ 2005 还是出现错误


 shihyu 回复于:2007-06-14 10:00:32

引用:原帖由 from2005on 于 2007-6-14 00:20 发表
我的水平比较差,哪位能详细解释一下?
1、为什么在分配空间时,多加了sizeof(void *) * row,有什么作用?
2、arr和&arr[0]   应该不相等吧?那如何访问这部分sizeof(void *) * row? 




___________________________________________________________________

1 我也想知道

2 arr和&arr[0]  应该不相等

[ 本帖最后由 shihyu 于 2007-6-14 10:31 编辑 ]


 太平绅士 回复于:2007-06-14 10:05:03

引用:原帖由 shihyu 于 2007-6-14 09:58 发表
太平绅士 你好:

head = (void *) ( (size_t) arr + sizeof(void *) * row ); // 可以跟我说一下为何 vc++ 2005 要多加上[color=Blue]() [/color]跟  [color=Blue](size_t)[/color] 才可以 , gcc 为何不需要?
 ... 



这个问题,偶常跟别人说要学会从简单的道理来推理:

1. int *p;   p += 2;
    这时候p的值实际上增加了  2*sizeof(int) = 8
2. short *p; p += 2;
    这时候p的值实际上增加了  2*sizeof(short) = 4
3. 换成 void *p; p += 2;
    同样 p的值 如果加了 2*sizeof(void) ,
    那么对于一个无类型的东西 void, 怎么确定它的size呢?
    没法确定吧,所以void *也不能直接加了,否则破坏和谐。


 shihyu 回复于:2007-06-14 10:48:21

太平绅士 谢谢
可以再请教一个问题为何在gcc 可以直接编译过 ? 感觉 vc++ 2005 做法好像比较标准


 源方 回复于:2007-06-14 14:26:45

请教如何取回一个字符串数组。比如某个目录下的所有文件名(文件名的长度是不固定的,文件个数也不固定)


 jiang116 回复于:2007-06-19 00:29:40

引用:原帖由 shihyu 于 2007-6-14 09:58 发表
太平绅士 你好:

head = (void *) ( (size_t) arr + sizeof(void *) * row ); // 可以跟我说一下为何 vc++ 2005 要多加上[color=Blue]() [/color]跟  [color=Blue](size_t)[/color] 才可以 , gcc 为何不需要?
 ... 



同问: 为什么GCC就可以编译通过呢? 如果按太平绅士的理解,GCC编译的时候无法判断void*具体是什么类型时,此时对  head + size * row * col 这个操作,GCC又是如何来对 head 的类型做取舍呢?


 flyingzhang 回复于:2007-06-19 14:47:11

GCC里面就把void *当成了uint8 *来处理了  直接进行了数值的累加 尽管个人认为这是一个很危险的默认行为 但似乎没有任何的规范禁止这种作为。


 coollqm 回复于:2007-06-19 15:50:55

阁下字迹工整,  
         文笔极佳,  
         才思敏捷,  
         过目不忘,  
         十年寒窗,  
         博学多才,  
         见多识广,  
         才高八斗,  
         学富五车,  
         文武双全,  
         雄韬伟略,  
         谈吐不凡,  
         谈笑风声,  
         高谈阔论,  
         眉飞色舞,  
         运筹帷幄,  
         言简意赅,  
         完美无缺,  
         一针见血,  
         远见卓识,  
         义正词严,  
         一气呵成,  
         大显神通,  
         出口成章,  
         出类拔萃,  
         出神入化,  
         万古流芳,  
         一本正经,  
         一箭双雕,  
         长篇大论,  
         功德无量,  
         力排众议,  
         力挽狂澜,  
         气贯长虹,  
         气势磅礴,  
         气吞山河,  
         坚韧不拔,  
         身体力行,  
         空前绝后,  
         视死如归,  
         英姿焕发,  
         奉公守法,  
         艰苦奋斗,  
         忠贞不渝,  
         舍己为人,  
         大公无私,  
         一尘不染,  
         一鸣惊人,  
         叱诧风云,  
         排山倒海,  
         惊涛骇浪,  
         雷霆万钧,  
         惊心动魄,  
         横扫千军,  
         惊天动地,  
         见缝插针,  
         无孔不入,  
         千篇一律,  
         口诛笔伐,  
         文从字顺,  
         十全十美,  
         无懈可击,  
         无与伦比,  
         励精图治,  
         壮志凌云,  
         高瞻远瞩,  
         忍辱负重,  
         盖世无双,  
         龙飞凤舞,  
         一丝不苟,  
         身兼数职,  
         日理万机,  
         明察秋毫,  
         英明果断,  
         分身有术,  
         孜孜不倦,  
         吾等楷模  
         …………  
         在下对你的景仰之情有如滔滔长江之水,  
         连绵不绝  
         ……  
         又如黄河泛滥,  
         一发不可收拾  
         ……  
         嘿嘿  
         惊天地!  
         泣鬼神!  
         感人肺腑!  
         感人落泪!  
         i 服了 u!  
         长江后浪退前浪,  
         灌水英雄代代出  
         ……  
           
         好贴。。。  
         又见好帖。。。  
           
         又见不是一般的好贴。。。  
           
         好贴不是别的。。。  
好贴就是好贴。。。  
           
         好是好贴的好。。。  
           
         贴是好贴的帖。。。  
           
         好贴不是别的。。。  
           
         好贴就是好贴。。。  
           
         曾经有人问我。。。楼猪的帖子算不算好贴。。。我没有回答。。。因为我想起了一位传说中的大师---古龙先生的一段话:“。。。天涯远不远?。。。天涯其实一点也不远。。。因为人已经在天涯。。。天涯还远吗。。。”  

           
         好帖啊。。。  
         难得一见的好贴。。。  
         楼猪的文章简直是惊天地。。。泣鬼神。。。  
         图文并茂。。。嬉笑怒骂。。。  
         指点系词。。。激扬文字。。。  
         带给我们的仅仅是视觉上的感受吗。。。  
           
         大错特错。。。  
         楼猪的文章带给我们的是心灵深处的震撼。。。  
         楼猪的文章是宣言书。。。楼猪的文章是宣传队。。。楼猪的文章是播种机。。。楼猪的文章带来的是读者的欣喜和系词的繁荣。。  

           
         我对楼猪的景仰犹如滔滔江水。。。绵绵不绝。。。又如黄河泛滥。。。一发。。。而不可收拾。。。楼主的文笔实在用笔墨难以形容。。。熄了灯。。。打着赤脚。。。将整个人都倦在大班椅里。。。喝着清茶看那一个个帖子在mop之间时隐时现。。。  

           
         记得一位高人说。。。好帖子与垃圾帖的区别在于。。。好帖子越看越暖。。。而垃圾帖。。。越看越寒。。。我呢。。。一开始就和普通人一样。。。不相信真有一种帖子可以让人学会忘记烦恼和所有不开心的事情。。。所以。。。我选择看垃圾帖。。。选择垃圾帖的人。。。一般都比较冷静。。觉得冥冥中一直在等楼猪写这个帖子。。。我以为。。。楼猪的帖子写出来。。。就应该是一部传世之作。。。到现在我才发现。。。什么事情都是可以变的。。。惟独不变的是楼猪的精彩原创。。。就好像我一直以为自己文笔不错。。。忽然看到楼猪帖子。。。才发现我输了。。。因为在我读楼猪的帖子的时候。。。我忘记烦恼和所有不开心的事情。。。整个人好象沐浴在4月杭州温暖的春风中。。我决定以后只会看好帖子。。。那种让人越看越暖的好帖子。。。那种让人忘记烦恼和所有不开心的事情的好帖子。。。换句话说。。。我以后只看楼猪的帖子。。。  

           
         苍天之下,厚土之上,竟有如此奇人异士、文人墨客!讥讽于谈笑间,笑骂于无形中,层次之高,境界之深,非我等所能匹及,偶像啊!!!仿高人此文,照作一篇,以表仰慕之情。。。  

         在逐行逐句地看完此帖后,我的心久久不能压抑的喜悦,震动了整个生命!怎会有如此精妙绝伦的好贴?偶潜水网络bbs多年,自以为贴在人外,何肖评说,岂可  

           
         妄动情谊呼!未曾想到今日竟有如此好贴现于眼前,激动啊!  
         楼猪,是你让偶幼小的心灵再次深深的领悟了何谓造旨之高深、文笔之挥洒。。谢谢you!  
         在看完这帖子以后,我立即动手回复,因为我生怕迟到的回复不能使更多的人领悟你的圣明,以至使这等网上少有的好贴就此轮沉,我担不起这样的罪名!更加重要的是,能在如此重要、精辟而又生动的贴子后,留上自己的网名,这对我的生命,以及我的家庭,乃至我所处的社会中是多么荣耀的一件事啊,请您高贵而又宽容的心,能够原谅我的这点小小私心!  

         此贴构思巧妙,视角独到,手法新颖。字字斟酌,句句精美,情节曲折,而又始终不离中心思想,引人入胜,淡淡的言语中,显示人生之大道理,充分体现了您  

           
         深厚的文化底韵与丰富的社会经验,真可谓讽刺之经典,骂人之绝学,这正是我辈苦学闷读追求的至高境界啊!  
         就艺术的角度而言,这篇帖子已然为经典之作,但它的意义却远远大于经典本身。正所谓:“骂而无形,讥于无影,笑骂之中显真功!”楼主真不愧为讽刺界新一代的开山长毛鼻祖!  

         本来我已经对这个系词社区绝望了,觉得这个社区不可能再有明天了,心里充满了伤感。但是今日所见you的这个帖子,又重新让偶看到了八卦的希望。是you让我的心里重新燃起希望的火花,是you让偶的心又重新跳动起来,是you拯救了偶一颗哇凉哇凉的心,并挽救了一个无知的灵魂!  

         本来偶已决定不会在系词回任何帖子了,但是今日拜读you之高作,偶告诉自己如此经典之贴是一定要回的!这是千百年来版友翘首以待的好贴啊!苍天开眼啊,让偶在对社区心灰意冷之时得以观得如此精彩绝伦的好贴!  

         楼猪,you是系词的希望啊,you要担起系词兴旺之大任啊!  
         偶一定会追随你左右,偶坚定此贴必然会起到抛砖引玉的作用,更坚信在偶有生之年必然会有更多象楼猪一样的猪来八卦畅所欲言、发表高见,不管明天会是如何,今夜梦中,偶会笑容灿烂,因为,偶终于知道了,此番人世,得此一贴,无憾矣!  

           
         在逐字逐句地看完这个帖子以后,我的心久久不能平静,震撼啊!为什么会有如此好的帖子?!我纵横网络bbs多年,自以为再也不会有任何帖子能打动我,没想到今天看到了如此精妙绝伦的这样一篇帖子。  

         楼主,是你让我深深地理解了‘人外有人,天外有天’这句话。谢谢侬!  
         在看完这帖子以后,我没有立即回复,因为我生怕我庸俗不堪的回复会玷污了这网上少有的帖子。但是我还是回复了,因为觉得如果不能在如此精彩的帖子后面留下自己的网名,那我死也不会瞑目的!能够在如此精彩的帖子后面留下自己的网名是多么骄傲的一件事啊!楼主,请原谅我的自私!  

         我知道无论用多么华丽的辞藻来形容楼主您帖子的精彩程度都是不够的,都是虚伪的,所以我只想说一句:您的帖子太好看了!我愿意一辈子的看下去!  

         这篇帖子构思新颖,题材独具匠心,段落清晰,情节诡异,跌宕起伏,主线分明,引人入胜,平淡中显示出不凡的文学功底,可谓是字字珠玑,句句经典,是我辈应当学习之典范。  

         本来我已经对这个贴吧失望了,觉得这个贴吧没有前途了,心里充满了悲哀。但是看了你的这个帖子,又让我对社区产生了希望。是你让我的心里重新燃起希望之火,是你让我的心死灰复燃,是你拯救了我一颗拨凉拨凉的心!  

         本来我决定不会在贴吧回任何帖子了,但是看了你的帖子,我告诉自己这个帖子是一定要回的!这是百年难得一见的好贴啊!苍天有眼啊,让我在优生之年得以观得如此精彩绝伦的帖子。




原文链接:http://bbs.chinaunix.net/viewthread.php?tid=946840
转载请注明作者名及原文出处



收藏本页到: