Стек C с использованием массива

Это только часть программы, но я не понимаю этих кодов, почему мы объявили массив int* в структуре, что это значит? Также мы обычно используем int или void перед типом функции, почему мы написали struct Stack * перед созданием функции, а также какая польза здесь от unsigned? Нажмите на ссылку, чтобы просмотреть актуальную программу. ссылка

struct Stack {
    int top;
    unsigned capacity;
    int* array;
};

struct Stack* createStack(unsigned capacity) {
    struct Stack* stack = (struct Stack*) malloc(sizeof(struct Stack));
    stack->capacity = capacity;
    stack->top = -1;
    stack->array = (int*) malloc(stack->capacity * sizeof(int));
    return stack;
}

int main() {
    struct Stack* stack = createStack(100);
}

person Stack    schedule 29.12.2014    source источник
comment
Не обижайтесь, но вам нужно пройти базовый курс по c типам данных. Есть много основных концептуальных проблем.   -  person Sourav Ghosh    schedule 29.12.2014
comment
int * это не массив, это указатель.   -  person Iharob Al Asimi    schedule 29.12.2014
comment
Unsigned означает целое число без знака.   -  person andyn    schedule 29.12.2014
comment
@iharob В связанном списке мы используем следующий указатель, чтобы указать на следующий элемент, но поскольку массив заразен, поэтому нам не нужен указатель, так зачем использовать указатель здесь?   -  person Stack    schedule 29.12.2014
comment
@SouravGhosh, можешь посоветовать какие-нибудь курсы?   -  person Stack    schedule 29.12.2014


Ответы (2)


1) int * используется, потому что мы заранее не знаем, насколько огромным будет массив, поэтому мы объявляем его как указатель и выполняем malloc, используя емкость стека.

Если бы мы использовали массив, нам пришлось бы выполнять дополнительные проверки, чтобы убедиться, что наш начальный объявленный размер не переполнен, и это привело бы к огромным накладным расходам в программе.

2) Функция создания стека возвращает структурный понтер типа стек в соответствии с синтаксисом для функций.

Синтаксис:

<return type> function_name(<Parameters>){<Statements>}

3) Мы хотим, чтобы программа выдавала нам ошибку, если кто-то пытается объявить отрицательную емкость. Unsigned гарантирует, что это удовлетворено

Надеюсь это поможет.

person Ganesh Kamath - 'Code Frenzy'    schedule 29.12.2014
comment
Таким образом, в основном стек создания используется для создания структуры, достаточно большой для хранения 100 элементов массива. В связанном списке мы создаем отдельные узлы, то есть отдельные структуры, но одного типа для хранения более 1 элемента, но здесь мы создаем только одну структуру или отдельные однотипные структуры по 100 элементов каждая? - person Stack; 29.12.2014
comment
1 строение. Выделено 100 элементов int. но в вашей ссылке используются только 3. - person Ganesh Kamath - 'Code Frenzy'; 29.12.2014
comment
что вы имеете в виду, что используются только 3, мы создали стек из 100 элементов [создать стек (100)] - person Stack; 29.12.2014
comment
см. пример по вашей ссылке. Он создает стек, который может содержать 100 целых чисел, но для демонстрации он вставляет 10, 20, 30 (используя 3 пробела для целых чисел). Затем выталкивание 30 (удаление одного из стека). затем отображается вершина стека (после удаления 30 TOS становится 20) - person Ganesh Kamath - 'Code Frenzy'; 29.12.2014

почему мы объявили массив int* в структуре что это значит?

Элемент array используется для хранения содержимого стека. Однако мы не знаем заранее, сколько элементов должен содержать стек, поэтому мы не можем объявить его как обычный массив (чей размер должен быть известен во время компиляции1). Вместо этого мы будем выделять память во время выполнения с помощью библиотечной функции malloc, которая возвращает указатель на первый элемент динамически выделяемого блока; этот указатель будет храниться в члене массива.

почему мы написали struct Stack * перед созданием функции

Поскольку функция createStack возвращает указатель на новый экземпляр struct Stack:

struct Stack *createStack( ... )  ----------------+
{                                                 | The type of the expression in the 
  struct Stack *stack = ...; -----+               | `return` statement must match the  
  ...                             |               | return type of the function
  return stack; <-----------------+---------------+
}

какая польза от неподписанного здесь

unsigned — это сокращение от unsigned int; это гарантирует, что для размера стека могут использоваться только неотрицательные значения.

Вот как выглядит память после вызова функции createStack:

                   +---+
            stack: |   |----+  // The stack variable points to a struct Stack instance
                   +---+    |
                    ...     |
                   +---+    |
       stack->top: |   |<---+  // The actual struct Stack instance is created on the heap
                   +---+       // The -> operator allows us to refer to the members of the
  stack->capacity: |   |       // instance through the stack pointer variable.
                   +---+       
     stack->array: |   |----+  // The memory for the stack contents is allocated in a 
                   +---+    |  // separate malloc call, and the resulting pointer is
                    ...     |  // stored in the instance's array member.  
                   +---+    |
  stack->array[0]: |   |<---+
                   +---+
  stack->array[1]: |   |
                   +---+
  stack->array[2]: |   |
                   +---+
                    ...
                   +---+
stack->array[N-1]: |   |    // N == stack->capacity
                   +---+

Переменная stack в main указывает на экземпляр struct Stack; этот экземпляр создается строкой

struct Stack* stack = (struct Stack*) malloc(sizeof(struct Stack));

в функции createStack. Память для экземпляра стека берется из «кучи» (области памяти, зарезервированной для динамического выделения). Внутри экземпляра стека член array также указывает на область динамической памяти, зарезервированную другим вызовом malloc:

stack->array = (int*) malloc(stack->capacity * sizeof(int));

Эта функция выделяет достаточно памяти для хранения столько объектов int, сколько указано в элементе capacity.

Изменить

Обратите внимание, что оба вызова malloc можно очистить следующим образом:

struct Stack *stack = malloc( sizeof *stack );
...
stack->array = malloc( stack->capacity * sizeof *stack->array );

Если вы не используете компилятор C++ или компилятор C, предшествующий стандарту 1989 года, приведение типов не нужно (а в реализациях C89 опасно).

Выражения sizeof используют разыменованное целевое выражение, а не имя типа; это немного убирает визуальный беспорядок и сокращает обслуживание, если вы когда-нибудь решите изменить тип целевой переменной (например, с int * на double *). Тип выражения *stackstruct Stack, поэтому следует, что sizeof *stack == sizeof (struct Stack). Точно так же тип выражения *stack->array равен int, поэтому sizeof *stack->array == sizeof (int). Обратите внимание, что круглые скобки требуются только в том случае, если операнд sizeof является именем типа.

<ч> 1. C99 представил массивы переменной длины, размер которых может указываться во время выполнения, но они не будут работать в этом контексте по нескольким причинам.

person John Bode    schedule 29.12.2014
comment
Большое спасибо за подробное объяснение. Переменная стека в основном указывает на экземпляр стека структур, похоже ли это на то, что переменная стека является объектом стека структур, который имеет копию всех членов стека структур? какое дополнительное преимущество мы получаем, реализуя это с использованием структур, а не простого стека с использованием массива? Также в последней строке вы сказали, что если он изменится с int на double, то лучше писать вторым способом, но не будет ли проще в первом случае, просто изменив (int) на (double)? - person Stack; 29.12.2014