V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Kellerman
V2EX  ›  程序员

在 C 语言里面,不规则的二维数组有什么比较方便高校的复制方法吗?

  •  
  •   Kellerman · 2020-04-16 10:56:59 +08:00 · 3049 次点击
    这是一个创建于 1464 天前的主题,其中的信息可能已经有所发展或是发生改变。

    就像标题说的,我现在需要将数组从一个不规则的二维数组中复制到另外一个二维数组中,这两个二维数组都是不规则的,而且结构是不一样的,只是所能容纳元素的总长度相等,这种问题,有什么高效的方法吗?谢谢大家了!

    第 1 条附言  ·  2020-04-16 12:21:26 +08:00
    那这样吧,n 段不等长的连续内存,复制到 m 段不等长的内存里,有没有比较方便的方法,存储顺序按照源内存的顺序存储。
    32 条回复    2020-04-16 19:02:58 +08:00
    InkStone
        1
    InkStone  
       2020-04-16 10:59:01 +08:00
    我觉得最大的问题是,两个数组的结构都不一样,你想怎么复制?

    如果只是按内存地址顺序复制,那直接 memcpy 就好了。
    across
        2
    across  
       2020-04-16 11:03:52 +08:00
    不能。
    不过一开始就自己 malloc 一块区域,手动控制对象,效率会好点吧。
    jngke931126
        3
    jngke931126  
       2020-04-16 11:11:25 +08:00
    很好奇这个的应用场景,能说下不,也许有别的办法呢
    linvon
        4
    linvon  
       2020-04-16 11:45:33 +08:00
    只能自己操作内存了吧
    Kellerman
        5
    Kellerman  
    OP
       2020-04-16 12:22:42 +08:00
    @InkStone 那如果说 我是从 n 段不等长的连续内存,复制到 m 段不等长的内存里,有没有比较方便的方法。(段内存内部是连续的,段与段之间是不连续的!)
    Kellerman
        6
    Kellerman  
    OP
       2020-04-16 12:23:04 +08:00
    @across 能具体讲讲吗,我的应用场景是,是从 n 段不等长的连续内存,复制到 m 段不等长的内存里,有没有比较方便的方法。(段内存内部是连续的,段与段之间是不连续的!
    Kellerman
        7
    Kellerman  
    OP
       2020-04-16 12:23:21 +08:00
    @jngke931126 我是从 n 段不等长的连续内存,复制到 m 段不等长的内存里,有没有比较方便的方法。(段内存内部是连续的,段与段之间是不连续的! 这是应用场景!
    Kellerman
        8
    Kellerman  
    OP
       2020-04-16 12:23:32 +08:00
    @linvon 自己操作内存这个能详细说下吗?
    xpfd
        9
    xpfd  
       2020-04-16 12:31:01 +08:00
    自己写个函数,针对每段数据,单独 memcpy
    Kellerman
        10
    Kellerman  
    OP
       2020-04-16 12:35:51 +08:00
    @xpfd 那这样的我要比对每一段源和目的内存的长度,然后分情况讨论,这样就会显的非常复杂,有什么更简单的方法吗?
    linvon
        11
    linvon  
       2020-04-16 13:02:39 +08:00
    @Kellerman 手动根据长度自行 memcpy 呗,你要是嫌双判断麻烦,就先把 n 段先拿出来存放成线性的 x,再把 x 根据 m 段的长度拆解进去
    zhyl
        12
    zhyl  
       2020-04-16 13:11:44 +08:00
    数组存储空间连续, 直接当成内存空间使用 memcpy 拷贝就行了
    across
        13
    across  
       2020-04-16 13:15:06 +08:00
    @Kellerman 仅在拷贝时解决不了,要在更高层面优化,不如查查稀疏数组( Sparse Array )管理方法。
    zhyl
        14
    zhyl  
       2020-04-16 13:15:38 +08:00
    结构不一样不影响拷贝, 只影响你怎么去解释这个数组

    举个例子: 一个 int 数组拷贝到一个 char 数组中, 两个数组的基本元素结构并不一样, int 占 4 字节(假设), char 占 1 字节, 这个结构只影响你后续怎么使用这个数组, 但是拷贝的话是不看结构的, memcpy 前两个参数为 void* 就应该明白这一点
    InkStone
        15
    InkStone  
       2020-04-16 13:31:48 +08:00
    @Kellerman 没看明白你的意思。

    n 段内存复制到 m 段内存,n≠m 的时候怎么做映射?
    假设 n 段内存的长度为 n1,n2,n3,n4,n5,m 段内存的长度为 m1,m2,m3,m4,m5,n1 要复制到 m1, n1>m1 怎么办,n1<m1 又怎么填充?

    你最好不要描述得那么抽象,直接把你想解决的问题说出来给大家听听。
    zjsxwc
        16
    zjsxwc  
       2020-04-16 13:37:33 +08:00
    对不起我看不懂题目
    xdtr
        17
    xdtr  
       2020-04-16 13:39:00 +08:00
    根据数组 a 的所有数据长度 malloc 一片内存 m,把数组 a 的所有数据按顺序存放到 m 中,然后根据数组 b 的每一段长度从 m 中取出对应的长度存放到 b 中。
    wutiantong
        18
    wutiantong  
       2020-04-16 13:53:45 +08:00
    not a good question

    我建议对问题做进一步补充:
    既然要问的是有什么“高效的”方法,那不妨贴一段代码来展示作为 baseline 的实现。
    pkookp8
        19
    pkookp8  
       2020-04-16 14:06:59 +08:00 via Android
    @InkStone 可能问题中 n 和 m 长度虽然不等,但总长 m 大于等于 n
    例如 2 段内存,一段 4 字节一段 20 字节
    按序拷贝到
    3 段内存,一段 8 字节一段 12 字节一段 4 字节

    我觉得没办法吧,就是比较长短。短的部分直接拷贝,拷贝后长的部分减去相应长度,继续下一次拷贝
    oahebky
        20
    oahebky  
       2020-04-16 15:09:25 +08:00
    直接复制很低效吗???
    InkStone
        21
    InkStone  
       2020-04-16 15:25:46 +08:00
    @pkookp8 如果放在一段连续的内存里,直接 memcpy 整个长度就好了。

    我觉得你这个需求多半是可以塞进连续内存里的。要解析的时候写个 struct reinterpret_cast 一下就好了。
    crz
        22
    crz  
       2020-04-16 15:45:19 +08:00
    @zhyl 看起来说的是类似 {char, int} => {int, chart} 这样的映射,所以不能直接用 memcpy
    augustheart
        23
    augustheart  
       2020-04-16 15:51:13 +08:00
    但是如果是不同的结构,不考虑两个结构体是否用可以用来取巧的区别,for 是你唯一可靠的选择。
    而且就算开 for 遍历也并不慢。(当然,你也可以考虑用 duff's device 减少循环的消耗)
    augustheart
        24
    augustheart  
       2020-04-16 15:53:20 +08:00
    @augustheart 当然,我并没有考虑能不能写个合用的 duff's device,所以就是个瞎说。
    但是无论如何,每一个元素都必须处理到
    name1991
        25
    name1991  
       2020-04-16 16:23:32 +08:00
    如果段与段之间不连续的话是有点难办的
    zjsxwc
        26
    zjsxwc  
       2020-04-16 16:47:52 +08:00
    C 没有 Rust 的 Match 语法

    楼主的需求只能用 yacc 写个转换代码生产机,自动生成 C 代码
    name1991
        27
    name1991  
       2020-04-16 17:05:13 +08:00
    @zjsxwc 写下思路?
    ExplorerLog
        28
    ExplorerLog  
       2020-04-16 17:25:37 +08:00
    sizeof 第一段 和 memcpy 第一段,指针加第一段 size
    sizeof 第二段 和 memcpy 第二段,指针加第二段 size
    ...

    循环操作

    写个函数
    zjsxwc
        29
    zjsxwc  
       2020-04-16 18:44:11 +08:00 via Android
    @name1991 #27 原文:“@zjsxwc 写下思路?”
    回复:

    就是设计一个你 n 段内存数据到 m 段内存数据对应规则的描述语法 X,然后 yacc 设计一个简单的编译器把用语法 X 写的对应规则编译成相应的 C 语言源代码。


    这个 X 语法很简单,比如
    (n1, len1),(n2, len2),(n3, len3) -> (m1, len4),(m2, len5)

    其中 len1+len2+len3==len4+len5

    表示把 n 段内存中 3 段数据复制到 m 段内存中的 2 段。
    zjsxwc
        30
    zjsxwc  
       2020-04-16 18:54:49 +08:00 via Android
    编译出来的 c 代码就是一堆 memcpy 调用以及维护每个 memcpy 三个参数的代码,挺无脑的。

    当然也可以不用 yacc 直接解析也行。
    nightwitch
        31
    nightwitch  
       2020-04-16 18:57:46 +08:00
    pod 类型直接 for 循环拷贝就行了,不会比你换着花样 memcpy 慢很多的
    Huelse
        32
    Huelse  
       2020-04-16 19:02:58 +08:00
    既然用了 c 语言,就告别了优雅的写法,自己动手操作指针、内存等,楼上都说了很多了

    当然用 c++直接 template 好了,实在不行还可以用 gsl
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5307 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 08:36 · PVG 16:36 · LAX 01:36 · JFK 04:36
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.