1. Q:为什么我不能对void *指针进行算术运算?
A:因为编译器不知道所值对象的大小,而指针的算法运算总是基于所指对象的大小的。
2. Q:C语言可以“按引用传参”吗?
A:不可以。严格来说,C语言总是按值传参,你可以模拟按引用传参,定义接受指针的函数,然后在调用时使用&操作符。但C没有任何真正等同于按引用传参的东西。
3. Q:怎样在整型和指针之间进行转换?能否暂时把整数放入指针变量,或者相反?
A:C标准中规定整数与指针之间的相互转换是实现定义的,因此没有了指针和整数之间无法修改就相互转换的保证。事实上强制进行整数和指针的相互转换从来就不是什么好的实践。当需要同时保存两种类型数据的存储结构时,使用联合是更好的办法。
4. Q:空指针到底是什么?
A:根据C语言定义,每一种指针类型都有一个特殊值——“空指针”,它与同类型的其他所有指针值都不相同,它“保证与任何对象或函数的指针值都不相等”。也就是说,空指针不会指向任何地方,它不是任何对象或函数的地址。取地址操作符&永远也不会返回空指针,对malloc的成功调用也不会返回空指针。注意,空指针在概念上不同于未初始化的指针,空指针可以确保不指向任何对象或函数,而未初始化的指针则可能指向任何地方。
5. Q:怎样在程序里获得一个空指针?
A:使用空指针常量。空指针常量可以是0或NULL(在stdio.h文件中)。根据C语言定义,在指针上下文中的“值为0的整型常量表达式”会在编译时转换为空指针。然而,传入函数的参数不一定被当作指针上下文,此时生成空指针需要显式的类型转换。下表总结了何时可以直接使用空指针常量,何时需要进行显式类型转换:
6. Q:如果NULL的值改变了,比如在使用非零内部空指针的机器上,用NULL(而不是0)不是更好吗?
A:不,尽管符号常量经常代替数字使用以备数字的改变,但这不是用NULL代替0的原因。C语言本身确保了源码中用于指针上下文的0会生成空指针。
7. Q:有没有什么简单的方法理解所有这些与空指针有关的东西?
A:遵循两条简单规则:(a) 当源码中需要空指针常量时,使用"0"或"NULL";(b) 如果在函数调用中"0"或"NULL"用作参数,把它转换成被调函数需要的指针类型。
8. Q:空指针是指向地址0的指针吗?
A:不能将空指针看作指向地址0的指针,空指针不指向任何地方。如果需要访问地址0,应该阅读厂商文档,使用机器提供的技巧来访问。
9. Q:在C语言中“指针和数组等价”到底是什么意思?
A:意思是数组和指针的算法定义使得可以用指针方便地访问数组或者模拟数组,换言之,在C语言中只是指针算术和数组下标运算等价,指针和数组是不同的。特别地,等价的基础来自这个关键定义:一个T数组类型的对象如果出现在表达式中会退化为一个指向数组第一个元素的指针,指针的类型是指向T的指针。
10. Q:如果你不能给它赋值,那么数组如何能成为左值呢?
A:术语“左值”并不完全表示“能赋值的东西”,更好的定义应该是“在内存中有特定位置的东西”。
11. Q:既然数组引用会退化为指针,如果array为数组,那么array和&array又有什么区别?
A:区别在于类型。在标准C中,&array生成一个“T型数组”的指针,指向整个数组;而array生成一个T型的指针,指向数组的首元素。
int a[10]; int *pInt = a; // a的类型是"int型的指针" int (*pArr)[10] = &a; // &a的类型是"10个int的数组的指针" int array[NROWS][NCOLUMNS]; int (*pArr2)[NCOLUMNS] = array; // array的类型是"NCOLUMNS个int的数组的指针" int (*pArr3)[NROWS][NCOLUMNS] = &array; // array的类型是"NROWS个NCOLUMNS个int的数组的数组的指针"