我在接受采访时被问到这个问题:“将数字的字符串表示转换为整数”。但是如果数字超过可以存储在32位整数中的最大值,则必须抛出错误。 我的问题是我们如何检查一个数字是否溢出32位无符号整数?
答案 0 :(得分:9)
在循环中,您已获得由第一个数字确定的整数的当前值。你将要这样做:
curval = curval * 10 + digit; // digit converted from '0'..'9' to 0..9 already
您可以使用以下方法测试溢出:
if (curval > UINT32_MAX / 10 || (curval == UINT32_MAX / 10 && digit > UINT32_MAX % 10))
...overflow would occur...
else
curval = curval * 10 + digit; // overflow did not occur
除法和模数运算是编译时操作,而不是运行时操作。
这种方法比使用“大于32位的无符号整数进行计算”的一个优点是,它可以扩展为使用更大的整数 - 使用64位整数和uintmax_t
整数 - 通过更改从UINT32_MAX到UINT64_MAX或UINTMAX_MAX的常量。这就是必要的(当然,除了改变变量类型之外)。
同样的基本测试也适用于签名类型,但是增加了复杂性。使用16位整数更容易进行演示(输入和思考的数字更少),所以我将切换到16位二进制补码short
:
USHRT_MAX
= 65535 SHRT_MAX
= 32767 SHRT_MIN
= -32768 问题是short
类型可以存储-32768但是你可以累积的最大正值是32767.对于除SHRT_MIN之外的所有值,上面的测试都可以正常工作。有办法绕过这种困境。一种是在计算过程中将curval
存储为负值,并在返回前将其否定,如果它应为正数。然后你的测试可能是:
if (curval < SHRT_MIN / 10 || (curval == SHRT_MIN / 10 && digit > -(SHRT_MIN / 10))
...overflow would occur...
else
curval = curval * 10 - digit; // Note subtraction!
在否定负值之前,您仍需检查curval
是否为SHRT_MIN
。 (理论上,你应该检查-SHRT_MAX != SHRT_MIN
以允许除了二进制补码二进制之外的其他系统;我为限制引用的值满足该条件。)
当然,同样的想法和技巧适用于INT_MAX
,INT32_MAX
,INT64_MAX
和INTMAX_MAX
。
答案 1 :(得分:6)
(我查看了这个问题的possible duplicate,我不确定阅读的有用性,因为在面试环境中,你可以期待描述一般的想法/方法)
回答面试问题的一部分是提出澄清问题(面试官期待您的重要检查表项目之一)。
因此,您的调查线至少应包含以下内容:
unsigned long long
/ uint64_t
(64位整数)?stdin
/从文件中读取/硬编码为字符串文字?假设您的面试官告诉您它是十进制表示+您可以使用unsigned long long
:
unsigned int
范围介于0 to 4,294,967,295
之间。如果数字的十进制字符串表示形式超过10个字符(超过10个数字),则它已经溢出;提出错误。unsigned long long
并除以UINT32_MAX+1=4294967296
。如果结果大于0
,则溢出;提出错误。答案 2 :(得分:0)
使用uint64_t
进行转换。你将一次添加一个数字;对于每个数字,您将乘以10并添加下一个字符的值。处理完每个字符后,检查结果是否大于UINT32_MAX
;如果是,则退出并出现错误(或者溢出时应该做的任何事情)。完成后,将号码作为uint32_t
返回。 uint64_t
中定义了uint32_t
,UINT32_MAX
和stdint.h
。