提问人:tycoon 提问时间:3/14/2022 最后编辑:chqrlietycoon 更新时间:3/14/2022 访问量:130
C语言中的投射是如何工作的?
How casting works in C?
问:
我正在解决leetcode上的一个问题,这是我的代码。
/*
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
然后我注意到我正在使用肯定会超过高长度值限制的函数,因为返回双倍值,我将其转换为之前的 with,我将其更改为pow
pow
int
(int)pow(2, length - (i+1))
(long int)pow(2, length - (i+1))
我传递这些值来测试代码。
4
16
1111010010111101
2
10
6
101101
4
1111
预期结果是
49359
3
48
12
但我得到了
49359
65535
49152
49152
当我使用时,我得到了预期的结果,但是如果我将答案或pow投射到long,我会得到意想不到的结果。我不确定这是由于投射还是其他原因,但据我所知,只有当我将这些变量投射到长整型时才会发生。int answer
(int)pow(...)
答:
代码中存在多个问题:
while (t--)
如果 enter 的值为负数,将导致意外行为。用t
while (t-- > 0)
char string[length];
没有足够的空间容纳字符和 null 终止符。用length
char string[length + 1];
scanf("%s", string);
不提供任何防止缓冲区溢出的保护。没有简单的方法可以告诉 读取 的字节数是可变的。由于长度可以大到 ,因此您可能应该从堆中分配数组并使用 读取 .scanf()
%s
100000
getchar()
循环中的代码似乎没有实现该问题的解决方案:
给定一个二进制字符串,她将字符串的美定义为 的所有子字符串的十进制表示的按位异或。
S
S
这些说明具有误导性,因为结果与任何内容的十进制表示无关。但是您的代码不会转换所有子字符串,而只应显示结果为模。对模块应用异或将产生不同的结果。
998244353
此外,无需转换二进制表示:您可以乘以 2 并在循环中添加下一个数字的值。
pow
res
要计算生成的位串,请考虑偏移位处的位,从字符串的开头开始,偏移量为:i
0
它将与仅删除前缀的子字符串的自身时间进行异或运算。
i
然后,索引小于的每个位将是每个子字符串的 XOR 操作时间,并删除最后一位。
j
i
j
i-j
XOR 时间将产生 if 为奇数,因此与使用 的最后一位相反的 进行掩码具有相同的效果。
i
0
i
i
为此,您可以使用 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;
}
评论
在 %
之后,按顺序显示以下内容: — 可选的赋值抑制字符 *
。 — 大于零的可选十进制整数,用于指定最大字段宽度(以字符为单位)。 — 一个可选的长度修饰符,用于指定接收对象的大小。 — 转换说明符字符,用于指定要的转换类型应用的。
scanf()
*
scanf
snprintf
{ char format[20]; snprintf(format, sizeof format, "%%%ds", length); if (scanf(format, string) != 1) return 1; }
scanf()
stderr
errno
strerror(errno)
FILE *fp = fopen(filename, "r"); if (f == NULL) { fprintf(stderr, "cannot open %s: %s\n", filename, strerror(errno)); return 1; }
评论
pow()
1ull << 40
(string[i]=='1'?1:0)
(string[i]=='1')
==
1
0
printf("%d\n", answer);
==>printf("%ld\n", answer);
char string[length];
==>char string[length+1];
(10^10)
INT_MAX