为啥我的二进制到十进制转换器程序中只有前 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**jj必须从右边开始计算。您的前两个数字恰好是正确的,因为它们几乎是对称的。 -1 的偏移量以“修复”来掩盖错误。 不要使用 pow 获得 2 的整数幂:使用移位。另请注意,第五个字符串的位数太多,无法转换为 32 位 int。 “二进制到十进制转换”也是不正确的,它将数字字符串转换为二进制。二进制转十进制由printf完成。 【参考方案1】:

您的代码存在许多问题。首先,正如 cmets 中所指出的,您正在从左到右处理二进制数字,而您应该从右到左处理。

其次,在另一个函数中声明一个函数(就像您为 strlen 所做的那样)不是标准 C(尽管某些编译器可能允许这样做)。如果你真的不能使用标准的strlen 函数(在&lt;string.h&gt; 中提供),那么将你的定义移到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 个输出正确?的主要内容,如果未能解决你的问题,请参考以下文章

将小数转换为只有两位数的二进制:1 和 2

为啥只有注释更改的两个程序二进制文件在 gcc 中不完全匹配?

Perl - 将数字转换为 2 个十进制

十进制转换为二进制为啥用短除法,即用短除法的原理是啥,为啥要用到短除法?

实验 9 根据材料编程

将短转换为二进制...前 8 位和后 8 位由于某种原因被交换