为啥我的二进制到十进制转换器程序中只有前 2 个输出正确?
Posted
技术标签:
【中文标题】为啥我的二进制到十进制转换器程序中只有前 2 个输出正确?【英文标题】:Why are only the first 2 outputs correct in my binary to decimal converter programm?为什么我的二进制到十进制转换器程序中只有前 2 个输出正确? 【发布时间】:2021-08-29 20:00:01 【问题描述】:我必须编写一个转换器,从numbers[]
获取字符串并将它们输出为小数。
我循环遍历大小和索引,然后将当前索引与其位置的幂相加,然后将其全部加起来。比如:101 = 1^2 + 0^1 + 1^0
所以我目前对此感到困惑:
#include <stdio.h>
#include <math.h> // Kompilieren mit -lm : gcc -Wall -std=c11 dateiname.c -lm
int main()
char* numbers[] =
"01001001",
"00101010",
"010100111001",
"011111110100101010010111",
"0001010110011010101111101111010101110110",
"01011100110000001101";
// Add here..
int strlen(char *str)
int len=0;
for(;str[len]!='\0';len++)
return len;
int sum = 0;
int length = sizeof(numbers) / sizeof(numbers[0]);
for( int i = 0; i < length; i++ )
int size = strlen(numbers[i]);
for (int j = 0; j < size; j++)
if(numbers[i][j] == '1')
sum += 1 * pow(2,j-1);
else
sum += 0 * pow(2,j-1);
printf("%s to the base of 2 \nequals %d to the base of 10 \n\n",numbers[i], sum);
sum = 0;
return 0;
前两个循环的输出是正确的,即 01001001 = 73 和 00101010 = 42。但是,一旦长度变大,我的输出就完全错误了;例如010100111001 = 1253 而不是 1337 和 011111110100101010010111 = 7645567 而不是 8342167。
【问题讨论】:
j
从左边开始数,但如果使用2**j
,j
必须从右边开始计算。您的前两个数字恰好是正确的,因为它们几乎是对称的。 -1 的偏移量以“修复”来掩盖错误。
不要使用 pow
获得 2 的整数幂:使用移位。另请注意,第五个字符串的位数太多,无法转换为 32 位 int
。 “二进制到十进制转换”也是不正确的,它将数字字符串转换为二进制。二进制转十进制由printf
完成。
【参考方案1】:
您的代码存在许多问题。首先,正如 cmets 中所指出的,您正在从左到右处理二进制数字,而您应该从右到左处理。
其次,在另一个函数中声明一个函数(就像您为 strlen
所做的那样)不是标准 C(尽管某些编译器可能允许这样做)。如果你真的不能使用标准的strlen
函数(在<string.h>
中提供),那么将你的定义移到main
的外部(和之前)。
第三,您不应该使用pow
函数(它接受并返回double
值)进行整数运算。只需使用一个正在运行的 int
变量,并在每次运行内部 for
循环时将其乘以 2。
第四,您的"0001010110011010101111101111010101110110"
值会溢出大多数机器上的int
类型(假设是32 位),因此请在必要时尝试使用long long int
(很可能是64 位)。
最后,无论x
是什么,添加0 * x
是没有意义的,因此您可以取消else
块。
这是一个工作版本(使用标准 strlen
):
#include <stdio.h>
#include <string.h> // For "strlen" - we don't need math.h if we don't use "pow".
int main(void) // For strict compliance, you should add the "void" argument list
char* numbers[] =
"01001001",
"00101010",
"010100111001",
"011111110100101010010111",
"0001010110011010101111101111010101110110",
"01011100110000001101" ;
long long int sum = 0; // So we can use more than 32 bits!
size_t length = sizeof(numbers) / sizeof(numbers[0]);
for (size_t i = 0; i < length; i++)
int size = (int)strlen(numbers[i]); // strlen gives a "size_t" type
long long int p = 1;
for (int j = size-1; j >= 0; j--) // Start at the END of the string and work backwards!
if (numbers[i][j] == '1')
sum += p;
// No point in adding zero times anything!
p *= 2; // Times by two each time through the loop
printf("%s to the base of 2 \nequals %lld to the base of 10 \n\n", numbers[i], sum);
sum = 0;
return 0;
【讨论】:
真的,非常感谢!我对 c 真的很陌生,这是我的第四个任务。它真的有助于你如何打破“错误”。 @0___________:但您已经发布了一个答案,您使用strchr
的结果而不测试NULL
。我怀疑这会使它“对任何数据都正确”。
@MOehm 对!更正。我不争论是否有人有建设性的意见。在另一句话之前 - 由调用者传递有效指针(与标准库函数相同)
@AdrianMole cast 不能防止溢出。
@AdrianMole 计算编译时间还是运行时间都没有关系。分配大于 INT_MAX 的值是实现定义的【参考方案2】:
sizeof(); // it will give you the size of datatype (in bytes), not the length of a string.
你必须改用字符串函数。
length = strlen(numbers[0]);
【讨论】:
但是sizeof
这里只用来获取测试数组(6)的大小。处理字符串时,程序使用strlen
。
目的是什么:int length = sizeof(numbers) / sizeof(numbers[0]);
@OwaisYosuf 获取数组长度是一个常用的习惯用法。
int length = sizeof(numbers); // 数组的长度。
最后的评论不是真的。 sizeof
会告诉你一个变量在内存中占用了多少字节,这和数组的长度是不一样的。【参考方案3】:
你的函数很糟糕,很复杂并且使用pow
。您不需要知道字符串的长度。
这可以更容易地完成:
unsigned long long bstrtoint(const char *str)
unsigned long long result = 0;
while(*str)
result *= 2;
result += *str++ == '1';
return result;
或任何基数(小于位数)
//bad digits considered as zeroes
static const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUWXYZ";
unsigned long long strtoint(const char *str, unsigned base)
unsigned long long result = 0;
char *ppos;
while(*str)
result *= base;
result += (ppos = strchr(digits, toupper(*str++))) ? (ppos - digits < base) ? ppos - digits : 0 : 0;
return result;
例子:
printf("%llu\n", bstrtoint("1111000011110000"));
printf("%llu\n", strtoint("0001010110011010101111101111010101110110", 2));
printf("%llu\n", strtoint("1dr45Xvy4", 36)); // base 36 number
https://godbolt.org/z/bsG5rfTsb
如果你想正确使用你的程序布局:
int main(void) // For strict compliance, you should add the "void" argument list
char* numbers[] =
"01001001",
"00101010",
"010100111001",
"011111110100101010010111",
"0001010110011010101111101111010101110110",
"01011100110000001101" ;
unsigned long long sum = 0;
size_t length = sizeof(numbers) / sizeof(numbers[0]);
for (size_t i = 0; i < length; i++)
size_t size = strlen(numbers[i]); // strlen gives a "size_t" type
sum = 0;
for (size_t j = 0; j < size; j++)
sum *= 2;
if (numbers[i][j] == '1')
sum += 1;
printf("%s to the base of 2 \nequals %llu to the base of 10 \n\n", numbers[i], sum);
return 0;
但您不必将字符串集成两次 - 根本不需要 strlen
int main(void) // For strict compliance, you should add the "void" argument list
char* numbers[] =
"01001001",
"00101010",
"010100111001",
"011111110100101010010111",
"0001010110011010101111101111010101110110",
"01011100110000001101" ;
unsigned long long sum = 0;
size_t length = sizeof(numbers) / sizeof(numbers[0]);
for (size_t i = 0; i < length; i++)
sum = 0;
for (size_t j = 0; numbers[i][j] != 0; j++)
sum *= 2;
if (numbers[i][j] == '1')
sum += 1;
printf("%s to the base of 2 \nequals %llu to the base of 10 \n\n", numbers[i], sum);
return 0;
【讨论】:
以上是关于为啥我的二进制到十进制转换器程序中只有前 2 个输出正确?的主要内容,如果未能解决你的问题,请参考以下文章
为啥只有注释更改的两个程序二进制文件在 gcc 中不完全匹配?