Я написал простую программу для реализации стека на основе динамического массива. realloc используется для изменения размера контейнера, который я использую для хранения элементов стека.
#include <stdio.h>
#include <stdlib.h>
void stack_push(int **stack, int *stackSize, int element);
int stack_pop(int **stack, int *stackSize);
int main()
{
char ch;
int *stack = NULL, stackSize = 0;
do
{
printf("\n1. Push\n");
printf("2. Pop\n");
printf("Exit (0)\n");
printf("Enter choice : ");
scanf("%c", &ch);
switch(ch)
{
case '1':
stack_push(&stack, &stackSize, 1);
break;
case '2':
printf("%d\n", stack_pop(&stack, &stackSize));
break;
case '0':
break;
}
} while (ch != '0');
return 0;
}
void stack_push(int **stack, int *stackSize, int element)
{
if (!*stack)
{
*stack = malloc(sizeof(int));
}
else
{
*stack = realloc(*stack, sizeof(int) * (*stackSize + 1));
}
*stack[*stackSize] = element;
*stackSize += 1;
}
int stack_pop(int **stack, int *stackSize)
{
if (!*stack)
{
return -1;
}
else
{
*stackSize -= 1;
int element = *stack[*stackSize];
if (*stackSize > 0)
{
*stack = realloc(*stack, sizeof(int) * (*stackSize));
}
else
{
free(*stack);
*stack = NULL;
}
return element;
}
}
Эта программа отлично работает для первого элемента. Но когда я пытаюсь добавить последующие элементы, я получаю ошибку сегментации.
Я попытался отладить свой код и обнаружил, что:
Ошибка сегментации возникает на линии:
*stack[*stackSize] = element;
Вот скриншот, показывающий другие детали: Ошибка сегментации
Где я ошибаюсь?





Это вопрос приоритета. Изменять:
*stack[*stackSize] = element;
к:
(*stack)[*stackSize] = element;
Также измените:
int element = *stack[*stackSize];
к:
int element = (*stack)[*stackSize];
Для начала нужно написать
scanf(" %c", &ch);
вместо
scanf("%c", &ch);
Обратите внимание на начальный пробел в строке формата. Это позволяет пропускать пробельные символы во входном буфере.
Внутри функции stack_push вы должны написать
( *stack )[*stackSize] = element;
вместо
*stack[*stackSize] = element;
потому что оператор индекса имеет более высокий приоритет, чем унарный оператор *.
Та же проблема существует и в функции stack_pop, где вместо
int element = *stack[*stackSize];
ты должен написать
int element = ( *stack )[*stackSize];
Также подход, когда функция stack_pop возвращает целое число -1, если стек пуст
int stack_pop(int **stack, int *stackSize)
{
if (!*stack)
{
return -1;
}
//...
не хорошо. В общем случае -1 — допустимое значение, которое можно хранить в стеке.
Было бы лучше объявить функцию как
int stack_pop(int **stack, int *stackSize, int *element );
То есть функция возвращает 0, если стек пуст. В противном случае он возвращает ненулевое значение (например, 1) и присваивает переменной, на которую указывает указатель element, значение элемента в стеке.
В качестве альтернативы вы можете добавить еще одну функцию, которая проверяет, пуст ли стек. Эту функцию следует вызывать перед вызовом функции stcak_pop.
Также было бы намного лучше, если бы вместо отдельных переменных stack и stackSize вы использовали структуру, содержащую соответствующие элементы данных, например
struct Stack
{
size_t top;
int *elements;
};
А в main вы можете определить объект такой структуры, как
struct Stack stack = { .top = 0, .elements = NULL };
Большое спасибо за подробный ответ! Не могли бы вы предложить какой-нибудь источник, из которого я могу узнать больше о приоритете операторов декларатора, таких как *, [] и т. д. Я читал о приоритете арифметических, логических и реляционных операторов, но это что-то новое для меня.
@KingoftheSkies Вы можете найти PDF-копию черновика стандарта C в Интернете. Оператор нижнего индекса является постфиксным оператором. Постфиксные операторы имеют более высокий приоритет, чем унарные операторы.
Большое спасибо. Я понял проблему.