我个人总是使用它们检查函数内部的值,但是在我们的大学,老师希望我们总是检查函数之外的值。如果我们要使用相同的检查值多次调用该函数,我认为在函数外检查一次值是个好主意。但是,如果您忘记检查关键值,它可能会给您带来错误,例如程序中的分段错误。
我已经粘贴了我正在处理的代码。在学校,我们应该检查功能以外的价值,但我认为这很疯狂,在这种情况下浪费时间。 main函数位于代码的末尾,您可以在检查malloc的返回值(函数外部的init_unsecure和函数内的init_secure)时或者在删除元素之前检查元素是否存在时看到区别(复制函数外的remove_unsecure)存在函数中的while循环和函数内的remove_secure。
你怎么看?查看函数内部的值是不是很明显?#include <stdlib.h>
typedef struct strens
{
int v[100];
int n;
} StrEns, *Ens;
// init struct pointer (need to check if return value is not NULL)
Ens init_unsecure()
{
Ens e;
if ((e = malloc(sizeof(StrEns))) != NULL)
e->n = 0;
return e;
}
// init struct pointer and check if malloc is not NULL
Ens init_secure()
{
Ens e;
if ((e = malloc(sizeof(StrEns))) == NULL)
exit(EXIT_FAILURE);
e->n = 0;
return e;
}
// insert element
Ens insert(Ens e, int x)
{
e->v[e->n] = x;
++e->n;
return e;
}
// return if element exists or not
int exists(Ens e, int x)
{
int i = 0;
while (i < e->n && e->v[i] != x)
++i;
return (i != e->n);
}
// remove element (need to check if element exists before)
Ens remove_unsecure(Ens e, int x)
{
--e->n;
int i = 0;
while (e->v[i] != x)
++i;
e->v[i] = e->v[e->n];
}
// remove element if exists
Ens remove_secure(Ens e, int x)
{
--e->n;
int i = 0;
while (i < e->n && e->v[i] != x)
++i;
e->v[i] = e->v[e->n];
}
// comparing init_unsecure vs init_secure && remove_unsecure vs remove_secure
int main()
{
Ens e1, e2, e3;
if ((e1 = init_unsecure()) == NULL)
return EXIT_FAILURE;
if ((e2 = init_unsecure()) == NULL)
return EXIT_FAILURE;
if ((e3 = init_unsecure()) == NULL)
return EXIT_FAILURE;
e1 = init_secure();
e2 = init_secure();
e3 = init_secure();
if (exists(e1, 42))
remove_unsecure(e1, 42);
if (exists(e2, 42))
remove_unsecure(e2, 42);
if (exists(e3, 42))
remove_unsecure(e3, 42);
remove_secure(e1, 42);
remove_secure(e2, 42);
remove_secure(e3, 42);
return EXIT_SUCCESS;
}
答案 0 :(得分:1)
C编程中的(仍然)主流思维方式是你的函数的调用者知道他在做什么,因此应该提供有效的参数。不这样做被广泛认为是未定义行为的原因。
例如,free
不必验证您传递的指针是否先前由malloc
返回,因为这会影响性能。只要调用函数的代码是正确的并且在预期范围内提供每个参数,即使没有在函数内部进行防御性检查,一切都应该没问题。
但是,仍然建议在整个代码中使用断言,以便作为程序员能够尽早捕获异常。