如何解决为什么高值输入会阻止数组使用 C 中的实际输入值?
我正在创建一个函数,该函数使用 scanf_s 获取一个值并将其转换为二进制值。该功能运行良好...直到我输入了一个非常高的值。
我也在 VS 2019 上用 C 语言在 x64 上做这个
以防万一,我正在使用
main(int argc,char* argv[])
用于主函数。
因为我不确定到底发生了什么,所以我猜这是整个代码。
BinaryGet()
{
// Declaring lots of stuff
int x,y,z,d,b,c;
int counter = 0;
int doubler = 1;
int getb;
int binarray[2000] = { 0 };
// I only have to change things to 1 now,am't I smart?
int binappend[2000] = { 0 };
// Get number
printf("Gimme a number\n");
scanf_s("%d",&getb);
// Because why not
printf("\n");
// Get the amount of binary places to be used (how many times getb divides by 2)
x = getb;
while (x > 1)
{
d = x;
counter += 1;
// Tried x /= 2,gave me infinity loop ;(
x = d / 2;
}
// Fill the array with binary values (i.e. 1,2,4,8,16,32,etc)
for (b = 1; b <= counter; b++)
{
binarray[b] = doubler * 2;
doubler *= 2;
}
// Compare the value of getb to binary values,subtract and repeat until getb = 0)
c = getb;
for (y = counter; c >= 1; y--)
{
// Printing c at each subtraction
printf("\n%d\n",c);
// If the value of c (a temp variable) compares right to the binary value,subtract that binary value
// and put a 1 in that spot in binappend,the 1 and 0 list
if (c >= binarray[y])
{
c -= binarray[y];
binappend[y] += 1;
}
// Prevents buffer under? runs
if (y <= 0)
{
break;
}
}
// Print the result
for (z = 0; z <= counter; z++)
{
printf("%d",binappend[z]);
}
}
问题是,当我输入值 999999999999999999(18 位)时,它只打印 0 一次并结束函数。数字的值无关紧要,18个将产生相同的结果。
然而,当我输入 17 位数字时,它给了我这个:
99999999999999999
// This is the input value after each subtraction
1569325055
495583231
495583231
227147775
92930047
25821183
25821183
9043967
655359
655359
655359
655359
131071
131071
131071
65535
32767
16383
8191
4095
2047
1023
511
255
127
63
31
15
7
3
1
// This is the binary
1111111111111111100100011011101
它给我的二进制值是 31 位数字。我觉得奇怪的是,在 32,一个方便的数字,它跳出来了,所以我把第 32 个二进制位的值减去 1 (2,147,483,647) 并且它起作用了。但是加 1 给我 0。
改变数组的类型(unsigned int 和 long)并没有改变这一点。也没有更改数组括号中的值。我试着搜索看看它是否是 scanf_s 的限制,但什么也没找到。
我确定(我认为)这不是数组,但可能我正在用函数做一些愚蠢的事情。有人可以帮忙吗?我给你一个远距离高五。
解决方法
问题确实与您注意到的数字的二次幂大小有关,但在此调用中:
scanf_s("%d",&getb);
%d
参数表示它正在读入一个有符号整数,在您的平台上可能是 32 位,并且由于它是有符号的,这意味着它可以在正方向上达到 2³¹-1。
scanf()
和相关函数使用的转换说明符可以接受更大尺寸的数据类型。例如,%ld
将接受 long int
,而 %lld
将接受 long long int
。检查您平台的数据类型大小,因为 long int
和 int
实际上可能是相同的大小(32 位),例如。在 Windows 上。
因此,如果您改用 %lld
,您应该能够读取更大的数字,最多可达 long long int
的范围,但请确保将目标 (getb
) 更改为匹配!此外,如果您对负数不感兴趣,请让类型系统帮助您并使用无符号类型:%llu
表示 unsigned long long
。
一些细节:
-
如果
scanf
或其朋友失败,则getb
中的值是不确定的,即。未初始化,并从中读取未定义行为 (UB)。 UB 是 C 中极其常见的错误来源,您希望避免它。如果getb
告诉您它有效,请确保您的代码仅从scanf
读取。 -
事实上,通常不可能用
scanf
避免 UB 除非你完全控制输入(例如,你之前用其他一些无错误的软件写出来的) )。虽然您可以检查scanf
和相关函数的返回值(它将返回它转换的字段数),但如果某个字段太大而无法适应您拥有的数据类型,则其行为未定义 -
关于
scanf
etc. here 有更多详细信息。 -
为了避免不知道
int
的大小,或者long int
在这个或那个平台上是否不同的问题,还有定义整数的 headerstdint.h
特定宽度的类型,例如。int64_t
。这些也具有与scanf()
一起使用的宏,例如SCNd64
。这些可以从 C99 开始使用,但请注意,Windows 在其编译器中对 C99 的支持是不完整的,可能不包括这一点。 -
不要对自己太苛刻,你并不笨,C 是一门难以掌握的语言,并且不遵循自最初设计以来发展起来的现代习语。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。