C - 将整数转换为二进制数组

3

我对C语言非常陌生。 我需要一个小程序将int类型的数字转换为二进制,并且最好将二进制存储在数组中,以便我可以进一步将它们拆分用于解码。 以下是我的代码:

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

int main()
{
    int arr[20];
    int dec = 40;
    int i = 0, ArrLen;

    if(dec > 0)
    {
        while(dec > 0)
        {
            arr[i] = dec % 2;
            i++;
            dec = dec / 2;
        }
    }
    else
    {
        printf("Invalid Number");
    }
}

从上面的代码中,我可以在arr中存储二进制值。 但是,与其获取二进制等效值:101000,数组现在像这样{0, 0, 0, 1, 0, 1},这是正确答案的相反顺序。 那么问题是,如何获得正确顺序的数组或者可能翻转它? 我有一件确定的事情,那就是最大数组长度不会超过8个元素。
这种转换将被重复使用。 因此,我计划将其放入一个函数中,这样我就可以调用该函数,传递一个整数,然后将数组作为返回值。所以另一个问题是,能否获得数组作为返回值?

首先,考虑手动完成这个任务的步骤,然后将其转化为代码。顺便提一下,int类型的值已经是二进制的了。有很多不同的方法可以实现这个任务,特别是如果你利用计算机存储数据的知识。但我猜这是一个课程作业,因为大多数学校都会让你早早地完成这个任务。 - ydobonebi
嗨,Quinn,这不是任何作业。我已经毕业很久了。我现在主要从事C#,PHP和JAVA方面的工作,没有涉及到C语言。从int中打印出二进制很容易,但是存储它们,我还无法解决。 - Fei Hap Lee
在 C 语言中,你不能直接传递一个数组。你需要在函数内部使用 malloc 函数来分配内存,并返回指向该地址的指针。 - M. Shaw
http://ideone.com/Woyw8H - Kaustav Ray
1
@M.Shaw struct R { unsigned char ar[8]; }; struct R func(int value) { struct R r; .... return r; } - 如果您在一个结构体中嵌入了一个固定长度的数组,您是可以通过值返回它的。如果需要的话,编译器会生成适当的代码来完成此操作。但这是否对于当前的任务是必要或者合适的,这是一个不同的问题。 - WhozCraig
8个回答

8
你可以使用指向int类型的指针来参数化数组。参数化数字位数也可能很有用。
void int_to_bin_digit(unsigned int in, int count, int* out)
{
    /* assert: count <= sizeof(int)*CHAR_BIT */
    unsigned int mask = 1U << (count-1);
    int i;
    for (i = 0; i < count; i++) {
        out[i] = (in & mask) ? 1 : 0;
        in <<= 1;
    }
}

int main(int argc, char* argv[])
{
    int digit[8];
    int_to_bin_digit(40, 8, digit);
    return 0;
}

小问题:/* 断言:count <= sizeof(unsigned)*CHAR_BIT && count > 0 */ - chux - Reinstate Monica
@chux 我对 sizeof(?) 这个问题犹豫不决,因为它在评估有符号类型并且只是将其转换为无符号类型以进行逻辑移位。零的 count 不应被标记为错误,但小于零可能是一个错误。实际上,count 应该是无符号的。 - Johnny Cage
断言 count>0 有助于处理 count == 01U << (count-1); 的问题。请注意,在 1U << (count-1) 中,count 没有转换为无符号数。 - chux - Reinstate Monica

2
与Johnny Cage的答案相同,但增加了一个函数来获取数字的长度。
#include <math.h>

int bit_len(unsigned int n){
   return floor(log(n)/log(2))+1;
}
void int_to_bin_digit(unsigned int in, int len_digitis,int* out_digit){

  unsigned int mask = 1U << (len_digitis-1);
  int i;
  for (i = 0; i < len_digitis; i++) {
    out_digit[i] = (in & mask) ? 1 : 0;
    in <<= 1;
  }
}

int main(int argc, char* argv[]){
   int number = 30;
   int len = bit_len(number);
   int digits[len];
   int_to_bin_digit(number,len, digits);
   for( int i =0;i<len;i++){
       printf("%d",digits[i]);
   }
  return 0;
 }

2

或递归 V2.0:

#include <stdio.h>

char *binaryToAbits(unsigned int answer, char *result) {
  if(answer==0) return result;
  else {
    result=binaryToAbits(answer>>1,result);
    *result='0'+(answer & 0x01);
    return result+1;
  }
}

int main(void) {
    unsigned int numToConvert=0x1234ABCD;
    char ascResult[64];
    *binaryToAbits(numToConvert,ascResult)='\0';
    printf("%s",ascResult);
    return 0;
}

注意,感谢 @chux,这里有一个更好的递归函数来处理将0转换的情况——它输出"0"而不是"":

char *binaryToAbits(unsigned int answer, char *result) {
  if(answer>1) {
    result=binaryToAbits(answer>>1,result);
  }
  *result='0'+(answer & 0x01);
  return result+1;
};

1
  1. numToConvert=0 --> 应该返回 "" 而不是 "0"
  2. 对于 0x1234ABCD,64 位足够了,但我预计应该是 65 或 33。
- chux - Reinstate Monica
@chux - 当然可以,但这需要另一个函数来检查0。很容易,我只是没费心去做。缓冲区大小:我原本想是32,然后加上nul变成33,再向上取整到64 :) - Martin James
1
需要另一个函数来检查是否为0。嗯,也许可以进行小的改写: if (answer > 1) {result=binaryToAbits(answer>>1,result); } *result='0'+(answer & 1); return result+1; 稍微简单一些,但可以很好地处理0。 - chux - Reinstate Monica
@chux 好主意!如果您允许,我会编辑并添加归属。 - Martin James
其实,算了吧,我还是要添加它。如果你反对,我会将其删除,或者你可以:) - Martin James

0

这应该可以运行。

#include <stdio.h>

void intToBin(int dec, int bin[], int numBits){
    for(int i = 0; i < numBits; i++){
        bin[i] = 1 & (dec >> i);
    }
}

void printArr(int arr[], int arrSize){
    for(int i = 0; i < arrSize; i++) {
        printf("%d ", arr[i]);
    }
}

int main(int argc, char* argv[]){
    int bin[32];
    intToBin(-15, bin, 32); 
    printArr(bin, 32);
}

0

可以试试这个:

uint8_t * intToBin(int x) {
    uint8_t *bin = (int *) malloc(8);
    uint8_t i = 0;
    int mask = 0x80;
    for (i = 0; i < 8; i++) {
        bin[i] = (x & mask) >> (7-i);
        mask >>= 1;
    }
    return bin;
}

包含 <stdint.h> 以声明 uint8_t。 如果不想出现内存泄漏,请记得释放 malloc 分配的内存。


内存不足 int *bin = (int * ) malloc(8); --> int *bin = malloc(8 * sizeof *bin); - chux - Reinstate Monica
@chux OP需要将8位存储在数组中。我应该将“bin”的类型更改为“unsigned char”或“uint8_t”。OP需要8位,而我已经分配了64位。没有任何理由需要256位的内存来存储8位数据。 - M. Shaw
“OP 需要 8 位,而我已经分配了 64 位”是不正确的。代码分配了 8,如 malloc(8),这显然对于 8 个 int 来说是不够的内存 - 因此有了这个注释。无论如何,现在的 malloc(8) 对于 8 个 uint8_t 来说已经有足够的内存了。但现在它有一个新问题:返回一个被强制转换为 int *uint8_t *。使用 4 字节的 int,调用代码可以引用 int* 数组的前两个,但 OP 显然期望有 8 个。 - chux - Reinstate Monica

0

使用位运算逻辑:

for(int i = 0 ; i < 8 ; i++)
{
    bytearray[i] = inputint & pow(2,7-i);
}

顺便说一下,利用C语言的联合和结构体可以更快地完成这个任务。 - ydobonebi
sizeof(int) * 8 是32。操作员说“最大的数组长度不会超过8个元素”。 - M. Shaw
你还需要适当地移位 & 的结果,否则对于15,结果将是 [0x1, 0x2, 0x4, 0x8] 而不是 [1, 1, 1, 1] - M. Shaw
取模方法也很慢。最快的运算符始终是 >><<&,它们在大多数指令集中都编译为单个指令。您可以查看 GCC 对模数的编译 https://dev59.com/Mm855IYBdhLWcg3wZzff。 - M. Shaw
@M.Shaw 我不明白为什么在我的例子中使用移位操作会得到正确的结果。我可以使用移位操作来重写它,而不是使用 pow() 函数,但我认为另一个答案已经这样做了。另外,我想模运算相对于移位操作来说可能会更加耗时。 - ydobonebi
显示剩余5条评论

0

这可能会有所帮助:

void binary(unsigned n)
{
    unsigned i;
    for (i = 1 << 31; i > 0; i = i / 2)
        (n & i)?`/*STORE 1*/` : `/*STORE 0*/` ;
}

注意:最好使用1u << 31,因为在32位int中,1 << 31是未定义的行为。 - chux - Reinstate Monica

-1

递归实现:

(由于您无法预先知道给定数字的二进制格式中数字(0/1)的数量)

int arr[200]; //for storing the binary representation of num
int i=0; // to keep the count of the no of digits in the binary representation

void calBinary(int n) // function to recalculate
{
   if(n>1)
      calBinary(n/2);
   arr[i++]=n%2;
}

1
你的数组仍然会被反转。 - M. Shaw
可能是因为递归通常与无副作用相关,但这并不是无副作用的。 - DanZimm
是的,那是真的!它总是不够高效,但它并没有错!无论如何,我学到了! :) - Kaustav Ray

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接