#c #struct #unions
Вопрос:
Я пишу реализацию стека на C, которая позволяет хранить данные любого типа. У меня есть это до сих пор:
// stack.h
enum ELEMENT_TYPE {
ELEMENT_CHAR,
ELEMENT_INT,
ELEMENT_DOUBLE,
ELEMENT_FLOAT
};
typedef struct {
enum ELEMENT_TYPE type;
union {
char val_c;
int val_i;
double val_d;
float val_f;
};
} Stack_Element;
typedef struct {
unsigned top;
unsigned capacity;
Stack_Element* elements;
} Stack;
Stack* stack_malloc(unsigned capacity) {
Stack* stack = (Stack*)malloc(sizeof(Stack));
stack->top = 0;
stack->capacity = capacity;
stack->elements = (Stack_Element*)malloc(sizeof(stack->elements) * capacity);
return stack;
}
void stack_push(Stack* stack, enum ELEMENT_TYPE type, ...) {
if (isFull(stack)) {
return;
}
va_list ap;
va_start(ap, type);
switch(type) {
case ELEMENT_CHAR:
printf("Pushing char: %cn", (char) va_arg(ap, int));
stack->elements[stack->top].val_c = (char) va_arg(ap, int); // issue
printf("After pushing: %cn", stack->elements[stack->top].val_c);
break;
case ELEMENT_INT:
printf("Pushing int: %dn", va_arg(ap, int));
stack->elements[stack->top].val_i = va_arg(ap, int); // issue
printf("After pushing: %dn", stack->elements[stack->top].val_i);
break;
case ELEMENT_DOUBLE:
printf("Pushing double: %fn", va_arg(ap, double));
stack->elements[stack->top].val_d = va_arg(ap, double); // issue
printf("After pushing: %fn", stack->elements[stack->top].val_d);
break;
case ELEMENT_FLOAT:
printf("Pushing float: %fn", (float) va_arg(ap, double));
stack->elements[stack->top].val_f = (float) va_arg(ap, double); // issue
printf("After pushing: %fn", stack->elements[stack->top].val_f);
break;
}
stack->elements[stack->top].type = type;
stack->top ;
va_end(ap);
}
Проблема, с которой я столкнулся, находится в очереди stack->elements[stack->top].val_?
. В первом printf
, где я печатаю Pushing X: %x
, значение правильное, поэтому у меня будет что-то вроде Pushing int: 123
.
Но тогда выводом для второго printf
является After pushing: 291176586
, или другое мусорное значение. Я сбит с толку, почему это происходит. Любая помощь будет признательна.
Комментарии:
1.
malloc(sizeof(stack->elements) * capacity)
это выделение неправильного размера. Чтобы избежать такого рода ошибок, используйте шаблонp = malloc(sizeof *p * N)
2. Изменено на
malloc(sizeof *stack->elements * capacity)
, но это не работает. Также пробовалsizeof stack->elements * capacity
3. @Sami Use
stack->elements = malloc( capacity * sizeof *stack->elements);
4. Используйте правильную версию , не «пробуйте» — C не является языком проб и ошибок
5. @4386427 в чем разница?
sizeof
имеет более высокий приоритет, чем умножение.
Ответ №1:
Вы используете va_arg
неправильно. На главной странице написано:
Каждый вызов функции va_arg() изменяет ap таким образом, что значения последовательных аргументов возвращаются по очереди.
но вы получаете доступ к нему дважды. Измените свой код на:
char tmp = (char) va_arg(ap, int); // Save in tmp variable
printf("Pushing char: %cn", tmp);
stack->elements[stack->top].val_c = tmp;
printf("After pushing: %cn", stack->elements[stack->top].val_c);
break;
Кроме того, вы malloc
ошибаетесь, как было указано в комментариях.
stack->elements = (Stack_Element*)malloc(sizeof(stack->elements) * capacity);
должно быть
stack->elements = malloc(sizeof(*stack->elements) * capacity);
^
notice
Тем не менее, я предпочитаю порядок
stack->elements = malloc(capacity * sizeof *stack->elements);
но он делает то же самое.
Комментарии:
1. Хороший улов! Может
va_fetch
быть, это было бы более точное название дляva_arg
.
Ответ №2:
stack->elements = (Stack_Element*)malloc(sizeof(stack->elements) * capacity);
malloc
неверно, stack->elements
это указатель, длина которого равна 4.
должно быть
stack->elements = (Stack_Element*)malloc(sizeof(Stack_Element) * capacity);
Комментарии:
1. Это ничего не добавляет к другому ответу. Также: это указатель, длина которого равна 4 . Это зависит от моей платформы (64 бита) — 8.