简体   繁体   English

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

[英]Why does a high-value input prevent an array from using the actual input value in C?

I'm making a function that takes a value using scanf_s and converts that into a binary value.我正在制作一个 function ,它使用 scanf_s 获取一个值并将其转换为二进制值。 The function works perfectly... until I put in a really high value. function 完美运行......直到我投入了非常高的价值。

I'm also doing this on VS 2019 in x64 in C我也在 C 的 x64 中的 VS 2019 上执行此操作

And in case it matters, I'm using万一这很重要,我正在使用

main(int argc, char* argv[]) 

for the main function.为主要的 function。

Since I'm not sure what on earth is happening, here's the whole code I guess.由于我不确定到底发生了什么,我猜这是整个代码。

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]);
}
}

The problem is that when I put in the value 999999999999999999 (18 digits) it just prints 0 once and ends the function.问题是当我输入值 999999999999999999(18 位)时,它只打印一次 0 并结束 function。 The value of the digits doesn't matter though, 18 ones will have the same result.数字的值无关紧要,18 个数字将具有相同的结果。

However, when I put in 17 digits, it gives me this:但是,当我输入 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

The binary value it gives me is 31 digits.它给我的二进制值是 31 位。 I thought that it was weird that at 32, a convenient number, it gimps out, so I put in the value of the 32nd binary place minus 1 (2,147,483,647) and it worked.我觉得奇怪的是,在 32,一个方便的数字,它会出现,所以我把第 32 个二进制位的值减去 1 (2,147,483,647) 并且它起作用了。 But adding 1 to that gives me 0.但是加1给我0。

Changing the type of array (unsigned int and long) didn't change this.更改数组的类型(无符号整数和长整数)并没有改变这一点。 Neither did changing the value in the brackets of the arrays.也没有更改 arrays 括号中的值。 I tried searching to see if it's a limit of scanf_s, but found nothing.我试图搜索它是否是scanf_s的限制,但一无所获。

I know for sure (I think) it's not the arrays, but probably something dumb I'm doing with the function.我确定(我认为)它不是 arrays,但可能是我用 function 做的一些愚蠢的事情。 Can anyone help please?有人可以帮忙吗? I'll give you a long-distance high five.我给你一个长距离高五。

The problem is indeed related to the power-of-two size of the number you've noticed, but it's in this call:问题确实与您注意到的数字的二次方大小有关,但它在这个调用中:

scanf_s("%d", &getb);

The %d argument means it is reading into a signed integer, which on your platform is probably 32 bits, and since it's signed it means it can go up to 2³¹-1 in the positive direction. %d参数意味着它正在读入一个带符号的 integer,它在您的平台上可能是 32 位,并且由于它已签名,这意味着它可以 go 在正方向上达到 2³¹-1。

The conversion specifiers used by scanf() and related functions can accept larger sizes of data types though. scanf()和相关函数使用的转换说明符可以接受更大大小的数据类型。 For example %ld will accept a long int , and %lld will accept a long long int .例如%ld将接受long int ,而%lld将接受long long int Check the data type sizes for your platform, because a long int and an int might actually be the same size (32 bits) eg.检查您平台的数据类型大小,因为long intint实际上可能是相同的大小(32 位),例如。 on Windows.在 Windows 上。

So if you use %lld instead, you should be able to read larger numbers, up to the range of a long long int , but make sure you change the target ( getb ) to match, Also if you're not interested in negative numbers: let the type system help you out and use an unsigned type: %llu for an unsigned long long .因此,如果您改用%lld ,您应该能够读取更大的数字,直到long long int的范围,但请确保您更改目标( getb )以匹配,另外如果您对负数不感兴趣:让类型系统帮助您并使用无符号类型: %llu用于unsigned long long

Some details:一些细节:

  1. If scanf or its friends fail, the value in getb is indeterminate ie.如果scanf或其朋友失败,则getb中的值是不确定的,即。 uninitialised, and reading from it is undefined behaviour (UB).未初始化,并且从中读取的是未定义的行为(UB)。 UB is an extremely common source of bugs in C, and you want to avoid it. UB 是 C 中极其常见的错误来源,您希望避免它。 Make sure your code only reads from getb if scanf tells you it worked.如果scanf告诉您它有效,请确保您的代码仅从getb读取。

  2. In fact, in general it is not possible to avoid UB with scanf unless you're in complete control of the input (eg. you wrote it out previously with some other, bug free, software).事实上,一般情况下,除非您完全控制输入(例如,您之前使用其他一些无错误的软件将其写出来),否则通常无法使用scanf避免 UB。 While you can check the return value of scanf and related functions (it will return the number of fields it converts), its behaviour is undefined if, say, a field is too large to fit into the data type you have for it.虽然您可以检查scanf和相关函数的返回值(它将返回它转换的字段数),但如果字段太大而无法适应您拥有的数据类型,则它的行为是不确定的。

  3. There's a lot more detail on scanf etc. here .这里有更多关于scanf的详细信息。

  4. To avoid problems with not knowing what size an int is, or if a long int is different on this platform or that, there is also the header stdint.h which defines integer types of a specific width eg.为了避免不知道int大小的问题,或者long int在这个或那个平台上是否不同,还有header stdint.h定义了特定宽度的 integer 类型,例如。 int64_t . int64_t These also have macros for use with scanf() like SCNd64 .这些有与scanf()一起使用的宏,如SCNd64 These are available from C99 onwards, but note that Windows' support of C99 in its compilers is incomplete and may not include this.这些从 C99 开始可用,但请注意,Windows 在其编译器中对 C99 的支持是不完整的,可能不包括这一点。

  5. Don't be so hard on yourself, you're not dumb, C is a hard language to master and doesn't follow modern idioms that have developed since it was first designed.不要对自己这么苛刻,你并不愚蠢,C 是一门很难掌握的语言,它不遵循自最初设计以来就发展起来的现代习语。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM