2.7 问与答
问:使用指针的困难之一是,我们往往会错误的使用它,并且这种错误不是发生在编译时,而是发生在运行时。下列几段代码,哪些会造成编译时错误,哪些会造成运行时错误,为什么?
a) char *sptr = "abc",*tptr; *tptr = sptr; | b) char *sptr = "abc",*tptr; tptr = sptr; |
c) char *sptr = "abc",*tptr; *tptr = *sptr; | d) int *iptr = (int *)10; *iptr = 11; |
e) int *iptr = 10; *iptr = 11; | f ) int *iptr = (int *)10; iptr = NULL; |
答:a)编译时错误。*tptr是一个字符,而sptr是一个指向字符的指针,代码试图将一个指针变量分配给一个字符变量,很显然这会产生类型冲突。
b)没有错误。因为tptr和sptr都是字符指针。
c)可能产生运行时错误。因为程序并没有为tptr分配存储空间。
d)可能产生运行时错误。因为将一个固定的地址赋值给一个整型指针是很危险的。在代码中,我们会把11写到地址为10的*iptr中,这种操作很可能不合法。
e)可能产生运行时错误或者警告。因为此代码尝试将一个整型赋值给一个整型指针,很多时候这种操作并不合法或会造成类型冲突。
f)没有错误。因为,虽然程序一开始做了一个将固定地址赋值给整型指针iptr的危险操作,但它立刻将此指针设置为NULL,这是正确的操作。
问:回想一下,我们用指针的算术运算来计算指针。如果指针p包含地址0x10000000,那么在以下表达式中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);
PS:
1、此书(Mastering Algorithms with C)译稿版权归本人(Love_Lei)及好友(bigship)共同所有,未经本人同意谢绝一切转载,并不得抄袭,模仿,盗版!更请大家监督盗版之人!
2、由于本人水平有限,如对译文有任何建议和异议,欢迎大家留言指正,我们共同讨论学习!谢谢!