Как вставить значение в произвольную позицию в блоке памяти? - PullRequest
2 голосов
/ 04 июля 2010

У меня есть две функции C, которые в основном работают со структурой данных стека. Этот метод выдвигает значение типа OBJ, которое на самом деле просто unsigned long, на вершину стека. Стек также увеличивается при необходимости.

OBJ Quotation_push_(CzState *cz, CzQuotation *self, OBJ object)
{
    if ((self->size + 1) > self->cap) {
        self->items = (OBJ *)CZ_REALLOC(self->items, sizeof(OBJ) * (self->cap + 1) * 2);
        self->cap = (self->cap + 1) * 2;
    }
    self->items[self->size++] = object;
    return (OBJ)self;
}

Следующая функция вставляет OBJ в произвольную позицию в массиве self->items. Попробуйте, как я мог, это просто не будет работать должным образом. Я использую Quotation_push_ здесь с фиктивным значением, чтобы получить поведение автоматического роста. Проблема в том, что я всегда вижу фиктивное значение CZ_NIL в конце массива с элементом, который я пытаюсь вставить, просто перезаписывая то, что уже находится в позиции. Вот что у меня так далеко:

OBJ Quotation_insert_(CzState *cz, CzQuotation *self, OBJ object, int pos)
{
    printf("have to move %d OBJ from %d to %d\n", self->size - pos, pos, pos + 1);
    Quotation_push_(cz, self, CZ_NIL);
    memmove(self->items + ((pos + 1) * sizeof(OBJ)), self->items + (pos * sizeof(OBJ)), sizeof(OBJ) * (self->size - pos));
    self->items[pos] = object;
    return (OBJ)self;
}

Я не получаю никаких ошибок или ошибок, просто они не работают, как ожидалось. Есть идеи?

1 Ответ

3 голосов
/ 04 июля 2010

Последнее обновление:

Есть две проблемы, обе в вызове на memmove.

Первая ошибка - это единичная ошибка в количестве байтов, которые должны быть перемещены. Правильный номер будет:

sizeof(OBJ) * (self->size - pos - 1)

Пропуск -1 на самом деле переместит слишком много байтов, поместив ваш новый CZ_NIL объект за в конец буфера.

Вторая проблема больше, но более тонкая. Добавление целых чисел к указателю приводит к тому, что компилятор выполняет арифметику указателя , которая автоматически учитывает размер объектов, на которые указывают. См. этот вопрос для деталей. Вот краткая версия: self->items - это массив OBJ, поэтому вам не нужно включать sizeof(OBJ) в первые два аргумента для memmove.

Собрав все вместе, правильный вызов функции будет выглядеть так:

memmove((self->items + pos + 1),
        (self->items + pos),
        sizeof(OBJ) * (self->size - pos - 1));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...