C 中的转换是如何工作的?

How casting works in C?

我在 leetcode 上解决了一个 problem,这是我的代码。

/*
max int 2147483647 (10^10)
max uint 4294967295 (10^10)
ULONG_MAX 18446744073709551615 (10^20)
LONG_MAX 9223372036854775807 (10^20)
USHRT_MAX 65535, SHRT_MAX 32767
*/

#include <stdio.h>
#include <math.h>

int main(void) {
    int t; 
    scanf("%d", &t);
    while (t--) {
        int length;
        scanf("%d", &length);
        char string[length];
        scanf("%s", string);
        long int answer = 0;
        int ones = 0;
        for (int i = 0; i < length; i++) {
            ones = ones + (string[i] == '1') * (i + 1);
            if (ones & 1) {
                answer = (answer + (long int)pow(2, length - (i + 1))) % 998244353;
            }
        }
        printf("%ld\n", answer);
    }
    
    return 0;
}

它适用于较小的值(可能是 int 可以容纳的值)。但是在计算大值时却给出了意想不到的结果

然后我认为这可能是由于溢出造成的,所以我将变量 int answer 更改为 long int answer 我认为这会解决问题,但它没有,而且甚至破坏了代码较小的值

然后我注意到我正在使用 pow 函数,它肯定会超过高长度值的限制,因为 pow 在 return 中给出双倍值,我正在转换它之前有 (int)pow(2, length - (i+1))int,我改为 (long int)pow(2, length - (i+1))

我正在传递这些值来测试代码。

4
16
1111010010111101
2
10
6
101101
4
1111

预期结果是

49359
3
48
12

但是我得到了

49359
65535
49152
49152

我在使用 int answer(int)pow(...) 时得到了预期的结果,但是如果我将 answer 或 pow 转换为 long,我会得到意想不到的结果。我不确定这是由于转换还是其他原因造成的,但据我所知,只有当我将这些变量转换为 long 时才会发生这种情况。

代码中存在多个问题:

    如果输入的 t 值为负数,
  • while (t--) 将导致意外行为。使用 while (t-- > 0)

  • char string[length]; 没有足够的 space 用于 length 个字符和空终止符。使用 char string[length + 1];

  • scanf("%s", string); 不提供任何防止缓冲区溢出的保护。没有简单的方法可以告诉 scanf()%s 读取最多可变数量的字节。由于长度可以与 100000 一样大,您可能应该从堆中分配数组并使用 getchar().

    读取位
  • 循环中的代码似乎没有实现问题的解决方案:

    Given a binary string S, she defines the beauty of the string as the bitwise XOR of decimal representations of all substrings of S.

    这些说明具有误导性,因为结果与任何东西的十进制表示法都无关。但是您的代码不会转换所有子字符串,只应显示结果模 998244353。对模块应用 xor 会产生不同的结果。

  • 此外,pow 无需转换二进制表示:您可以将 res 乘以 2,然后在循环中添加下一个数字的值。

要计算生成的位串,请考虑偏移量 i 处的位,从字符串的开头开始,偏移量为 0:

  • 对于仅删除前缀的子字符串,它将与自身进行 i 次异或运算。

  • 然后索引 j 小于 i 的每个位将对每个子字符串进行异或 j 次,最后 i-j 位被删除.

  • 如果 i 是奇数,
  • XORing i 次将产生 0,因此与使用 [= 最后一位相反的掩码具有相同的效果28=].

    您可以为此使用 2 个嵌套循环:

          for (int i = 0; i < length; i++) {
              int bit = (string[i] - '0') & ~i;
              for (j = 0; j < i; j++) {
                  bit ^= (string[j] - '0') & ~j;
              }
              answer = (answer * 2 + bit) % 998244353;
          }
    

这是修改后的版本:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int t, i, j, c;
    int string_size = 0;
    unsigned char *string = NULL;   /* array for the bits */

    /* read the number of test cases */
    if (scanf("%d", &t) != 1)
        return 1;
    while (t-- > 0) {
        int length;
        /* read the length */
        if (scanf("%d", &length) != 1)
            return 1;
        /* discard the rest of the input line */
        while ((c = getchar()) != EOF && c != '\n')
            continue;
        /* reallocate the string if required */
        if (length > string_size) {
            string_size = length;
            string = realloc(string, string_size);
            if (string == NULL)
                return 1;
        }
        /* read the bits */
        i = 0;
        while (i < length && ((c = getchar()) == '0' || c == '1')) {
            string[i++] = (unsigned char)(c - '0');
        }
        /* discard the rest of the input line */
        while (c != EOF && c != '\n') {
            c = getchar();
        }
        /* compute the answer one bit at a time */
        long int answer = 0;
        for (i = 0; i < length; i++) {
            /* compute the next bit of the result string */
            int bit = string[i] & ~i;
            for (j = 0; j < i; j++) {
                bit ^= string[j] & ~j;
            }
            /* compute the answer one bit at a time, reducing modulo 998244353 */
            answer = (answer * 2 + bit) % 998244353;
        }
        printf("%ld\n", answer);
    }
    free(string);
    return 0;
}