考虑这个程序:
int main(void)
{
int* i = malloc(sizeof(int));
int* j = malloc(sizeof(int));
}
然而,这是一种天真的方法,因为malloc
可能会失败并且指针不是free
' d。
所以你可以这样做:
int main(void)
{
int* i;
int* j;
if ((i = malloc(sizeof(int)) < 0)
{
return -1;
}
if ((j = malloc(sizeof(int)) < 0)
{
free(i);
return -1;
}
free(i);
free(j);
}
但是我觉得这很容易出错。考虑必须分配20个指针,在上一个malloc
错误案例中,您必须free
19个变量,然后return -1
。
我也知道atexit
,这可以帮助我这样写:
int* i;
int* j;
void del_i(void)
{
free(i);
}
void del_j(void)
{
free(j);
}
int main(void)
{
if ((i = malloc(sizeof(int)) < 0)
{
return -1;
}
else
{
atexit(del_i);
}
if ((j = malloc(sizeof(int)) < 0)
{
return -1;
}
else
{
atexit(del_j);
}
}
哪个更好,但我不喜欢将所有指针声明为全局。有没有办法将这两种方法结合起来,基本上是:
atexit
一起使用。答案 0 :(得分:4)
free
上的 NULL
被定义为安全无操作。所以非跳跃变化可能是:
int *i = malloc(sizeof(int));
int *j = malloc(sizeof(int));
if(i && j)
{
// do some work
}
free(i);
free(j);
答案 1 :(得分:3)
首先,这将不检测malloc
失败:
if ((i = malloc(sizeof(int)) < 0)
{
return -1;
}
malloc
在失败时返回NULL
,而不是负数。
其次,atexit
适用于清理静态和全局对象。将本地对象设置为全局只是在atexit
内使用它们不是一个好主意。
更好的方法是为所有需要在all-or-nothing单元中分配的相关指针创建struct
,定义一个函数以便一次释放它们,并编写一个分配它们的函数逐个检查每个分配的内存:
typedef struct AllOrNothing {
double *dPtr;
int *iPtr;
float *fPtr;
size_t n;
} AllOrNothing;
void freeAllOrNothing(AllOrNothing *ptr) {
free(ptr->dPtr);
free(ptr->iPtr);
free(ptr->fPtr);
free(ptr);
}
int allocateAllOrNothing(size_t n, AllOrNothing **res) {
*res = malloc(sizeof(AllOrNothing));
if (*res == NULL) {
return -1;
}
// Freeing NULL is allowed by the standard.
// Set all pointers to NULL upfront, so we can free them
// regardless of the stage at which the allocation fails
(*res)->dPtr = NULL;
(*res)->iPtr = NULL;
(*res)->fPtr = NULL;
(*res)->n = n;
(*res)->dPtr = malloc(n*sizeof(double));
if ((*res)->dPtr == NULL) {
free(*res);
*res = NULL;
return -1;
}
(*res)->fPtr = malloc(n*sizeof(float));
if ((*res)->fPtr == NULL) {
free(*res);
*res = NULL;
return -1;
}
(*res)->iPtr = malloc(n*sizeof(int));
if ((*res)->iPtr == NULL) {
free(*res);
*res = NULL;
return -1;
}
return 0;
}
答案 2 :(得分:0)
int main(void)
{
int* i = NULL; // Init with NULL otherwise free on none NULL possible
int* j = NULLL;
if (!(i = malloc(sizeof(int)))
{
goto exit;
}
if (!(j = malloc(sizeof(int)))
{
goto exit;
}
...
exit:
free(i);
free(j);
...
return err;
}
这是你可以用goto语句解决的问题。
答案 3 :(得分:0)
int main(void)
{
int* i = NULL;
int* j = NULL;
bool success = false;
do {
i = malloc(sizeof(int));
if (NULL == i) break;
j = malloc(sizeof(int));
if (NULL == j) break;
success = true;
} while (0);
if (!success)
{
printf("Something failed!");
}
else
{
printf("All succeeded!");
// Do more work
}
free(i);
free(j);
return (success? 0 : 1);
}
答案 4 :(得分:0)
避免多个退出点。避免隔行扫描分配和错误处理。遵循清洁的操作顺序:
// Do all allocations first, test their `NULL`-ness, then free them all.
int main(void) {
// Allocate resources
// declare and allocate in one step
int* i = malloc(sizeof *i);
double* j = malloc(sizeof *j);
// Test for acceptability
bool ok = i && j;
// Perform the main body of code
if (ok) {
; // do normal process in the code;
}
// free resources
free(i);
free(j);
// return status
return ok ? 0 : -1;
}
答案 5 :(得分:-1)
int *i=NULL,*j=NULL;
if(!(i=malloc(sizeof(int))))
goto EXIT;
if(!(j=malloc(sizeof(int))))
goto EXIT;
/* do some work */
return 0;
EXIT:
free(i);
free(j);
exit(EXIT_FAILURE);
虽然goto被认为是一种糟糕的编程习惯 但在这里我们可以用它来轻松简单地完成任务