В функции создан неверный указатель - PullRequest
0 голосов
/ 22 марта 2020

Я пытаюсь реализовать целочисленный вектор в C. Указатель вектора, созданный в vector_copy, имеет размер 0x3 или 0x2, что вызывает ошибку сегментации. Почему это происходит? Это действительно сбивает с толку меня, так как у меня есть аналогичная реализация для vector_new.

typedef struct vector {
    int* items;
    size_t size;
    size_t max;
} vector;
vector* vector_copy(vector* v) {
    vector* v2;

    memcpy(v2->items,v->items,v->max * sizeof(int*));
    if (v2->items == NULL) {
        return NULL;
    }
    v2->size = v->size;
    v2->max = v->max;
    return v2;
}
vector* vector_new(size_t initial_capacity) {
    vector* newv;
    newv->items = malloc(initial_capacity * sizeof(int*));
    if (newv->items == NULL) {
        return NULL;
    }
    newv->size = 0;
    newv->max = initial_capacity;
    return newv;
}
int main() {
    vector* v;
    vector* v2;

    v = vector_new(4);
    //new vector with capacity 4 and size 0

    vector_push(v, 1);
    vector_push(v, 2);
    //1 and 2 are pushed back

    v2=vector_copy(v);
    //vector is supposed to be copied

    vector_free(v);
    vector_free(v2);
    return 0;
}

1 Ответ

1 голос
/ 22 марта 2020
vector* v2;
memcpy(v2->items,v->items,v->max * sizeof(int*));

Это не хорошая идея. Вы в основном создали указатель v2, который указывает на какое-то произвольное местоположение (потому что вы его не инициализировали), причем значение указателя v2, вероятно, будет тем, что осталось в стеке от некоторого предыдущего работа (а) . Затем, копируя байты в это произвольное место, могут возникнуть всевозможные странности.

Вам нужно на самом деле выделить некоторую память для этого нового вектора, с чем-то вроде:

vector *v2 = vector_new(v->max);
memcpy(v2->items, v->items, v->max * sizeof(int));

Вы (надеюсь) также заметите, что я изменил sizeof, чтобы использовать int вместо int*. Я подозреваю, что items указывает на массив из первых, в этом случае это правильное значение для использования.


Так что следующая функция является лучшей отправной точкой:

vector *vector_copy(vector* v) {
    // Use vector_new to get empty one with exact same properties.

    vector *v2 = vector_new(v->max);
    if (v2 == NULL) return NULL;

    // Copy data in to it and return.

    memcpy(v2->items, v->items, v->max * sizeof(int));
    v2->size = v->size;

    return v2;
}

У вас также есть те же проблемы (без распределения структуры и неправильно sizeof) в вашей функции new, которую можно исправить с помощью:

vector *vector_new(size_t initial_capacity) {
    // Allocate a vector structure, fail if no go.

    vector *newv = malloc(sizeof(vector));
    if (newv == NULL) return NULL;

    // Allocate the data area, free structure and fail if no go.

    newv->items = malloc(initial_capacity * sizeof(int));
    if (newv->items == NULL) {
        free(newv);
        return NULL;
    }

    // Set up everything needed and return it.

    newv->size = 0;
    newv->max = initial_capacity;

    return newv;
}

Тот факт, что эта функция устанавливает максимум на основе initial_capacity освобождает вас от необходимости установки max в vector_copy().


(a) Я утверждаю «вероятно» из-за того, как много реализаций работать с точки зрения повторного использования областей памяти стека кадров. Однако это ни в коем случае не гарантируется, только одна возможность. Вы должны просто предположить, что оно будет иметь какое-то случайное значение и поэтому будет вести себя надлежащим образом (или неуместно, в зависимости от вашей точки зрения).

...