#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 по тем же причинам.