一次数组越界的bug经历
数组和指针都是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(,,weight_string); sprintf((char *)price_string,"%d",price);
Clear_Left_Num(money_string);
OLED_Show_String(,,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+) = ' ';
*(num_string+) = ' ';
*(num_string+) = ' ';
}
思路就是把小数点后一位后面的残余数据用空格刷新。
但是实验现象是在显示完第一行数据之后,本来应该在第二行显示第二个数据,但是他 在第一行数据的后面又显示了第二行的数据!!也就是说第二行数据显示了两次。
为什么会显示两次呢?我程序中就写了一次啊、、、
分析:
既然是显示的问题,那就先看看这个显示函数!
/*----------------------------------
**函数名称: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=;
while (chr[j]!='\0')
{
OLED_ShowChar(x,y,chr[j]); x+= ; if(x>){x=;y+=;} //自动换行写 j++;
}
}
原来这个函数会在数组结束之前,显示数组的全部内容。因为数组的最后一个结尾标志是 '\0’
那么,上面第一行一直在显示,说明他可能没有遇到数组结束标识符。
查看数组定义的大小:
unsigned char weight_string[] = {};
unsigned char price_string[] = {};
原来 weight_string 数组的最后一个结束标志被我赋值成了空格。那么他就会一直读取存储在这个数组后面的内存数据,并且给显示出来。也就是所谓的“数组越界”。
幸好我们只是读取显示,并没有改写这个数据!
既然他显示的是第二行的数据,说明第二行的数据就是存储在在这个数组后面的内存中。
查看编译器生成的map文件:
果然,第二个数组紧邻着第一个数组存储。
第一个数组读取越界之后,读到了第二个数组。
到此,问题解决。
总结:
一定要看到程序的内在联系。分析内存虽然困难,但是却是找到烦人bug 的捷径。
一次数组越界的bug经历的更多相关文章
- iOS如何彻底避免数组越界
我们先来看看有可能会出现的数组越界Crash的地方: ? 1 2 3 4 5 6 7 - (void)tableView:(UITableView *)tableView didSelectRowAt ...
- Objective-c防止数组越界而崩溃(全局效果)
数组越界其实是很基本的问题,但是解决起来除了count的判断,还有每个调用的时候都要去判断一遍 对于不明确的数据总会有崩溃的风险 然而 每次调用都判断 那是太累了 so ..runtime&c ...
- 数组越界保护与消息传递black机制
数组越界保护if(index.row <= [array count]) 发送消息[[NSNotificationCenter defaultCenter] postNotificati ...
- 解决Android时时更新listview数组越界问题
时时更新数据一般出现在金融.股票行业对数据的准确性要求极高情况下使用. 先来看看下面一段代码, public class MainActivity extends Activity { private ...
- Android 【问题汇总】列表数组越界的问题
遇到了一个诡异的问题,ListView发生数组越界(偶尔会),程序崩溃. 错误信息如下: W/dalvikvm( ): threadid=: thread exiting with uncaught ...
- iOS 数组越界 Crash加工经验
我们先来看看有可能会出现的数组越界Crash的地方. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSInd ...
- Java中的数组越界问题
Java中数组初始化和OC其实是一样的,分为动态初始化和静态初始化, 动态初始化:指定长度,由系统给出初始化值 静态初始化:给出初始化值,由系统给出长度 在我们使用数组时最容易出现的就是数组越界问题, ...
- java.sql.SQLException之数组越界
java.sql.SQLException之数组越界 1.具体错误如下: (1)java.sql.SQLException:Parameter index out of range(0<1) ( ...
- .NET 下 模拟数组越界
前面一篇文章提到过 数组越界行为,虽然编译器为我们做了大量的检查工作让我们避免这些错误. 但是我觉得还是有必要模拟一下数组越界,感受一下这个错误. 那么对于.NET来说我们怎么来模拟数组越界呢? 一. ...
随机推荐
- Linux下的 .o、.a、.so文件
http://blog.sina.com.cn/s/blog_656681710100qzmy.html 工程里很多函数只是有声明,找不到实现的代码.因为那些实现代码已经编译成库所以看不见,我所看见的 ...
- Gradle 1.12用户指南翻译——第三十三章. PMD 插件
本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...
- java 调用JRuby
1.core package vanilla; import org.jruby.embed.ScriptingContainer; public class HelloWorld { private ...
- linux下显示不规则图片窗口
测试环境是ubuntu15.04,使用的图形库是gtk+. 图片格式采用的是X11的xpm格式,首先从网上找一个背景透明的png图片,然后用图形转换工具(比如gimp)转换为xpm格式. 程序代码如下 ...
- 史上最全webview详解
本文来自:http://www.jianshu.com/users/320f9e8f7fc9/latest_articles WebView在现在的项目中使用的频率应该还是非常高的. 我个人总觉得HT ...
- C语言之多线程机制(程序可以同时被执行而不会相互干扰)
接触过linux的人或多或少知道,linux有多线程的机制,也就是说程序可以同时执行,不受干扰,关于这个在我以前的博文里有过类似模拟的时间片轮转程序,跟这个其实是类似的.其实在window上,线程的头 ...
- 在Eclipse 中集成SVN
在项目开发的过程中,我们需要用到版本控制工具,最常见的也就是SVN了,下面就来介绍最简单的一种在Elipse中集成svn工具. 第一步:下载 svn包,如site-1.6.5.zip或者site-1. ...
- SAP BADI的“多次使用”(multiple use)
SAP中的某些BADI是不允许多用(multiple use)的,即不能同时存在多个活动的增强实施类.如下图中的这种,无论为其创建多少个实施类,都只有活动的那一个会被触发: tips : 业务加载项定 ...
- STL容器的基本特性和特征
1. STL有6种序列容器类型(1)vector它提供对元素的随即访问,在尾部添加和删除元素的时间是固定的,在头部或中部插入和删除元素的复杂度为线性时间.(2)deque在文件中声明.是双端队列,支持 ...
- Python函数式实现单例特性
传统的单例一般是基于类的特性实现,Python模块是天生的单例,下面来个简单的借助模块和函数实现单例特性: gdb = None def get_gdb(): global gdb if gdb is ...