问:使用指针的困难之一是,我们往往会误用它,并且这种错误不是在编译被编译器捕获时,而是发生在运行时。下列几段代码,哪些会造成编译时错误,哪些会造成运行时错误,为什么?
a)char *sptr = "abc",*tptr;b)char *sptr = "abc",*tptr;
*tptr = sptr;tptr = sptr;
c)char *sptr = "abc",*tptr;d)int *iptr = (int *)10;
*tptr = *sptr;*iptr = 11;
e)int *iptr = 10;f)int *iptr = (int *)10;
*iptr = 11;iptr = NULL;
答:a)编译时错误。因为*tptr是一个字符,而sptr是一个指向字符的指针,代码试图将一个字符指针赋给一个字符,很显然这会产生类型冲突。b)没有错误。因为tptr和sptr都是字符指针。c)可能产生运行时错误。因为程序并没有为tptr分配存储空间。当解引用tptr时,无法确定它的指向。d)可能产生运行时错误。因为将一个固定的地址赋值给一个整型指针是很危险的。当解引用iptr时,我们会把11写到地址为10的*iptr中,这种操作很可能不合法。e)可能产生运行时错误或者警告。因为此代码尝试将一个整数赋给一个整型指针,很多时候这种操作并不合法或会造成类型冲突。f)没有错误。因为,虽然程序一开始做了一个将固定地址赋给整型指针iptr的危险操作,但它立刻将此指针设置为NULL,这是正确的操作。
问:回想一下,我们用指针的算术运算来计算指针。如果指针p包含地址0x 10 000 000,那么在以下表达式中p将访问哪个内存地址?且p在此地址会访问多少字节的数据?
- *(p + 5)
答:这个问题的答案取决于指针p的类型。回想一下,当向指针p加上整数i时,所得到的并不是p指向的地址加上i个字节,而是p指向的地址加上i乘以p所引用的数据类型大小个字节。由于问题中没有说明指针p的类型,因此无法知道以上表达式将访问到哪个地址。同样,p的类型也决定要访问多少字节的数据,所以我们也无法知道将会访问多少个字节的数据。
问:链表的操作list_rem_next会从链表中删除一个元素(见第5章)。iptr是一个整型指针,如果我们想要把此指针指向从链表中删除的整数,那么我们如何调用list_rem_next来替代本章之前所提到的方法?函数的原型如下所示,list为链表,element引用将要删除的元素,并在函数返回时data指向已删除的数据。
- int list_rem_next(List *list, ListElmt *element, void **data);
答:另一种调用list_rem_next的方法如下所示。在该方法中,将iptr转换为一个void指针来代替之前的指向void指针的指针。这种调用方式可以接受因为void指针与其他类型相兼容。但是还是要说明一下,我们之前的调用方式更加清晰,因为这与list_rem_next原型相一致。
- retval = list_rem_next(&list, element, (void *)&iptr);



