为什么高值输入会阻止数组使用C中的实际输入值?



我正在制作一个函数,该函数使用scanf_s获取值并将其转换为二进制值。这个功能运行得很好……直到我输入了一个非常高的值

我也在C

中的x64中的VS 2019中这样做为了方便,我用

main(int argc, char* argv[]) 

为main函数。

由于我不确定到底发生了什么,下面是我猜的全部代码。

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 numbern");
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%dn", 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]);
}
}

问题是当我输入值999999999999999999999999(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的限制,但没有找到。

我知道肯定(我认为)它不是数组,但可能是一些愚蠢的我正在做的函数。有人能帮忙吗?我要给你一个远距离的击掌。

问题确实与您注意到的数字的2次幂大小有关,但它在这个调用中:

scanf_s("%d", &getb);

%d参数表示它正在读取一个有符号整数,在您的平台上可能是32位,并且由于它是有符号的,因此它可以在正方向上读取到2³¹-1。

scanf()和相关函数使用的转换说明符可以接受更大的数据类型。例如,%ld将接受long int,%lld将接受long long int。检查您的平台的数据类型大小,因为long intint实际上可能是相同的大小(32位)。在Windows .

因此,如果您使用%lld代替,您应该能够读取更大的数字,直到long long int的范围,但请确保更改目标(getb)以匹配!此外,如果你对负数不感兴趣,让类型系统帮助你,使用无符号类型:unsigned long long%llu

一些细节:

  1. 如果scanf或其友端失败,则getb的值不确定。未初始化,从它读取是未定义行为(UB)。UB是C语言中非常常见的bug来源,您希望避免它。确保你的代码只有在scanf告诉你它工作时才从getb读取。

  2. 事实上,在一般情况下,它是不可能避免UB与scanf,除非你在输入的完全控制(例如。您之前使用其他一些无bug的软件编写了它)。虽然您可以检查scanf和相关函数的返回值(它将返回它转换的字段数),但如果字段太大而无法容纳您为其设置的数据类型,则其行为是未定义的。

  3. 这里有更多关于scanf等的细节。

  4. 为了避免不知道int的大小,或者long int在这个平台或那个平台上是否不同的问题,还有头文件stdint.h,它定义了特定宽度的整数类型。int64_t。这些也具有用于scanf()(如SCNd64)的宏。这些从C99开始可用,但请注意,Windows在其编译器中对C99的支持是不完整的,可能不包括这个。

  5. 别对自己太苛刻了,你又不笨,C是一门很难掌握的语言,而且它不遵循自设计以来发展起来的现代习惯。

最新更新