有些形式的指针算术是允许的,有些则不允许。在第8章中我们学习到了指针程序,但可能并没有对此做太多考虑。
现在,让我们深入研究一下在代码中使用指针时会发生什么。看看清单9-1中的代码。代码清单9-1.Using Pointers
首先要注意的是,我们包含了一个名为string.h的头文件。如果你读了这个文件,然后你会发现各种各样的函数用来操作字符串和内存。在该头文件中找到的大多数函数声明都是SystemV标准C库的,有些已经存在了几十年。如果你有兴趣了解有关给定库函数的更多信息(例如,memcmp),用搜索引擎搜索函数名,将得到关于该函数的大量信息。如前所述,搜索库在编写自己的函数之前。你需要的东西很可能已经写好了。
你将在string.h头文件中找到的函数声明之一是:
extern char*strcpy(char*,const char*);
它将第二个参数常量字符指针指向的字符复制到第一个参数指向的字符数组中[在此上下文中使用时,const表示函数不更改第二个参数指向的数据。因为strcpy()知道左值对于第二个参数,它可以更改其内容。常量限定符告诉编译器不要让这种情况发生]。因此,语句:
strcpy(buffer,"When in the course of human events");
只需将引用复制到缓冲区中。
声明:
ptr=buffer;
只需初始化ptr以指向缓冲区。也就是说,它将缓冲区的左值复制到ptr的右值中。记住:数组名本身就是数组的左值。想一想到目前为止所说的话,直到你确定理解了最后两句话的意思。
编译、上传和运行程序时,输出与图9-1所示类似。
图9-1 程序输出结果
从图9-1可以看出,ptr存储在内存地址2242处,缓冲区的左值为2244。第二行确认ptr确实指向缓冲区。然后,代码进入while循环以显示缓冲区的内容,并通过ptr引用它。这与第8章中使用的程序类型几乎相同。
现在,将以下代码添加到程序中,就在对Serial.flush()的调用上方:
现在运行程序。图9-2显示了运行程序时的输出。
(www.xing528.com)
图9-2 程序输出结果
图9-2中显示的信息“事件”一词,后面的所有无用垃圾信息都是关于什么的?换句话说,声明是什么:
Serial.print(*(ptr+i));
输出这种使用指针算法的程序变量数据,在上一章中已出现过,但在这里不起作用。为什么?
要解决问题,请查看由while循环控制的语句:
Serial.print(*ptr++);
现在问问自己:为什么while循环终止了?while循环终止的原因是ptr已递增,因此它指向存储在缓冲区中的null字符。从清单9-1中的信息可以看出,缓冲区包含34个字符,加上一个空字符。当while循环终止时,ptr的右值必须为2277(即2242+35)。然后,程序代码落入for循环和语句:
Serial.print(*(ptr+i));
结果:
Serial.print(*(2277+0));
它试图显示在缓冲区数组中存储的引号之后存储在内存中的任何内容!这是SRAM存储中的无用数据。相信笔者,这几乎是每个C程序员都曾犯过的低级错误。
那么,解决办法是什么?非常简单,就是在需要重新使用指针操作时复位一下指针即可:
ptr=buffer;//Reset the pointer back to buffer[0]...
Serial.println("");//So the output prints on a new line
然后再运行一次。现在输出(如图9-3所示)与预期一致。
图9-3 程序输出结果
始终记住:当递增指针时,它不会自动重置自身。由for循环控制的语句:
Serial.print(*(ptr+i));显示加法是一种允许的指针算术形式。我们在第8章中已了解到,所有指针算法都经过缩放,以适合所指向的数据。在本例中,char数据类型的标量为1字节,因此循环中的每一次传递都会向ptr的右值添加1,代码将遍历引号。如果ptr指向int数据,则表达式:
(ptr+i)在Serial.print()中,由于int的标量是2字节,因此语句在每次传递时都会向ptr添加2。
因此,指针加法的算术运算是合法的,并且会根据所使用的数据类型自动进行缩放。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。