数组和指针都是 C 里面的好东西, 但是一旦使用不当, 真的会让人抓狂.
下面是写程序时遇到的一次数组越界的经历, 感觉对以后写程序有点启发, 所以记录下来.
起因:
我想用 OLED 动态显示一组浮点数, 而且浮点数的长度是不定的.
1, 如果只是单纯的显示, 没有消隐的话, 上一次的长数的据残留会影响下一次短长度数据的显示.
2, 如果显示一次就清空一次显示区域的话, 数据会一直抖动, 一开始以为是我刷新频率不够, 故把刷新频率由 100HZ 改为 1000HZ, 但是效果还是和之前一样!
后来想想也是, 不管我把刷新频率改为多少, 清空后的空白和显示的数据都是相同的频率. 1000hz 显示数据, 那么也是 1000hz 的空白. 所以会抖动严重.
3, 把数据的每一位都取出来单独显示, 但是这样就又带来了数据对齐的问题. 不爽, 不好看, 弃之.
4, 使用 sprintf 格式化需要显示的数据为字符串. 然后用 OLED 的显示字符串的方式显示.
于是有了下面这样的程序:
- sprintf((char *)weight_string,"%.1f",weight); // 格式化为字符串
- Clear_Left_Num(money_string); // 消除残余
- OLED_Show_String(42,2,weight_string);
- sprintf((char *)price_string,"%d",price);
- Clear_Left_Num(money_string);
- OLED_Show_String(42,4,price_string);
这段程序在定时器中断函数中调用. weight 和 price 就是我想显示的浮点数.
先格式化为字符串, 然后显示. OLED_Show_String() 的前两个参数是字符的起始显示坐标.
Clear_Left_Num 函数如下:
- void Clear_Left_Num(unsigned char *num_string)
- {
- while(*num_string != '.')
- num_string++;
- // 一位小数点后面的数据用空格刷新
- *(num_string+2) = ' ';
- *(num_string+3) = ' ';
- *(num_string+4) = ' ';
- }
思路就是把小数点后一位后面的残余数据用空格刷新.
但是实验现象是在显示完第一行数据之后, 本来应该在第二行显示第二个数据, 但是他 在第一行数据的后面又显示了第二行的数据!! 也就是说第二行数据显示了两次.
为什么会显示两次呢? 我程序中就写了一次啊,,,
分析:
既然是显示的问题, 那就先看看这个显示函数!
- /*----------------------------------
- ** 函数名称: OLED_Show_String
- ** 功能描述: 光标处显示字符串, 字符串可以用数组表示, unsigned char string_2[] = {"THIS IS A TEST"};
- ** 参数说明: X,Y 为坐标
- * chr: 字符串首地址
- ** 作者: Andrew
- ** 日期: 2018.1.24
- -----------------------------------*/
- void OLED_Show_String(u8 x, u8 y, u8 *chr)
- {
- u8 j=0;
- while (chr[j]!='\0')
- {
- OLED_ShowChar(x,y,chr[j]);
- x+= 8 ;
- if(x>120){x=0;y+=2;} // 自动换行写
- j++;
- }
- }
原来这个函数会在数组结束之前, 显示数组的全部内容. 因为数组的最后一个结尾标志是 '\0'
那么, 上面第一行一直在显示, 说明他可能没有遇到数组结束标识符.
查看数组定义的大小:
- unsigned char weight_string[7] = {0};
- unsigned char price_string[3] = {0};
原来 weight_string 数组的最后一个结束标志被我赋值成了空格. 那么他就会一直读取存储在这个数组后面的内存数据, 并且给显示出来. 也就是所谓的 "数组越界".
幸好我们只是读取显示, 并没有改写这个数据!
既然他显示的是第二行的数据, 说明第二行的数据就是存储在在这个数组后面的内存中.
查看编译器生成的 map 文件:
果然, 第二个数组紧邻着第一个数组存储.
第一个数组读取越界之后, 读到了第二个数组.
到此, 问题解决.
总结:
一定要看到程序的内在联系. 分析内存虽然困难, 但是却是找到烦人 bug 的捷径.
来源: https://www.cnblogs.com/qsyll0916/p/9061841.html