我一直在学习C ++,并且很难理解null。特别是,我阅读的教程提到进行“空检查”,但是我不确定这意味着什么或为什么有必要。
- 到底是什么?
- “检查为空”是什么意思?
- 我是否总是需要检查null?
任何代码示例将不胜感激。
我一直在学习C ++,并且很难理解null。特别是,我阅读的教程提到进行“空检查”,但是我不确定这意味着什么或为什么有必要。
任何代码示例将不胜感激。
Answers:
在C和C ++中,指针本质上是不安全的,也就是说,当您取消引用指针时,确保指针指向有效的位置是您的责任。这是“手动内存管理”的一部分(与Java,PHP或.NET运行时等语言中实现的自动内存管理方案相对,后者不允许您花费大量精力创建无效的引用)。
捕获许多错误的常见解决方案是将所有不指向任何内容的指针设置为NULL
(或,在正确的C ++中0
),并在访问指针之前对其进行检查。具体而言,通常的做法是所有的指针初始化为NULL(除非你已经拥有的东西,当你宣布他们在指向他们),并将它们设置为NULL,当你delete
或free()
他人(除非他们后立即去的范围了)。示例(在C语言中,也是有效的C ++语言):
void fill_foo(int* foo) {
*foo = 23; // this will crash and burn if foo is NULL
}
更好的版本:
void fill_foo(int* foo) {
if (!foo) { // this is the NULL check
printf("This is wrong\n");
return;
}
*foo = 23;
}
如果没有空检查,则将NULL指针传递给此函数将导致段错误,并且您无能为力-操作系统将简单地杀死您的进程,并可能会进行核心转储或弹出崩溃报告对话框。使用null检查后,您可以执行适当的错误处理并优雅地恢复-自己纠正问题,中止当前操作,编写日志条目,并在适当时通知用户。
其他答案几乎涵盖了您的确切问题。进行空检查以确保您收到的指针实际上指向类型的有效实例(对象,基元等)。
不过,我将在此处添加我自己的建议。避免空检查。:)空检查(以及其他形式的防御性编程)使代码混乱,实际上使它比其他错误处理技术更容易出错。
关于对象指针,我最喜欢的技术是使用Null Object模式。这意味着返回一个(指针,或者甚至更好地引用)一个空数组或列表而不是null,或者返回一个空字符串(“”)而不是null,甚至是字符串“ 0”(或等同于“ nothing”的东西) (在上下文中)。您希望将其解析为整数。
另外,您可能还不了解空指针,这是1965年CAR Hoare为Algol W语言首次实现的。
我称之为我的十亿美元错误。这是在1965年发明空引用的。那时,我正在设计第一个全面的类型系统,用于面向对象语言(ALGOL W)的引用。我的目标是确保所有引用的使用都绝对安全,并由编译器自动执行检查。但是我忍不住要插入一个空引用的诱惑,仅仅是因为它是如此容易实现。这导致了无数的错误,漏洞和系统崩溃,在最近四十年中可能造成十亿美元的痛苦和破坏。
空指针值表示定义明确的“无处”;它是一个无效的指针值,可以保证将其与其他任何指针值进行比较。尝试取消引用空指针会导致未定义的行为,并且通常会导致运行时错误,因此您需要在尝试取消引用之前确保指针不是NULL。许多C和C ++库函数将返回空指针以指示错误情况。例如,如果库函数malloc
无法分配已请求的字节数,则该库函数将返回空指针值,并且尝试通过该指针访问内存(通常)通常会导致运行时错误:
int *p = malloc(sizeof *p * N);
p[0] = ...; // this will (usually) blow up if malloc returned NULL
因此,我们需要malloc
通过p
对照NULL 的值来确保调用成功:
int *p = malloc(sizeof *p * N);
if (p != NULL) // or just if (p)
p[0] = ...;
现在,请稍等片刻,这会有些颠簸。
有一个空指针值和一个空指针常量,并且两者不一定相同。空指针值是基础体系结构用来表示“无处”的任何值。此值可以是0x00000000、0xFFFFFFFF,0xDEADBEEF或完全不同的值。不要假定空指针值始终为0。
空指针常量 OTOH始终是一个0值的整数表达式。就您的源代码而言,0(或任何等于0的整数表达式)表示空指针。C和C ++都将NULL宏定义为空指针常量。编译代码时,空指针常量将在生成的机器代码中替换为适当的空指针值。
另外,请注意,NULL只是许多可能的无效指针值之一;如果您声明一个自动指针变量而没有显式初始化它,例如
int *p;
最初存储在变量中的值是不确定的,并且可能不对应于有效或可访问的内存地址。不幸的是,在尝试使用非NULL指针值之前,没有(便携式)方法可以判断该值是否有效。因此,如果要处理指针,通常最好在声明它们时将它们显式初始化为NULL,并在它们未主动指向任何对象时将它们设置为NULL。
注意,与C ++相比,这在C语言中更多的是问题。惯用的C ++不应过多使用指针。
有两种方法,基本上都可以做同样的事情。
int * foo = NULL; //有时设置为0x00或0或0L而不是NULL
空检查(检查指针是否为空),版本A
if(foo == NULL)
空检查,版本B
if(!foo)//因为NULL被定义为0,所以!foo将从空指针返回一个值
空检查,版本C
if(foo == 0)
在这三个中,我更喜欢使用第一个检查,因为它明确告诉未来的开发人员您要检查的内容,并且可以清楚地表明您期望foo为指针。
你不知道 在C ++中使用指针的唯一原因是因为您明确希望存在空指针。否则,您可以参考,这在语义上既易于使用,又保证非null。
export
)和所有C ++ 03库功能以及 TR1 和大量C ++ 11。