Genie как повторить строку N раз как массив строк

Я пишу этот код, repeatc для повторения символа в массив символов. оно работает.

повторяется для повторяет строку 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

Почему этот код основной дамп? и как это исправить?


person Naam Famas    schedule 12.07.2015    source источник


Ответы (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 (он же memcpy в C) для копирования одного байта более чем глупо. Нет абсолютно никаких причин не делать здесь a[0] = e. Это проще и будет работать лучше.

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

Это очень неправильно. Вы говорите ему скопировать sizeof (char) * (n - 1) байтов из местоположения a в 1 байт после a. Это сильно отличается от того, что вы, кажется, намеревались заполнить оставшейся частью значением первого байта в массиве. На самом деле вы не должны использовать Memory.copy, вы должны использовать Memory.set: Memory.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;
person nemequ    schedule 12.07.2015
comment
Привет, меня очень заинтересовал твой код. после прочтения их и принести мне больше вопросов. 1: можете ли вы показать код: вернуть массив не принадлежащих строк, которые все указывают на одно и то же место 2: почему вы добавляете (принадлежащий) в конце < b>повторить с помощью функции? var a — локальная переменная, при выходе из этой функции она будет уничтожена? - person Naam Famas; 13.07.2015
comment
Это действительно должны быть совершенно новые вопросы, каждый вопрос stackoverflow должен быть как можно более атомарным, чтобы его можно было повторно использовать для дальнейшего использования. - person Jens Mühlenhoff; 13.07.2015