Инициализировать стек в C, установив указатель на NULL - PullRequest
1 голос
/ 23 февраля 2012

Я пытаюсь реализовать стек в C в соответствии со следующим заголовком (stack.h):

#ifndef STACK_H
#define STACK_H

/* An element from which stack is consisting */
typedef struct stack_node_ss {
  struct stack_node_ss *next;    /* pointer to next element in stack */
  void *value;                  /* value of this element */
} stack_node_s;

/* typedef so that stack user doesn't have to worry about the actual type of
 * parameter stack when using this stack implementation.
 */
typedef stack_node_s* stack_s;

/* Initializes a stack pointed by parameter stack. User calls this after he
 * has created a stack_t variable but before he uses the stack.
 */
void stack_init(stack_s *stack);

/* Pushes item to a stack pointed by parameter stack. Returns 0 if succesful,
 * -1 otherwise.
*/
int stack_push(void *p, stack_s *stack);

/* Pops item from a stack pointed by parameter stack. Returns pointer to
 * element removed from stack if succesful, null if there is an error or
 * the stack is empty.
 */
void *stack_pop(stack_s *stack);

#endif

Однако, будучи новичком в C, я застрял в функции stack_init, которую я написал в stack.c:

#include <stdlib.h>
#include <stdio.h>
#include "stack.h"

void stack_init(stack_s *stack) {
    (*stack)->value = NULL;
    (*stack)->next = NULL;
}

Основная программа начинается с:

  int *tmp;
  stack_s stack;
  stack_init(&stack);

И это приводит к сбою моей программы:

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000008
0x0000000100000abf in stack_init (stack=0x7fff5fbffb30) at stack.c:6
6       (*stack)->value = NULL;

Можете ли вы подсказать мне правильный путь? Большое спасибо.

Ответы [ 3 ]

6 голосов
/ 23 февраля 2012

Вы должны выделить память для самого **stack:

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

Но, пожалуйста, не указывайте типы указателей.Это действительно сбивает с толку и трудно читать.Лучше передать указатель по значению и оставить его вызывающей стороне для хранения указателя, например:

typedef struct stack_node_t
{
    struct stack_node_t * next;
    /* ... */
} stack_node;

stack_node * create_stack()
{
    stack_node * res = calloc(1, sizeof(stack_node));
    return res;
}

void destroy_stack(stack_node * s)
{
    if (!next) return;

    stack_node * next = s->next;
    free(s);
    destroy_stack(next);
}

// etc.

Тогда вы можете просто сказать:

stack_node * s = create_stack();

// use s

destroy_stack(s);
s = NULL;  // some people like this
2 голосов
/ 23 февраля 2012

Вы разыменовываете неинициализированный указатель, вызывая неопределенное поведение.

Поскольку эта функция создает новый стек, вам необходимо выделить некоторую динамическую память для стека, а затем установить указатель так, чтобы он указывал на вновь выделенный стек.память:

void stack_init(stack_s *stack) {
    *stack = malloc(sizeof(**stack)); // create memory for the stack

    (*stack)->value = NULL;
    (*stack)->next = NULL;
}

stack_s stack;
stack_init(&stack);

Тогда у вас должна быть функция с именем stack_destroy, которая будет free динамической памяти и устанавливать указатель на NULL:

void stack_destroy(stack_s *stack) {
    free(*stack);
    *stack = NULL;
}
0 голосов
/ 23 февраля 2012

Вы должны инициализировать стек в NULL - чтобы не выдавать ему значение NULL:

void stack_init(stack_s *stack) {
    *stack=NULL;
}
...