|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
题目是模拟atoi函数,进行提取字符串里第一段数字。在进阶题目里,小甲鱼要求对于溢出int的数值报错。网上很多帖子给出两种判断方式:
(1)你的如何短时间计算出2^ 31?(2)因为x是int型,即使x溢出,由于存储的限制,那么x的值也必然在这个区间范围内(这里不考虑类型升级)。
针对(1)如何快速计算2^ 31次方:简单粗暴的用16进制表示出来(),或者利用位运算。将最大值最小值记作int_max 和int_min。
针对(2)我们可以先比较x/10与int_max/10的大小, 再比较最后一位,即可避免上面的尴尬之处。
两种方式在说明什么,我没有看懂。答案里,小甲鱼利用了第一种方式,也就是牺牲时间来计算int的最大值和最小值,然后计算。说真的,我也没看懂。
现在说一下我的思路:
出现溢出,必然是在计算过程中。当一个数值(我们这个题目里只考虑正数,没有把符号计入要提取的范围)接近溢出的时候,已经很大了。溢出刚刚发生的时候,得到的数字会很小。那么我利用临时变量,对提取前后的数值进行了比较,如果数值突然变小,就认为是溢出了。
我感觉这个方法虽然只针对了本题,但是会比小甲鱼的思路要简洁一点。
[b][b]请各位大佬指正我这思路的不妥之处(除了只能针对本题外)[/b][/b]。
小甲鱼的程序:
#include <stdio.h>
#include <math.h>
int main()
{
int ch;
long long num = 0;
long long temp; // 临时变量,用于测试是否超出范围
int is_overflow = 0;
const int max_int = pow(2, sizeof(int) * 8) / 2 - 1;
const int min_int = pow(2, sizeof(int) * 8) / 2 * (-1);
printf("请输入待转换的字符串:");
do
{
ch = getchar();
if (ch >= '0' && ch <= '9')
{
temp = 10 * num + (ch - '0');
if (temp > max_int || temp < min_int)
{
is_overflow = 1;
break;
}
else
{
num = temp;
}
}
else
{
if (num)
{
break; // 如果已有数字,则退出循环
}
}
}
while (ch != '\n');
if (is_overflow)
{
printf("数值超出范围,结果未定义!\n");
}
else
{
if (!num)
{
printf("并未找到任何数值!\n");
}
else
{
printf("结果是:%d\n", num);
}
}
return 0;
}
我写的程序:
#include<stdio.h>
int main()
{
int ch,num=0,num0;//ch为输入的字符,num存储结果用的整形数值
printf("请输入待转换的字符串:");
do
{
ch=getchar();
if(ch>='0'&&ch<='9')
{
num0=num;//临时存储,用于比较是否溢出
num=10*num+(ch-'0');//按照10进制记录已读入的值
if(num<num0)break; //溢出了,跳出循环,不再读取字符。
}
else if(num) break; //不是数字,则跳出循环。
}
while ((ch!='\n'));
if(num<num0) //溢出时打印结果
printf("数值超出范围,结果未定义!\n");
else if(num!=0) //正常时打印结果
printf("结果是:%d\n",num);
else
printf("并未找到任何数值!\n"); //没有数字时打印结果
return 0;
}
确实奇怪,为什么会没有人帮你呢?
我帮你看了看,你的思路是对的
但是这么写不是很好,我的调试器检查出了这个溢出
还是强制转换一下unsigned类型吧
- $ cat main.c
- #include <stdio.h>
- int main() {
- int ch, num = 0, num0; // ch为输入的字符,num存储结果用的整形数值
- printf("请输入待转换的字符串:");
- do {
- ch = getchar();
- if(ch >= '0' && ch <= '9') {
- num0 = num; //临时存储,用于比较是否溢出
- #if 1
- num = 10 * num + (ch - '0'); //按照10进制记录已读入的值
- #else
- num = (unsigned)10 * num + (ch - '0'); //按照10进制记录已读入的值
- #endif
- if(num < num0)
- break; //溢出了,跳出循环,不再读取字符。
- } else if(num) break; //不是数字,则跳出循环。
- } while((ch != '\n'));
- if(num < num0) //溢出时打印结果
- printf("数值超出范围,结果未定义!\n");
- else if(num != 0) //正常时打印结果
- printf("结果是:%d\n", num);
- else
- printf("并未找到任何数值!\n"); //没有数字时打印结果
- return 0;
- }
- $ gcc-debug -o main main.c
- $ ./main
- 请输入待转换的字符串:2147483647
- 结果是:2147483647
- $ ./main
- 请输入待转换的字符串:2147483648
- main.c:11:17: runtime error: signed integer overflow: 2147483640 + 8 cannot be represented in type 'int'
- 数值超出范围,结果未定义!
- $
- $
- $
- $ vim main.c
- $ cat main.c
- #include <stdio.h>
- int main() {
- int ch, num = 0, num0; // ch为输入的字符,num存储结果用的整形数值
- printf("请输入待转换的字符串:");
- do {
- ch = getchar();
- if(ch >= '0' && ch <= '9') {
- num0 = num; //临时存储,用于比较是否溢出
- #if 0
- num = 10 * num + (ch - '0'); //按照10进制记录已读入的值
- #else
- num = (unsigned)10 * num + (ch - '0'); //按照10进制记录已读入的值
- #endif
- if(num < num0)
- break; //溢出了,跳出循环,不再读取字符。
- } else if(num) break; //不是数字,则跳出循环。
- } while((ch != '\n'));
- if(num < num0) //溢出时打印结果
- printf("数值超出范围,结果未定义!\n");
- else if(num != 0) //正常时打印结果
- printf("结果是:%d\n", num);
- else
- printf("并未找到任何数值!\n"); //没有数字时打印结果
- return 0;
- }
- $ gcc-debug -o main main.c
- $ ./main
- 请输入待转换的字符串:2147483648
- 数值超出范围,结果未定义!
- $
复制代码
如果不考虑负数的话,可以直接作为无符数来计算
超过了0x80000000就是溢出(包括这个数)
- $ cat main.c
- #include <stdio.h>
- int main() {
- //int ch, num = 0, num0; // ch为输入的字符,num存储结果用的整形数值
- int ch;
- unsigned int num = 0;
- printf("请输入待转换的字符串:");
- do {
- ch = getchar();
- if(ch >= '0' && ch <= '9') {
- num = num * 10 + (ch - '0');
- if(num >= 0x80000000) break; //溢出了,跳出循环,不再读取字符。
- } else if(num) break; //不是数字,则跳出循环。
- } while((ch != '\n'));
- if(num >= 0x80000000) //溢出时打印结果
- printf("数值超出范围,结果未定义!\n");
- else if(num != 0) //正常时打印结果
- printf("结果是:%d\n", num);
- else
- printf("并未找到任何数值!\n"); //没有数字时打印结果
- return 0;
- }
- $ gcc-debug -o main main.c
- $ ./main
- 请输入待转换的字符串:2147483648
- 数值超出范围,结果未定义!
- $ ./main
- 请输入待转换的字符串:2147483647
- 结果是:2147483647
- $
复制代码
你的这个程序还有一个bug
0是不是数字,0是数字
但是
- $ cat main.c
- #include <stdio.h>
- int main() {
- int ch, num = 0, num0; // ch为输入的字符,num存储结果用的整形数值
- printf("请输入待转换的字符串:");
- do {
- ch = getchar();
- if(ch >= '0' && ch <= '9') {
- num0 = num; //临时存储,用于比较是否溢出
- #if 1
- num = 10 * num + (ch - '0'); //按照10进制记录已读入的值
- #else
- num = (unsigned)10 * num + (ch - '0'); //按照10进制记录已读入的值
- #endif
- if(num < num0)
- break; //溢出了,跳出循环,不再读取字符。
- } else if(num) break; //不是数字,则跳出循环。
- } while((ch != '\n'));
- if(num < num0) //溢出时打印结果
- printf("数值超出范围,结果未定义!\n");
- else if(num != 0) //正常时打印结果
- printf("结果是:%d\n", num);
- else
- printf("并未找到任何数值!\n"); //没有数字时打印结果
- return 0;
- }
- $ gcc-debug -o main main.c
- $ ./main
- 请输入待转换的字符串:0
- 并未找到任何数值!
- $ ./main
- 请输入待转换的字符串:abcd1234
- 结果是:1234
- $ ./main
- 请输入待转换的字符串:abcd0
- 并未找到任何数值!
- $ ./main
- 请输入待转换的字符串:abcd0000
- 并未找到任何数值!
- $
复制代码
这个bug自己改吧
|
|