【问题标题】:Genie howto repeat a string N times as an string arrayGenie 如何将字符串作为字符串数组重复 N 次
【发布时间】:2015-07-12 18:04:12
【问题描述】:

我写了这段代码, repeatc 用于重复 char 到 char 数组。 它有效。

repeats for 将字符串重复 N 次到一个字符串数组。 但重复字符串到字符串数组核心转储。

A, A, A, 
AB, AB, AB, 
*** Error in `./untitled': free(): invalid pointer: 0x0000000000400f3d ***
....
....
Aborted (core dumped)

为什么? 我的代码:

// --cc='gcc'

[indent=4]

init
    var carray = repeatc ('A', 3)
    for i in carray do stdout.printf ("%c, ", i)
    // A, A, A

    stdout.putc ('\n')
    var sarray = repeats ("AB", 3)
    for i in sarray do stdout.printf ("%s, ", i)
    stdout.putc ('\n')



def repeatc (e: char, n: int): array of char
    var a = new array of char[n]
    Memory.copy (a, &e, sizeof (char))
    Memory.copy (&a[1], a, sizeof (char) * (n - 1)) // gcc
    return a

def repeats (e: string, n: int): array of string
    var a = new array of string[n]
    // WORKS: for var i = 0 to (n - 1) do a[i] = e
    // Memory.copy HOW TO?

    // (CORE DUMPED)
    Memory.copy (a, &e, sizeof (uint8*))
    Memory.copy (&a[1], a, sizeof (uint8*) * (n - 1))
    return a

为什么这段代码核心转储? 以及如何解决?

【问题讨论】:

    标签: vala genie


    【解决方案1】:

    这段代码有几个问题。

    [indent=4]
    
    init
        var carray = repeatc ('A', 3)
        for i in carray do stdout.printf ("%c, ", i)
        // A, A, A
    

    实际上,它会打印“A, A, A,”(注意尾随的逗号和空格)。有很多方法可以解决这个问题,最简单的就是像stdout.puts (string.joinv (", ", sarray)) 这样的事情。

    def repeatc (e: char, n: int): array of char
        var a = new array of char[n]
        Memory.copy (a, &e, sizeof (char))
    

    使用 Memory.copy(在 C 中也称为 memcpy)复制单个字节有点愚蠢。绝对没有理由不在这里做a[0] = e。它更容易并且性能会更好。

        Memory.copy (&a[1], a, sizeof (char) * (n - 1)) // gcc
    

    这是非常错误的。你告诉它从位置a复制sizeof (char) * (n - 1)字节到a之后的1个字节。这与您似乎打算的非常不同,即用数组中第一个字节的值填充 a 的其余部分。实际上你不应该使用Memory.copy,你应该使用Memory.setMemory.set (a, e, n) 可以替换这两个Memory.copy 行。

    也就是说,您真正想要的可能是字符串而不是字符数组。如果是这种情况,您可以替换整个函数并调用 string.nfill (3, 'A')

    def repeats (e: string, n: int): array of string
        var a = new array of string[n]
        // WORKS: for var i = 0 to (n - 1) do a[i] = e
        // Memory.copy HOW TO?
    

    你仍然需要一个循环。一旦您开始尝试使用 Memory.* 函数,您就在使用指针,因此您需要了解内存的布局方式。字符串实际上只是字符数组,而数组只是指向数组中第一个元素的指针。当你创建一个字符串数组时,你所拥有的是一个指向指针的指针(在 C 中,gchar**),而不是指向一个大的连续块的指针,你可以开始将字符数据复制到其中。

    我猜你正在尝试使用Memory.copy 而不是循环和简单的赋值来提高性能;这里唯一真正对性能不利的事情是一个简单的赋值将调用g_strdup,它将调用strlen,所以你最终扫描你的输入字符串N次来计算长度而不是一次。你会得到的最好的可能是这样的:

    var elen = e.length
    for var i = 0 to (n - 1)
        a[i] = (string) Memory.dup (e, (uint) elen);
    

    如果您真的关心性能,您想要做的是返回一个无主字符串数组,这些字符串都指向内存中的同一位置。或者,如果您真正感兴趣的是连接字符串而不是数组,则只需执行类似

    def repeatwithsep (e: string, n: int, separator: string): string
        var elen = e.length;
        var slen = separator.length;
        var a = new StringBuilder.sized ((elen * n) + (slen * (n - 1)) + 1);
        for var i = 0 to (n - 1)
            if i != 0
                a.append_len (separator, slen)
            a.append_len (e, elen)
        return (owned) a.str;
    

    【讨论】:

    • 嗨,我对你的代码很感兴趣。阅读它们并给我带来更多问题。 1:你能显示代码吗:返回一个无主字符串数组,它们都指向同一个位置 2:为什么你在 (owned) b>repeatwithsep 函数? var a是一个局部变量,离开这个函数会被销毁吗?
    • 这真的应该是全新的问题,每个 stackoverflow 问题都应该尽可能原子化,以便将来参考。
    猜你喜欢
    • 2013-07-27
    • 1970-01-01
    • 2013-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-21
    • 2015-03-29
    • 1970-01-01
    相关资源
    最近更新 更多