边界计算要注意的两条原则:
(1) 首先考虑最简单情况下的特例,然后将得到的结果外推,这是原则一;
(2) 仔细计算边界,绝不掉以轻心,这是原则二。
不对称边界编程思想的两种考虑方式:
1.用第一个入界点(包含在范围内)和第一个出界点(范围外的第一个数值)来表示一个数值范围;好处:1)取值范围的大小即为上界与下界之差,2)上界等于下界表示取值范围为空,3)即使取值范围为空,上界也永远不可能小于下界;
2.将上界视作某序列中第一个被占用的元素,下界视作某序列中第一个被释放的元素。
不对称边界应用举例和分析:考虑这样一个函数,该函数的功能是将长度无规律的输入数据送到缓冲区(一块能够容纳N个字符的内存),当缓冲区已满,就将缓冲区的全部内容写出。
缓冲区的可以是如下形式:
#define N 1024
static char buffer[N];
//根据不对称边界思想,bufptr应始终指向缓冲区中第一个未被占用的字符,而不是指向第一个已被占用的字符
static char *bufptr;
//将缓冲区的内容写出并重置bufptr指针
flushbuffer();
//写入函数,一次只能转移一个字符到缓冲区
void bufwrite(char* p, int n)
{
while(--n >= 0) // (--n >= 0)是n次迭代的一种方法,至少与等效的(n-- > 0)一样快
{
if(bufptr == &buffer[N])
//应用不对称边界思想,buffer[N]只能对其地址赋值和比较,不能直接引用其值,因为N超出了数组的元素的下标范围1~N-1
flushBuffer();
*bufptr++ = *p++;
}
}
//对上述算法的改进,这个程序的绝大部分开销来自于每次迭代时都要进行两个检查:一个检查用于判断循环计数器是否达到终值,另一个检查用于判断缓冲区是否已满,利用memcpy函数每次迭代转移k个字符到缓冲区
void bufwrite(char* p, int n)
{
while(n > 0)
{
int k,rem;
if(bufptr == &buffer[N])
flushBuffer();
rem = N - (bufptr - buffer);
k = n > rem ? rem : n;
memcpy(bufptr,p,k);
bufptr += k;
p += k;
n -= k;
}
}
//memcpy函数为C自带库函数,用汇编语言编写以提高运行速度,如果没有可以自己定义成如下形式
void memcpy(char* dest, const char* source, int n)
{
while(--k >= 0)
{
*dest++ = *source++;
}
}
