Нет необходимости в malloc
в этой программе, как написано.Память стека, обычные объявления переменных типа int i
или int valueStack[50]
, живет до тех пор, пока не будет объявлена функция, выходящая из нее.Таким образом, все переменные, которые вы объявляете в main
, будут жить до завершения программы.
С другой стороны, если вы попытаетесь вернуть память стека следующим образом:
int *newStack() {
int stack[50];
return stack;
}
int *valueStack = newStack();
будет проблемой, память, на которую указывает stack
, будет освобождена после возврата newStack
.vauleStack
осталось бы указывать на освобожденную память, которая может быть перезаписана.
Эмпирическое правило: если вы возвращаете указатель, оно должно быть malloc
'd.
Я не могу воспроизвести вашу проблему, но я вижу, где она может пойти не так.Есть несколько мест, где вы можете ходить со своими стеками.
Поскольку valueStack
и opStack
имеют фиксированные размеры, и pushValStack
, и popOpStack
сойдут с конца стека, когда top
достигает 49, что приводит к (ожиданию) переполнению стека.
int valueStack[50];
int valcounter = 0;
for( int i = 0; i < 50; i++ ) {
pushValStack(valueStack, &valcounter, i);
}
( Это 49, а не 50, потому что top
увеличивается до помещения значения в стек. Это приводит к отключениюошибка «один на один», когда для хранения чего-либо в позиции 0 top
необходимо начинать с -1. )
Аналогично, popValStack
и popOpStack
могут идти с задней сторонымассив, ведущий к переполнению стека.Отрицательные показатели работают в C;они читают память перед указателем, что плохо.Интересно, что это не вызвало ошибку для меня.YMMV.
Один из способов обнаружить такие ошибки - добавить 1039 * s, чтобы убедиться, что вы не выходите за пределы.Утверждение - это выражение, которое вы считаете истинным.Если это не так, программа останавливается.
#include <stdio.h>
#include <assert.h>
// Here I put the stack size into a constant so it can be referenced by the asserts.
#define STACK_SIZE 50
int popValStack(int valstack[], int *top){
assert( *top >= 0 );
int valdata = valstack[*top];
*top = *top - 1;
return valdata;
}
void pushValStack(int valstack[], int *top, int value){
*top = *top + 1;
assert( *top < STACK_SIZE );
valstack[*top] = value;
}
int main(int argc, char *argv[]){
int valueStack[STACK_SIZE];
int valcounter = 0;
for( int i = 0; i < STACK_SIZE; i++ ) {
pushValStack(valueStack, &valcounter, 1);
}
}
Тогда вместо загадочного segfault вы получите явную ошибку.
Assertion failed: (*top < STACK_SIZE), function pushValStack, file test.c, line 26.
Утверждения удобны для проверки любых предположенийи границы, которые у вас есть в вашем коде.
Сделав этот шаг дальше, мы можем улучшить код и целостность стека, используя структуру для сбора всех переменных, связанных со стеком, в одном месте..
typedef struct {
int *stack;
size_t size;
size_t top;
} IntStack;
( Я использовал size_t
здесь вместо int
, потому что он гарантированно будет достаточно большим, чтобы вместить размер максимально возможного объекта, поэтому он подходит для массиваindexes. )
Тогда IntStack может передаваться как единое целое.Он знает его размер и местонахождение вершины.
void IntStackPush( IntStack *stack, int value ) {
assert( stack->top < stack->size );
stack->stack[stack->top] = value;
stack->top += 1;
}
int IntStackPop( IntStack *stack ) {
assert( stack->top > 0 );
stack->top -= 1;
return stack->stack[stack->top];
}
#define STACK_SIZE 50
int main(){
int values[STACK_SIZE];
IntStack valueStack = { .stack = values, .size = STACK_SIZE, .top = 0 };
for( int i = 0; i < STACK_SIZE; i++ ) {
IntStackPush(&valueStack, i);
}
for( int i = 0; i < STACK_SIZE; i++ ) {
printf("%d\n", IntStackPop(&valueStack));
}
}
Обратите внимание, что мы должны вручную инициализировать структуру, которая может быть подвержена ошибкам.Вместо этого мы можем написать функцию, которая сделает это за нас.Так как мы возвращаем указатель из функции сейчас нам нужно malloc
.
IntStack *IntStackNew( size_t size ) {
// Allocate space for the struct.
IntStack *stack = malloc(sizeof(IntStack));
stack->top = 0;
stack->size = size;
// And allocate space for the stack.
stack->stack = malloc( size * sizeof(int) );
return stack;
}
И так как мы выделяем память в куче, нам нужно ее освободить.
void IntStackFree( IntStack *stack ) {
free(stack->stack);
free(stack);
}
Теперь стек можно использовать, ничего не зная о его кишках.
#define STACK_SIZE 50
int main(){
IntStack *valueStack = IntStackNew(STACK_SIZE);
for( int i = 0; i < STACK_SIZE; i++ ) {
IntStackPush(valueStack, i);
}
for( int i = 0; i < STACK_SIZE; i++ ) {
printf("%d\n", IntStackPop(valueStack));
}
IntStackFree(valueStack);
}