Удвоение массива динамического стека

#c #arrays #dynamic #stack #realloc

#c #массивы #динамический #стек #перераспределение

Вопрос:

У меня есть массив, используемый для представления общего стека.

 struct Stack {
    int size;
    int type;
    int capacity;
    void **data; // An array of generic data.
};

Stack *new_stack(int type) {
    Stack *tmp = malloc(sizeof(Stack));
    assert(tmp != NULL);
    tmp->size = 0;
    tmp->type = type;
    tmp->capacity = DEFAULT_CAPACITY;
    tmp->data = calloc(tmp->capacity, type);
    assert(tmp->data != NULL);
    return tmp;
}
 

Будет ли это правильным способом удвоить массив при сохранении его данных?

 void realloc_stack(Stack *s) {
    int old_capacity = s->capacity;
    s->capacity *= 2;
    s->data = realloc(s->data, s->capacity);
    memset(s->data   old_capacity, 0, old_capacity);
    assert(s->data != NULL);
}
 

Однако, когда я пытаюсь вызвать это из push_stack() следующим образом:

 void push_stack (Stack *s, void *data) {
    if (full_stack(s)) realloc_stack(s);
    s->data[s->size  ] = data;
}
 

Я понимаю эту проблему: в основном куча нулей там, где должны быть фактические числа.

 int main() {

    Stack *intStack = new_stack(sizeof(int));

    for (int i = 0; i < 15;   i) {
        push_stack(intStack, (void*)i);
    }
}
 

Результаты:

 Printing stack: 
14
13
12
11
10
0
0
0
0
9
8
7
6
1
0
 

Комментарии:

1. Что это за тип Stack.data ? Помните, что s->data old_capacity это будет зависеть от этого размера, а не sizeof(char) . Здесь вы рискуете переполнением буфера.

2. tmp->data = calloc(tmp->capacity, type); <-> s->data = realloc(s->data, s->capacity); : это не согласуется с точки зрения емкости.

3. @Raymond У вас есть тип структуры Stack , который вы не показали. У него есть data элемент, тип и, следовательно, размер которого мы не видим.

4. s->data[s->size ] = data; : Нет согласованности в размере type и.

5. Так и должно быть: s-> data = realloc(s-> данные, s-> тип * s-> емкость); Верно?

Ответ №1:

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#define DEFAULT_CAPACITY 8

typedef struct Stack {
    int size;    //number of element
    size_t type; //size of type, there are no problems with int
    int capacity;//max number of element
    void *data;  //memory of type * capacity
} Stack;

Stack *new_stack(size_t type) {
    Stack *tmp = malloc(sizeof(Stack));
    assert(tmp != NULL);
    tmp->size = 0;
    tmp->type = type;
    tmp->capacity = DEFAULT_CAPACITY;
    tmp->data = calloc(tmp->capacity, type);
    assert(tmp->data != NULL);
    return tmp;
}

void realloc_stack(Stack *s) {
    int old_capacity = s->capacity * s->type;
    s->capacity *= 2;
    s->data = realloc(s->data, s->capacity * s->type);
    assert(s->data != NULL);
    memset((char*)s->data   old_capacity, 0, old_capacity);
}

static inline int full_stack(Stack *s){//Deleting a "static inline" if you are open to the public as an interface
    return s->capacity == s->size;
}

void push_stack (Stack *s, void *data) {
    if (full_stack(s)) realloc_stack(s);
    memcpy((char*)s->data   s->type * s->size  , data, s->type);
}

void printIntObjectDump(Stack *s){
    int i, *p = s->data;
    for(i=0;i<s->capacity;  i){
        printf("%dn", p[i]);
    }
}

int main() {
    Stack *intStack = new_stack(sizeof(int));

    for (int i = 0; i < 15;   i) {
        push_stack(intStack, amp;i);
    }
    printIntObjectDump(intStack);
    return 0;
}
 

Комментарии:

1. Привет, BLUEPIXY, это сработало. Можете ли вы объяснить, зачем нам нужен char * cast ? Спасибо за вашу помощь!

2. @Raymond ; 1) арифметика указателя на void * UB (неопределенное поведение). 2) ячейка памяти, которая основана на размере void * , не представляет положение требуемой памяти. Это должно быть основано на размере s->type . (например, int * p = 0; p 1 означало 0 sizeof(int))

3. Он может быть вычислен правильно char* , поскольку sizeof(char) 1 гарантируется. Таким образом, он равен указанному местоположению.

4. примечание: вычисление void * в GCC разрешено в качестве спецификации расширения.

Ответ №2:

Чтобы расширить то, что сказал Пол Руб в комментариях выше:

Вы вызываете memset(s->data old_capacity, 0, old_capacity); , ваше намерение состоит в том, чтобы записать последнюю половину массива с 0; однако это не то, что происходит. Согласно ссылке на C , memset «Устанавливает первые байты num блока памяти, на который указывает ptr, в указанное значение». Вы пытаетесь заполнить массив целыми числами, которые являются 32-разрядными, а не 8. Поэтому вам, вероятно, следует настроить вызов на это:

 memset(s->data   (old_capacity * s->type), 0, old_capacity * s->type);
 

Это должно сработать и решить вашу проблему. Удачи!

Комментарии:

1. Это не сработало, но немного изменило результат. Печать стека: 14 13 12 11 10 0 0 0 0 9 8 7 6 1 0

2. О, вау, полный мозговой пердеж с моей стороны. Извини за это. Я думаю, что это должно быть s->type вместо s->type / 4 в обоих случаях. Если это не сработает, попробуйте оставить его только s->data old_capacity для начального местоположения. Я бы попробовал это сам, но у меня нет компилятора c на этом компьютере.

3. Также вы можете захотеть изменить вызов realloc на realloc(s->data, s->capacity * s->type); too по тем же причинам.