由一个bug想到的

    在暑假用VC++做的一个工程里面,有获取系统时间并保存为字符串的一段代码,如下:

	获得当前年月日,给全局变量strCurTime赋值///
	CTime currenttime = CTime::GetCurrentTime();//获得当前时间
	if( currenttime.GetMonth() < 10 && currenttime.GetDay() < 10 )//月份,日期都是个位数,补0
		strCurTime.Format("%d0%d0%d",currenttime.GetYear(),currenttime.GetMonth(),currenttime.GetDay());
	else if( currenttime.GetMonth() < 10 )//月份是个位数,日期不是个位数,月份前补0
		strCurTime.Format("%d0%d%d",currenttime.GetYear(),currenttime.GetMonth(),currenttime.GetDay());
	else if( currenttime.GetDay() < 10 )//月份不是个位数,日期是个位数,日期前补0
		strCurTime.Format("%d%d0%d",currenttime.GetYear(),currenttime.GetMonth(),currenttime.GetDay());

 
 
这段代码有问题,恰巧在单位数月份或单位数日期时运行不会出错,在月份和日期都是两位数时运行就会出问题。
做这个工程的时候是7、8月份,当时没有问题,现在10月份拿出来一运行就崩溃。

下面详细展示了我如何由报错找到问题所在:
崩溃后提示是STREX.CPP文件的第332行出现问题,windows搜索找出STREX.CPP文件,貌似里面是字符串操作的扩展功能。
找到第332行,如下:ASSERT(nFirst + nCount <= GetData()->nDataLength);
找到此句所在的函数:CString::Mid(int nFirst, int nCount),是从字符串中截取一段的函数,想到可能是调用Mid时下标越界。
在程序原文件中查找Mid函数,看看都在哪里用到。其中一句如下:
m_EDIT_CAM = strCurTime.Left(4)+"年"+strCurTime.Mid(4,2)+"月"+strCurTime.Right(2)+"日," + m_EDIT_CAM;
//strCurTime是全局变量,表示当前年月日,格式:YYYYMMDD
想到可能是strCurTime这个字符串有问题,这个字符串是在程序初始化函数中赋值的,遂找到程序初始化函数。
就找到了文章开头的那段代码,在此段代码后加一条输出语句做测试,输出strCurTime的值,发现竟然是空的。
仔细看这段代码,终于恍然大悟,发现一个很弱智但又很有意思的考虑不周全导致的bug。
月份和日期都是两位数时,不属于三个判断语句中的任何一个,所以不会给strCurTime赋值。
由此导致strCurTime是空字符串,再导致Mid函数越界,触发Assert,进而导致程序崩溃。

此过程学到了什么?
不是以后写代码时应该更加仔细,而是由错误一环一环向前推理,找出错误根源的能力。
因为人总会有考虑不全的时候,你再仔细还是会出错。linux的设计者Linus Torvalds在写linux内核时也留下了bug。
我觉得这类似“授之以鱼不如授之以渔”。
分析问题的能力是更重要的。

             —— 2012年10月14日   masikkk

实现一个环形缓冲区,可以定义一个结构体来表示它的属性: ```c typedef struct { int *buf; // 缓冲区指针 int head; // 头指针 int tail; // 尾指针 int size; // 缓冲区大小 } RingBuffer; ``` 初始化缓冲区的函数: ```c void init(RingBuffer *rb, int size) { rb->buf = (int*)malloc(size * sizeof(int)); rb->head = 0; rb->tail = 0; rb->size = size; } ``` 向缓冲区写入数据的函数: ```c void write(RingBuffer *rb, int data) { rb->buf[rb->tail] = data; rb->tail = (rb->tail + 1) % rb->size; // 尾指针移动到下一个位置 if (rb->tail == rb->head) { rb->head = (rb->head + 1) % rb->size; // 头指针移动到下一个位置 } } ``` 从缓冲区读取数据的函数: ```c int read(RingBuffer *rb) { if (rb->head == rb->tail) { return -1; // 缓冲区为空 } int data = rb->buf[rb->head]; rb->head = (rb->head + 1) % rb->size; // 头指针移动到下一个位置 return data; } ``` 判断缓冲区是否为空的函数: ```c int is_empty(RingBuffer *rb) { return (rb->head == rb->tail); } ``` 判断缓冲区是否已满的函数: ```c int is_full(RingBuffer *rb) { return ((rb->tail + 1) % rb->size == rb->head); } ``` 缓冲区的读写过程可以描述为:写入数据时,先将数据写入到尾指针指向的位置,然后尾指针向后移动一个位置,如果此时尾指针与头指针相等,说明缓冲区已满,需要将头指针向后移动一个位置。读取数据时,先判断缓冲区是否为空,如果不为空,将头指针指向的数据读取出来,然后头指针向后移动一个位置。 可能存在的bug风险点有: 1. 头指针或尾指针越界:在移动头指针或尾指针时,需要对指针进行取模操作,以确保它们始终在0到size-1之间。 2. 缓冲区数据覆盖:如果尾指针移动到了头指针的位置,说明缓冲区已满,需要将头指针向后移动一个位置,否则可能会导致数据被覆盖。 3. 多线程并发写入或读取:如果多个线程同时访问缓冲区,可能会导致数据不一致或者出现死锁等问题,需要使用同步机制来保证线程安全。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值