rat
rat

Reputation: 9

void* function doesn't retain a pointer to the allocated memory inside another function

I wanted to create a dynamic stack just for learning purposes, but I ran into a problem: I'd like to push() function be able to handle if the dstack isn't initialized, and it works when I go through the code in gdb, but when I call the print_dstack() after returning from push() function, the pointer I give to it is NULL (but I initialized *stack and returned the pointer explicitly), so I'm getting stuck on SEGFAULT at this point, because I am trying to read a pointer to NULL. I wonder why does that even happen?

Here's my code:

dstack.h:

#pragma once
#ifndef _DSTACK_H_
#define _DSTACK_H_

enum stack_inits {
  DEFAULT_SIZE = 16,
  DEFAULT_SPACE = 32
};

typedef struct {
    int size;
    int length;
    int *stack;
} dstack_t;

static void *init(const int size);

static void resize(dstack_t *stack);

void *push(dstack_t *stack, int item);

void print_dstack(dstack_t const *stack);

void free_dstack(dstack_t *stack);

#endif

dstack.c:

#include "dstack.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

static void *init(const int size)
{
  dstack_t *stack;
  if( (stack = (dstack_t*)malloc(sizeof(dstack_t))) == NULL)
    return NULL;
  if( (stack->stack = (int*)malloc(size * sizeof(int))) == NULL) {
    free(stack->stack);
    free(stack);
    return NULL;
  }
  stack->size = size;
  stack->length = 0;

  return stack;
}

static void resize(dstack_t *stack)
{
  stack->size += DEFAULT_SPACE;
  int *newStack = realloc(stack->stack, sizeof(int) * stack->size);
  assert(newStack);
  stack->stack = newStack;
}

void *push(dstack_t *stack, int item)
{
  if(stack == NULL)
    stack = init(DEFAULT_SIZE);
  if(stack->stack == NULL)
    if( (stack->stack = (int*)malloc(DEFAULT_SIZE * sizeof(int))) == NULL) {
      free(stack->stack);
      return NULL;
    }
  if(stack->length == stack->size)
    resize(stack);
  stack->stack[stack->length++] = item;
  return &stack->stack[stack->length-1];
}

void print_dstack(dstack_t const *stack)
{
  assert(stack);
  for(int i = 0; i < stack->length; i++)
  {
    if(i % 2 == 0)
      putchar('\0');
    printf("stack[%d] = %d\t", i, stack->stack[i]);
  }
}

void free_dstack(dstack_t *stack)
{
  free(stack->stack);
  free(stack);
}

stack_test.c:

#include "dstack.h"
#include <stdio.h>

int main()
{
  dstack_t *stack = NULL;
  push(stack, 10);

  print_dstack(stack);
  free_dstack(stack);
  return 0;
}

Upvotes: 0

Views: 48

Answers (1)

ikegami
ikegami

Reputation: 385657

You modify push's stack, but not the caller's argument (main's stack), to which push doesn't have access. If you want push to modify the caller's pointer variable, you will need to pass a pointer to it as follows:

dstack_t * stack = NULL;
push( &stack, 10 );

You could also use something like the the following:

dstack_t * stack = NULL;
stack = push( stack, 10 );

Adjust push accordingly.

Personally, I think it's appropriate for push to require an initialized stack.

Upvotes: 0

Related Questions