循环变量到底应该使用int还是unsigned int?

通常循环变量在循环中会充当数组下标,所以为了保证不出线向下越界,直觉上我们会选择使用unsigned int类型的循环变量。

但在运行下面这段代码的时候,问题出现了。

 

template <class T> void Adjust(T * arr, const unsigned int i, const unsigned int length){
	T temp = arr[i];
	unsigned int k;
	for (unsigned int j = i * 2 + 1; j < length; j = (k * 2) + 1){
		
		if (j + 1 < length)
			k = (arr[j] > arr[j + 1]) ? j : j + 1;
		else
			k = j;
		
		if(arr[k] > temp){
			arr[(j - 1) / 2] = arr[k];
			arr[k] = temp;
		}
		else
			break;
	}
}

template <class T> void HeapSort (T * arr, const unsigned int length){
	for (unsigned int i = (length / 2) - 1; i >= 0; i--){
		Adjust(arr, i, length);
		// (length / 2) - 1 == index of maximum non-leaf node.
	}
	T temp;
	for (i = length - 1; i > 0; i--){
		temp = arr[i];
		arr[i] = arr[0];
		arr[0] = temp;
		Adjust(arr, 0, i);
	}
}

  

调用HeapSort时,程序无法退出。在刚写完这段程序时,Adjust函数中的下标情况比较混乱,我总以为是Adjust函数中出现了下标向上越界的问题。正当我准备插入一条打印语句,以打印建堆结束后的数组时,我发现,在建堆循环中使用的循环变量unsigned int i(第21行),从建堆过程最后一步时的0,变成了 4294967295(即2^32-1)时,我才意识到,原来Adjust函数没有问题,HeapSort函数的逻辑也没有写错,错的只是循环变量。由于循环变量是无符号整数,所以当它为0时,再减1,就变成了UINT_MAX了。最后,我把这个循环变量改为int类型以后,一切就正常了。

那么,循环变量究竟就应该设定成int还是unsigned int呢?

我认为是这样的,使用unsigned int可以防止下溢,但是因为数组下标总是正的,上溢仍然无法通过编译器来防范。在本例中,循环变量在每次循环结束时减少的情况时,一旦循环变量从0开始减少一个值,那么几乎肯定就会出现上溢了,这个时候循环的逻辑是没有问题的,所以这类错误反而成了最大的麻烦。

另外,我认为使用unsigned int来规范当做数组下标使用的变量是个好习惯,但当用unsigned int与int类型进行比较操作时,则会在编译时产生一些有关类型转换的警告,本着视warning如error的态度,在使用unsigned int做循环变量与数组下标的时候,一定要小心行事。当然,如果压根就不用unsigned int而使用int,则是一个最简单有效的办法。

最终,希望通过使用编译规范来防止运行时错误,本身就是一个不合理的想法。想要避免运行时错误,还是需要靠认真编码、认真调试才是正道。当然,真正一劳永逸的办法,还是直接使用容器。这就是其他的话题了。

 

posted @ 2014-05-16 17:48  Superpig0501  阅读(2227)  评论(0编辑  收藏  举报