有没有办法仅使用 malloc 和自由函数来更改数组大小?
Is there a way to change an array size using malloc and free functions only?
作为家庭作业,我必须编写一个仅使用 malloc
和 free
函数来更改数组大小的函数。
我知道如何使用 realloc
,但我不知道如何使用 malloc
。
typedef struct{
int *tab;
int size;
}arr;
我需要编写这个函数:
void changeSizeDyn(arr *Dyn_arr, int size){
//
}
正如作业中所说:它只需要一次重新分配和一次内存释放,并且只需要从旧数组中复制一份元素。
我搜索了很多但只找到了使用 realloc
.
的结果
是否可以不使用 realloc
来做到这一点?
- 使用 malloc 分配新大小的内存。
- 将旧内存中的所有字节复制到新内存中。您可以在循环中执行此操作,您实际上不需要为此使用函数(如果这是赋值)。
- 释放旧内存。
void *onlymallocrealloc(void *ptr, size_t oldsize, size_t newsize)
{
void *newmem = malloc(newsize);
if(ptr && newmem)
{
memcpy(newmem, ptr, oldsize);
free(ptr);
}
return newmem;
}
并针对您的类型(略有更改)
typedef struct{
int size;
int tab[];
}arr;
arr *onlymalloc(arr *ptr, size_t newsize)
{
ptr = onlymallocrealloc(ptr, ptr -> size * sizoef(ptr -> tab[0]) + sizeof(*ptr), newsize * sizoef(ptr -> tab[0]) + sizeof(*ptr));
if(ptr)
{
ptr -> size = newsize;
}
return ptr;
}
编辑函数是否必须为 void
void onlymallocrealloc(void **ptr, size_t oldsize, size_t newsize)
{
void *newmem = malloc(newsize);
if(*ptr && newmem)
{
memcpy(newmem, *ptr, oldsize);
free(*ptr);
*ptr = newmem;
}
}
void onlymalloc(arr **ptr, size_t newsize)
{
onlymallocrealloc(&ptr, *ptr -> size * sizoef(*ptr -> tab[0]) + sizeof(**ptr), newsize * sizoef(*ptr -> tab[0]) + sizeof(**ptr));
if(*ptr)
{
*ptr -> size = newsize;
}
}
功能并不像乍看起来那么简单
给你。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
typedef struct
{
int *tab;
int size;
} arr;
int changeSizeDyn( arr *Dyn_arr, int size )
{
int success = 1;
if ( Dyn_arr->size != size )
{
int *tmp = NULL;
if ( size != 0 )
{
tmp = malloc( size * sizeof( int ) );
success = tmp != NULL;
if ( success )
{
int n = 0;
if ( Dyn_arr->size != 0 )
{
n = size < Dyn_arr->size ? size : Dyn_arr->size;
memcpy( tmp, Dyn_arr->tab, n * sizeof( int ) );
}
if ( n < size ) memset( tmp + n, 0, ( size - n ) * sizeof( int ) );
}
}
if ( success )
{
free( Dyn_arr->tab );
Dyn_arr->tab = tmp;
Dyn_arr->size = size;
}
}
return success;
}
int main( void )
{
arr a = { NULL, 0 };
int size = 10;
if ( changeSizeDyn( &a, size ) )
{
for ( int i = 0; i < size; i++ ) a.tab[i] = i;
for ( int i = 0; i < size; i++ ) printf( "%d ", a.tab[i] );
putchar( '\n' );
}
size = 5;
if ( changeSizeDyn( &a, size ) )
{
for ( int i = 0; i < size; i++ ) a.tab[i] = i;
for ( int i = 0; i < size; i++ ) printf( "%d ", a.tab[i] );
putchar( '\n' );
}
size = 0;
if ( changeSizeDyn( &a, size ) )
{
for ( int i = 0; i < size; i++ ) a.tab[i] = i;
for ( int i = 0; i < size; i++ ) printf( "%d ", a.tab[i] );
putchar( '\n' );
}
assert( a.tab == NULL && a.size == 0 );
}
程序输出为
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4
该函数有一个 return 类型 int
来表示它的调用是否成功。您需要一种方法来确定函数调用是否成功。否则将无法确定这一点。所以使用类型 void
作为函数的 return 类型是一个坏主意。
该函数默认将与旧数组元素不对应的所有新元素设置为零。其实不是必须的,只是让结构体的使用更加清晰。
如果用户传递的大小等于 0,则该函数只是释放旧数组并将数据成员 tab
设置为 NULL
。
如果数组的新大小和旧大小相等,则函数不执行任何操作。
请注意,将结构的数据成员 size
声明为类型 size_t
会好得多。否则,您需要在 size
不为负的函数中添加一个检查。我没有那样做,因为我认为您确实会在结构(和函数)声明中使用类型 size_t
而不是类型 int
。
struct Arr {
int *tab;
ptrdiff_t nmemb;
};
假设您最初是这样分配数组的:
struct Arr x;
x.nmemb = 7;
x.tab = malloc(sizeof(*x.tab) * x.nmemb);
你应该用这个函数重新分配它:
void change_size_dyn(struct Arr *dyn_arr, ptrdiff_t nmemb)
{
struct Arr old;
ptrdiff_t cp_nmemb;
if (!dyn_arr)
return;
old = *dyn_arr;
if (nmemb <= 0)
goto err;
dyn_arr->tab = malloc(sizeof(*dyn_arr->tab) * nmemb);
dyn_arr->nmemb = nmemb;
cp_sz = MIN(old.nmemb, nmemb);
memcpy(dyn_arr->tab, old.tab, cp_nmemb);
free(old.tab);
return;
err:
dyn_arr->tab = NULL;
dyn_arr->nmemb = 0;
free(old.tab);
}
应该这样称呼:
change_size_dyn(&x, 9);
您甚至可以在第一次分配时使用此功能(尽管您应该首先设置 NULL
和 0
这两个值)。您也不需要添加免费的;输入 0 会为您完成,就像 realloc
会做的那样:
int main(void)
{
struct Arr x = {0};
change_size_dyn(&x, 5);
/* ... */
change_size_dyn(&x, 9);
/* ... */
cleanup:
change_size_dyn(&x, 0);
return 0;
}
如果你传递一个结构,其中 dyn_arr->nmemb
已经是一个负值(不应该发生),行为是未定义的(那个负值将进入 memcpy
,它会被包装到一个非常高的 size_t
,这会溢出数组)。我不想检查它,因为在任何 non-buggy 场景中都没有必要。
Is it even possible to do that without using realloc
?
当然是。
例如,您可以这样做:
#include <stdlib.h> /* for malloc () and free () and EXIT_xxx macros. */
#include <stdio.h> /* for perror */
typedef struct{
int *tab;
size_t size; /* Prefer using size_t for (memory) sizes over using a
signed int. */
} arr;
void changeSizeDyn(arr *parr, size_t size)
{
if (!parr && !parr->tab)
{
errno = EINVAL;
}
else
{
arr tmp = {
malloc(size * sizeof *tmp.tab),
size
};
if (tmp.size && !tmp.tab)
{
perror("malloc() failed");
}
else
{
for (
size_t m = (tmp.size < parr->size) ?tmp.size :parr->size, i = 0;
i < m;
++i)
{
tmp.tab[i] = parr->tab[i];
}
free(parr->tab);
*parr = tmp;
errno = 0;
}
}
}
/* A main() to test the above: */
int main(void)
{
const size_t s = 42;
arr a = {
malloc(s * sizeof *a.tab),
s
};
if (a.size && !a.tab)
{
perror("malloc() failed");
exit(EXIT_FAILURE);
}
/* populate a.tab[0] to a.tab[a.size - 1] here. */
changeSizeDyn(&a, 43);
if (0 != errno)
{
perror("changeSizeDyn() failed");
exit(EXIT_FAILURE);
}
/* Use a.tab[0] to a.tab[a.size - 1] here. */
free(a.tab);
a.size = 0;
}
作为家庭作业,我必须编写一个仅使用 malloc
和 free
函数来更改数组大小的函数。
我知道如何使用 realloc
,但我不知道如何使用 malloc
。
typedef struct{
int *tab;
int size;
}arr;
我需要编写这个函数:
void changeSizeDyn(arr *Dyn_arr, int size){
//
}
正如作业中所说:它只需要一次重新分配和一次内存释放,并且只需要从旧数组中复制一份元素。
我搜索了很多但只找到了使用 realloc
.
是否可以不使用 realloc
来做到这一点?
- 使用 malloc 分配新大小的内存。
- 将旧内存中的所有字节复制到新内存中。您可以在循环中执行此操作,您实际上不需要为此使用函数(如果这是赋值)。
- 释放旧内存。
void *onlymallocrealloc(void *ptr, size_t oldsize, size_t newsize)
{
void *newmem = malloc(newsize);
if(ptr && newmem)
{
memcpy(newmem, ptr, oldsize);
free(ptr);
}
return newmem;
}
并针对您的类型(略有更改)
typedef struct{
int size;
int tab[];
}arr;
arr *onlymalloc(arr *ptr, size_t newsize)
{
ptr = onlymallocrealloc(ptr, ptr -> size * sizoef(ptr -> tab[0]) + sizeof(*ptr), newsize * sizoef(ptr -> tab[0]) + sizeof(*ptr));
if(ptr)
{
ptr -> size = newsize;
}
return ptr;
}
编辑函数是否必须为 void
void onlymallocrealloc(void **ptr, size_t oldsize, size_t newsize)
{
void *newmem = malloc(newsize);
if(*ptr && newmem)
{
memcpy(newmem, *ptr, oldsize);
free(*ptr);
*ptr = newmem;
}
}
void onlymalloc(arr **ptr, size_t newsize)
{
onlymallocrealloc(&ptr, *ptr -> size * sizoef(*ptr -> tab[0]) + sizeof(**ptr), newsize * sizoef(*ptr -> tab[0]) + sizeof(**ptr));
if(*ptr)
{
*ptr -> size = newsize;
}
}
功能并不像乍看起来那么简单
给你。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
typedef struct
{
int *tab;
int size;
} arr;
int changeSizeDyn( arr *Dyn_arr, int size )
{
int success = 1;
if ( Dyn_arr->size != size )
{
int *tmp = NULL;
if ( size != 0 )
{
tmp = malloc( size * sizeof( int ) );
success = tmp != NULL;
if ( success )
{
int n = 0;
if ( Dyn_arr->size != 0 )
{
n = size < Dyn_arr->size ? size : Dyn_arr->size;
memcpy( tmp, Dyn_arr->tab, n * sizeof( int ) );
}
if ( n < size ) memset( tmp + n, 0, ( size - n ) * sizeof( int ) );
}
}
if ( success )
{
free( Dyn_arr->tab );
Dyn_arr->tab = tmp;
Dyn_arr->size = size;
}
}
return success;
}
int main( void )
{
arr a = { NULL, 0 };
int size = 10;
if ( changeSizeDyn( &a, size ) )
{
for ( int i = 0; i < size; i++ ) a.tab[i] = i;
for ( int i = 0; i < size; i++ ) printf( "%d ", a.tab[i] );
putchar( '\n' );
}
size = 5;
if ( changeSizeDyn( &a, size ) )
{
for ( int i = 0; i < size; i++ ) a.tab[i] = i;
for ( int i = 0; i < size; i++ ) printf( "%d ", a.tab[i] );
putchar( '\n' );
}
size = 0;
if ( changeSizeDyn( &a, size ) )
{
for ( int i = 0; i < size; i++ ) a.tab[i] = i;
for ( int i = 0; i < size; i++ ) printf( "%d ", a.tab[i] );
putchar( '\n' );
}
assert( a.tab == NULL && a.size == 0 );
}
程序输出为
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4
该函数有一个 return 类型 int
来表示它的调用是否成功。您需要一种方法来确定函数调用是否成功。否则将无法确定这一点。所以使用类型 void
作为函数的 return 类型是一个坏主意。
该函数默认将与旧数组元素不对应的所有新元素设置为零。其实不是必须的,只是让结构体的使用更加清晰。
如果用户传递的大小等于 0,则该函数只是释放旧数组并将数据成员 tab
设置为 NULL
。
如果数组的新大小和旧大小相等,则函数不执行任何操作。
请注意,将结构的数据成员 size
声明为类型 size_t
会好得多。否则,您需要在 size
不为负的函数中添加一个检查。我没有那样做,因为我认为您确实会在结构(和函数)声明中使用类型 size_t
而不是类型 int
。
struct Arr {
int *tab;
ptrdiff_t nmemb;
};
假设您最初是这样分配数组的:
struct Arr x;
x.nmemb = 7;
x.tab = malloc(sizeof(*x.tab) * x.nmemb);
你应该用这个函数重新分配它:
void change_size_dyn(struct Arr *dyn_arr, ptrdiff_t nmemb)
{
struct Arr old;
ptrdiff_t cp_nmemb;
if (!dyn_arr)
return;
old = *dyn_arr;
if (nmemb <= 0)
goto err;
dyn_arr->tab = malloc(sizeof(*dyn_arr->tab) * nmemb);
dyn_arr->nmemb = nmemb;
cp_sz = MIN(old.nmemb, nmemb);
memcpy(dyn_arr->tab, old.tab, cp_nmemb);
free(old.tab);
return;
err:
dyn_arr->tab = NULL;
dyn_arr->nmemb = 0;
free(old.tab);
}
应该这样称呼:
change_size_dyn(&x, 9);
您甚至可以在第一次分配时使用此功能(尽管您应该首先设置 NULL
和 0
这两个值)。您也不需要添加免费的;输入 0 会为您完成,就像 realloc
会做的那样:
int main(void)
{
struct Arr x = {0};
change_size_dyn(&x, 5);
/* ... */
change_size_dyn(&x, 9);
/* ... */
cleanup:
change_size_dyn(&x, 0);
return 0;
}
如果你传递一个结构,其中 dyn_arr->nmemb
已经是一个负值(不应该发生),行为是未定义的(那个负值将进入 memcpy
,它会被包装到一个非常高的 size_t
,这会溢出数组)。我不想检查它,因为在任何 non-buggy 场景中都没有必要。
Is it even possible to do that without using
realloc
?
当然是。
例如,您可以这样做:
#include <stdlib.h> /* for malloc () and free () and EXIT_xxx macros. */
#include <stdio.h> /* for perror */
typedef struct{
int *tab;
size_t size; /* Prefer using size_t for (memory) sizes over using a
signed int. */
} arr;
void changeSizeDyn(arr *parr, size_t size)
{
if (!parr && !parr->tab)
{
errno = EINVAL;
}
else
{
arr tmp = {
malloc(size * sizeof *tmp.tab),
size
};
if (tmp.size && !tmp.tab)
{
perror("malloc() failed");
}
else
{
for (
size_t m = (tmp.size < parr->size) ?tmp.size :parr->size, i = 0;
i < m;
++i)
{
tmp.tab[i] = parr->tab[i];
}
free(parr->tab);
*parr = tmp;
errno = 0;
}
}
}
/* A main() to test the above: */
int main(void)
{
const size_t s = 42;
arr a = {
malloc(s * sizeof *a.tab),
s
};
if (a.size && !a.tab)
{
perror("malloc() failed");
exit(EXIT_FAILURE);
}
/* populate a.tab[0] to a.tab[a.size - 1] here. */
changeSizeDyn(&a, 43);
if (0 != errno)
{
perror("changeSizeDyn() failed");
exit(EXIT_FAILURE);
}
/* Use a.tab[0] to a.tab[a.size - 1] here. */
free(a.tab);
a.size = 0;
}