我写了函数 - 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 = %dn", *a);
a = (int *) realloc (str, 25);
scanf ("%d", a);
printf ("String = %dn", *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;
}
你的 realloc 应该像这样运行:
- 如果
ptr == NULL
,那么就malloc
- 如果
ptr != NULL
:-
malloc
新大小的新指针 (newPtr
) - 从
ptr
到newPtr
memcpy
内容 - 免费
ptr
- 返回
newPtr
-
请记住,realloc
需要一个指针,该指针是从调用到malloc
(或 NULL)时给出的。
恕我直言,实现 realloc
的行为,如果可能的话,它会尝试返回相同的地址,这对于您的任务来说太复杂了。
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。
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 = %dn", *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 = %dn", *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