• 循环变量到底应该使用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,则是一个最简单有效的办法。

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

  • 相关阅读:
    损失函数及其梯度
    激活函数及其梯度
    梯度下降简介
    误差计算
    输出方式
    全连接层
    测试(张量)- 实战
    数据加载
    高阶操作
    java网络基础知识的简述
  • 原文地址:https://www.cnblogs.com/superpig0501/p/3967580.html
Copyright © 2020-2023  润新知