我的realloc函数返回Segmentation fault

时间:2014-12-22 11:12:08

标签: c linux segmentation-fault malloc realloc

我编写了函数 - malloc,free和realloc malloc函数工作正常。问题在于realloc的功能它返回了我的分段错误,我不知道为什么会发生这种情况。如果你帮助我理解为什么会发生这种情况以及如何解决它,我会很高兴。

我的代码 -

#include <unistd.h>
#include <stdio.h>

void *malloc (size_t size);
void *realloc (void *ptr, size_t size);
void free (void *ptr);

typedef struct metadata_block *p_block;
struct metadata_block
{
  size_t size;
  p_block next;
  int free;
};

p_block head = NULL;

int
main ()
{
  char *str;
  int *a;
  a = (int *) malloc (4);
  scanf ("%d", a);
  printf ("String = %d\n", *a);
  a = (int *) realloc (str, 25);
  scanf ("%d", a);
  printf ("String = %d\n", *a);

  return 0;
}

void *
malloc (size_t size)
{
  void *my_malloc;
  p_block tmp;

  if (size <= 0)
    {
      return NULL;
    }

  if (head == NULL)
    {
      head = (void *) sbrk (size + sizeof (struct metadata_block));
      head->size = size;
      head->free = 0;
      head->next = NULL;
      return (void *) head + sizeof (struct metadata_block);
    }
  else
    {
      p_block tmp = head;
      while (tmp->next != NULL)
        {
          tmp = tmp->next;
        }
      tmp->next = (void *) sbrk (size + sizeof (struct metadata_block));
      tmp->size = size;
      tmp->free = 1;
      tmp->next = NULL;
      return (void *) size + sizeof (struct metadata_block);
    }
}

void *
realloc (void *ptr, size_t size)
{
  void *newptr;

  if (ptr == NULL)
    {
      return malloc (size);
    }
  if (size == 0)
    {
      return (ptr);
    }

  newptr = malloc (size);
  return (newptr);

}

void
free (void *ptr)
{
  p_block tmp;

  if (tmp->free == 1)
    {
      tmp = 0;
    }
  ptr = NULL;
}

3 个答案:

答案 0 :(得分:1)

你的realloc应该是这样的:

  • 如果ptr == NULL,则只需malloc
  • 如果ptr != NULL
    • malloc新尺寸的新指针(newPtr
    • memcpy内容从ptrnewPtr
    • 免费ptr
    • return newPtr

请记住,realloc需要一个通过调用malloc(或NULL)给出的指针。

恕我直言,实现realloc的行为,试图在可能的情况下返回相同的地址,这对你的任务来说太复杂了。

答案 1 :(得分:0)

OP realloc(),我们称之为realloc_gold()(和malloc_gold() free_gold()),需要复制数据内容和其他修复。

void *realloc_gold(void *ptr, size_t size) {

  if (ptr == NULL) {
    return malloc_gold(size);
  }

当尺寸为0时,释放当前ptr并最好处理与malloc_gold(0)相同的方式

  if (size == 0) {
    free_gold(ptr);
    return malloc_gold(ptr);
  }

检测OOM并复制数据内容。当然这会导致问题,oldsize是什么? C标准malloc()realloc()以某种方式保存该信息 ,但用户代码通常无法访问该信息。所以这段代码需要保存它。通常的解决方案是分配请求的大小+ size_t的大小,并将大小信息放在返回的指针之前。假设malloc_gold()做到了。

  void *newptr = malloc_gold(size);
  if (newptr != NULL) {
    true
    size_t oldsize = ((struct metadata_block *) ptr)[-1].size;
    memcpy(newptr, ptr, size < oldsize : size : oldsize);
    free_gold(ptr);
  }

  return (newptr);
}

malloc_gold()free_gold()需要考虑领先的规模 - 因此有些工作留给了OP。

答案 2 :(得分:-1)

The following is close to what you want, however, read all the commentary.

//#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

void *myMalloc  (size_t size);
void *myRealloc (void *ptr, size_t size);
void  myFree    (void *ptr);

//typedef struct metadata_block *p_block;
struct metadata_block
{
    size_t size;
    //p_block next;
    struct metadata_block * next;
    int free;
};

//p_block head = NULL;
struct metadata_block *head = NULL;

int main ()
{
    //char *str;
    char * str = NULL;
    int *a;

    //a = (int *) malloc (4);
    // following is not correct because myMalloc
    // returns parameter*sizeof(struct meta_block)
    // probably should call system malloc() instead of myMalloc()
    if( NULL == (a = myMalloc( sizeof(int) ) ) ) 
    { // myMalloc failed
        perror("myMalloc failed");
        exit( EXIT_FAILURE );
    }

    // implied else, myMalloc successful

    //scanf ("%d", a);
    if( 1 != scanf(" %d", a) ) 
    { // scanf failed
        perror("scanf 1 failed" );
        myFree( a );
        exit( EXIT_FAILURE );
    }

    // implied else, scanf successful

    printf ("String = %d\n", *a);

    //a = (int *) realloc (str, 25);
    int * b;
    if( NULL == (b = myRealloc( str, 25 ) ) )
    { // then, myRealloc failed
        perror( "myRealloc failed" );
        myFree(a);
        exit( EXIT_FAILURE );
    }

    // implied else, myRealloc successful

    a = b;

    //scanf ("%d", a);
    if( 1 != scanf(" %d", a ) )
    { // then, scanf failed
        perror( "scanf 2 failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, scanf successful

    printf ("String = %d\n", *a);

    // <-- added following line so no memory leaks
    myFree( a );

    return 0;
} // end function: main


void *myMalloc (size_t size)
{
    //void *my_malloc;
    //p_block tmp;

    if (size <= 0)
    {
        return NULL;
    }

    if (head == NULL)
    {
        if( NULL == (head = malloc(sizeof(struct metadata_block)*(size))) )
        { // then, malloc failed
            perror( "malloc failed" );
            exit( EXIT_FAILURE);
        }

        // implied else, malloc successful

        head->size = size;
        head->free = 0;
        head->next = NULL;
        return (void *) head + sizeof (struct metadata_block);
    }

    else
    {
        struct metadata_block* tmp = head;

        // step through existing linked list
        while (tmp->next != NULL)
        {
            tmp = tmp->next;
        }

        // initialize new metadata_block instance
        //tmp->next = (void *) sbrk (size + sizeof (struct metadata_block));
        tmp->next = malloc(sizeof(struct metadata_block)*(size+1));
        tmp->size = size;
        tmp->free = 1;
        tmp->next = NULL;
        return (void *) size + sizeof (struct metadata_block);
    }
} // end function: myMalloc


void *realloc (void *ptr, size_t size)
{
    void *newptr;

    if (ptr == NULL)
    {
        return malloc (size);
    }

    if (size == 0)
    {
        return (ptr);
    }

    newptr = malloc (size);
    return (newptr);
} // end function: realloc


// <-- the function myFree fails to actually free anything
//     and tmp is being used without first being set to something
void myFree (void *ptr)
{
    //p_block tmp;
    struct metadata_block *tmp = ptr;

    if (tmp->free == 1)
    {
        tmp = 0; // <-- this looses the allocated memory pointer
                 //     without actually freeing the allocated memory
    }

    ptr = NULL;  // <-- this has no effect on the rest of the program allocated memory
                 //     because C passes by value, not by reference
} // end function: myFree