![单片机C语言程序设计实训100例:基于STC8051+Proteus仿真与实战](https://wfqqreader-1252317822.image.myqcloud.com/cover/270/43738270/b_43738270.jpg)
1.10 数组、字符串与指针
大量单片机应用程序设计会用到数组定义,例如,下面的数组SEG_CODE定义了0~9的七段数码管段码表:
![](https://epubservercos.yuewen.com/DF9E4A/23020648309755406/epubprivate/OEBPS/Images/42553-00-40-2.jpg?sign=1739311763-Gi7Q8vCR6PyhukTX0suTumckdDjPhoUK-0-796f68d3874c9fc560858c006c7260c1)
由于程序运行过程中SEG_CODE数组数据保持不变,因此上述语句将存储类型设为code。如果将code改为data也不会影响程序的运行,但程序运行时数组会被分配到RAM中,而不是仅占用Flash ROM空间。在Small模式下,省略code相当于将程序存储类型设为默认的data类型。
编写单片机C语言程序时,如果定义的数组元素是动态变化的,则它必须被定义在RAM中。由于data类型仅允许使用128B内存,如果编译时提示RAM空间不够,可尝试将data改为idata,例如:
![](https://epubservercos.yuewen.com/DF9E4A/23020648309755406/epubprivate/OEBPS/Images/42553-00-40-3.jpg?sign=1739311763-kxjTVzqAzVAXPRDiSGwedBuKwCvpyhud-0-74da18f3edf52cc0e5b968f8f7963880)
另外,存储类型code、data和idata还可以放到数据类型前面。
字符串类型在单片机C语言程序设计中也会被大量使用,例如,下面的字节串定义:
![](https://epubservercos.yuewen.com/DF9E4A/23020648309755406/epubprivate/OEBPS/Images/42553-00-40-4.jpg?sign=1739311763-6kSoNZ5SK7HnsvmvDUslo8wgr4WIGJz4-0-a96890ca0e411b0123e4533a789eaa58)
这3种定义是相同的,它们都占用20B存储空间,实际串长均为16个字符,且最后未明确赋值的4个字节全部为0x00(即'\0')。在液晶屏上显示这类字符串时,可用以下方法:
![](https://epubservercos.yuewen.com/DF9E4A/23020648309755406/epubprivate/OEBPS/Images/42553-00-40-5.jpg?sign=1739311763-BctSDzCH8EwYKbI7r2uoXq83mOkxm6Nr-0-b40e6dcfbaa920f8bfe6fbfc9700ad87)
要注意的是,如果字符串长为16,而字符数组空间也只固定给出了16B,那么上述方法中的后两种就不可靠了。这是因为最后一个字符后面不一定是字符串结束标志'\0'(0x00)。
字符串还可以这样定义:
![](https://epubservercos.yuewen.com/DF9E4A/23020648309755406/epubprivate/OEBPS/Images/42553-00-40-6.jpg?sign=1739311763-Aihh4SYkgS3syPhPhzzyMpzIRkvRLXwA-0-2b04ec6e7593327db5de48a372f724ca)
这两种定义也是相同的,其字符串长均为16个字符,所占用存储空间均为17B。这是因为字符串末尾被自动附加了结束标志字节0x00('\0')。
在已知字符串长时,上述3种字符串显示方法均可使用。在字符串长未知时,可使用上述方法中的后两种。另外,上述显示方法还可以改写成:
![](https://epubservercos.yuewen.com/DF9E4A/23020648309755406/epubprivate/OEBPS/Images/42553-00-41-1.jpg?sign=1739311763-G4bEf5Jwdbm9Y3N0grzRdvVL9i7C44e8-0-1b806018d78ecc3d577b6eaaedd1becc)
在编写C语言程序时,除了常使用字符数组(字符串)以外,还会用到字符串数组,例如:
![](https://epubservercos.yuewen.com/DF9E4A/23020648309755406/epubprivate/OEBPS/Images/42553-00-41-2.jpg?sign=1739311763-CJHGSeEHLrEtFJU0HjJVlpjP80lTWTWP-0-b1b7e00a88ba0f4c318a8ebdef50d202)
如果要在液晶屏上显示“Counter:”这个字符串,可用以下语句实现:
![](https://epubservercos.yuewen.com/DF9E4A/23020648309755406/epubprivate/OEBPS/Images/42553-00-41-3.jpg?sign=1739311763-Pk5o6fDinI1JM3bIX7fGVJvvGqDtyKCn-0-cbc858793c3da8488420ade47fb6aa29)
在英文字符液晶屏上显示数值时,要将待显示数据转换为字符串。这时,可用此前提到的数据位分解方法,先分解出各位数字,然后加上0x30('0')得到对应数字的ASCII编码。
另一种更为简单的方法是使用sprintf函数,示例代码如下:
![](https://epubservercos.yuewen.com/DF9E4A/23020648309755406/epubprivate/OEBPS/Images/42553-00-41-4.jpg?sign=1739311763-xAUlmIMDjvf5T1aPk3a4bxapKhLC44TN-0-6d8c8b43864f42fa8d3b637303b464b1)
上述语句运行后,Buf会被以下字节填充:
![](https://epubservercos.yuewen.com/DF9E4A/23020648309755406/epubprivate/OEBPS/Images/42553-00-41-5.jpg?sign=1739311763-9dRKxjygF528iXSa8HmGTAryOllwC2AD-0-2e722d93061be08bf7429caf7139d0eb)
这些字节代表字符串“-123.45”,其最前面有一空格,用于填充使其总长到8字符,该字符串可直接送液晶屏显示。Keil C跟踪Buf的填充效果如图1-16所示。
![](https://epubservercos.yuewen.com/DF9E4A/23020648309755406/epubprivate/OEBPS/Images/42553-00-41-6.jpg?sign=1739311763-qhVa843bugXxMUG0RwYyNdljuQpXL5dZ-0-528f5d099723cdb0d1273850114b5564)
图1-16 Keil C跟踪Buf的填充效果
如果已经有语句:
![](https://epubservercos.yuewen.com/DF9E4A/23020648309755406/epubprivate/OEBPS/Images/42553-00-41-7.jpg?sign=1739311763-VJati70D8ALw80pvvJJ7RfyOA15k9iSh-0-d68b0dc1f815a4d1bc9824ce30c54d82)
语句sprintf(Buf+7, "%8.2f", x)会使Buf中的字符串变为“Result:-123.45”。此外,可以使用下面的语句得到同样的结果:
![](https://epubservercos.yuewen.com/DF9E4A/23020648309755406/epubprivate/OEBPS/Images/42553-00-41-8.jpg?sign=1739311763-Pm1ooA5pFkiCvPUDmWXTNpRnVYIRFxJY-0-03fe5bcd62558e278c8d34882f046a66)
另外,C语言还提供了与字符串有关的数据转换函数atoi、atol、atof、strtod、strtol、strtoul。在程序设计中涉及数据输入/输出、运算与显示时,可以恰当使用这些函数。
指针是C语言的重要特色之一,对于语句:
![](https://epubservercos.yuewen.com/DF9E4A/23020648309755406/epubprivate/OEBPS/Images/42553-00-41-9.jpg?sign=1739311763-WPIHK9KAu3e4RnYpZFlogG5CceOq5as0-0-485b84a2e5575a6e2a548c447dd13c73)
pd指向数组d中的第0个字节。显示数组内容可使用下面的代码:
![](https://epubservercos.yuewen.com/DF9E4A/23020648309755406/epubprivate/OEBPS/Images/42553-00-41-10.jpg?sign=1739311763-G47tZbmyw5pztPOpcPpDrw9tClDH6NeC-0-4620bd052d2c68f81edeaeadb672cb72)
但是不能使用下面的代码:
![](https://epubservercos.yuewen.com/DF9E4A/23020648309755406/epubprivate/OEBPS/Images/42553-00-41-11.jpg?sign=1739311763-bXV4lyysla0aAXIMsrrsyeEK94BpbYAC-0-1fa06e3fd9de9c0fe9ed56eaf06dc704)
数组名d虽然也是第0个字节的地址,但它不能在运行过程中改变,尽管数组名同样是数组中第0个元素的指针。某些函数定义中的形参为数组,调用函数时给出的实参常为指向同类型数据的指针,反之形参为指针,实参为数组名也很常见。
此前讨论的字符串示例中也出现了指针应用,这些应用同样要熟练掌握。
由于8051及其派生系列单片机具有独特的结构,Keil C51支持以下两种不同类型的指针。
1. 通用指针
上述示例u8 *pd中的pd就是通用指针。其指针声明与标准C语言完全一样。其特点是总用3个字节来存储指针,第1个字节表示存储器类型,第2、3个字节分别是指针所指向数据地址的高字节和低字节。这种定义很方便但执行速度较慢,在所指向的目标空间不明确时普遍使用。
2. 存储器指针
存储器指针在定义时指明了存储器类型,并且总指向特定的存储器空间(片内RAM、片外RAM或ROM),例如:
![](https://epubservercos.yuewen.com/DF9E4A/23020648309755406/epubprivate/OEBPS/Images/42553-00-42-1.jpg?sign=1739311763-LNRlVXg98XC6hELvQ93Klc1KSP1kBT2j-0-c8c5a92eee39848ef82f993979ac11dd)
由于定义中已经指明了存储器类型,因此相对于通用指针而言,存储器指针第一字节被省略了。对于data、bdata、idata存储器类型,存储器指针仅需要1个字节,因为它们的寻址空间都在256B以内。对code和xdata存储类型,存储器指针则需要2个字节,因为它们的寻址空间最大为64KB。
使用存储器指针比使用通用指针所占存储空间小、执行速度更快。在存储空间一定时,建议使用存储器指针。如果存储空间不确定,则使用通用指针。