添加两个二进制数字字符串-C

时间:2019-11-28 20:04:44

标签: c string binary point

我知道Internet上,尤其是Stack上有很多有关此问题的信息-但我仍然受阻。

给出两个二进制数字字符串-我们必须将它们的二进制和作为字符串返回。

实际上,我认为我与此人的问题相同:Padding and adding binary strings in C

但是我做了一些补充和替换,如下所示:

    // This function validates the two strings are really representing two binary number, and we keep the size of each
int isNum(const char* num, int* sizeOfNum) {
  *sizeOfNum = 0;
  while (*num != '\0') {
    if (*num != '0' || *num != '1') {
      return 0;
    }
    *sizeOfNum += 1;
  }
  return 1;
}

char* sumOfBinString(const char* num1, const char* num2) {

    int* sizeOfNum1 = (int*)(malloc(sizeof(int));
    int* sizeOfNum2 = (int*)(malloc(sizeof(int));

    if (isNum(num1, sizeOfNum1) && isNum(num2, sizeOfNum2)) {

        if (*sizeOfNum1 > *sizeOfNum2) {
          int size = (*sizeOfNum1);
        }
        else {
          int size = (*sizeOfNum2);
        }
    }

        //This 'size' is actually the size of the longer binary number string, and plus one for the null-terminator
    char *num1Copy = (char *)malloc((size+1) * sizeof(char));
    char *num2Copy = (char *)malloc((size+1) * sizeof(char));

    int i;
    for(i = size; i >= 0; i--)
    {
      num1Copy[i] = '0';
      num2Copy[i] = '0';
    }

    for (i = *sizeOfNum1; i >= 0; i--)
      if (i == 0 && num1Copy[i]=='1') //Two's complement
        num1Copy[i] = '1';
      else
        num1Copy[size - i] = num1[*sizeOfNum1-i];

    for (i = *sizeOfNum2; i >= 0; i--)
      if (i == 0 && num2Copy[i]=='1') //Two's complement
        num2Copy[i] == '1';
      else
        num2Copy[size - i] = num2[*sizeOfNum2-i];
}

但是我不知道如何从这里继续,因为在某些情况下,进位可能会溢出,因此我需要将该数字“加”为MSB。

有人可以帮助我从这里继续吗?

2 个答案:

答案 0 :(得分:0)

开始于:

int* sizeOfNum1 = (int*)(malloc(sizeof(int));
int* sizeOfNum2 = (int*)(malloc(sizeof(int));

if (isNum(num1, sizeOfNum1) && isNum(num2, sizeOfNum2)) {

    if (*sizeOfNum1 > *sizeOfNum2) {
      int size = (*sizeOfNum1);
    }
    else {
      int size = (*sizeOfNum2);
    }
}

您不需要为bsc大小使用指针,这很容易忘记之后free的内存或遇到其他问题。您可以在int上完成此操作:

    int sizeOfNum1=0,sizeOfNum2=0;

    if (isNum(num1, &sizeOfNum1) && isNum(num2, &sizeOfNum2)) { //if u add & isNum can modify sizeofNum1 by itself (You give address of variable to function)

        if (sizeOfNum1 > sizeOfNum2) {
          int size = sizeOfNum1;
        }
        else {
          int size = sizeOfNum2;
        }
    }

对于像在学校一样添加的背后的数学:

    111--- //carry line
      1100
   + 10100
    ------
    100000

在循环中,每个sizeOfNum都有2个发射器,当它达到0时,您只会在输出中添加一个长度更长的信号(ofc记住,您需要随时检查进位,例如在1100发射器将结束进位时仍然是1,因此您需要当心)此处的一些指南:

int i,j;    
i=(size==sizeOfNum1)?size:sizeOfNum2;
j=((i==sizeOfNum1)&&(i==size))?sizeOfNum2:sizeOfNum1;
for(;i>=0;i--,j--){
   //here you are adding
}

答案 1 :(得分:0)

诊断

问题中显示的代码有很多问题。这些包括:

  • 这不是一个完整的程序,因此我们无法提供完整的分析。
  • 在以下部分中,编译器通常会报告一个错误:

    if (i == 0 && num2Copy[i]=='1') //Two's complement
        num2Copy[i] == '1';
    else
        num2Copy[size - i] = num2[*sizeOfNum2-i];
    

    ==正文中的if应该是=。编译器通常会抱怨一条语句无效。

  • 您分配了指针sizeOfNum1sizeOfNum2,但没有释放它们。您应该创建简单的变量,并将这些变量的地址传递给函数。

  • 您为更长的字符串的两个副本加上一个空字节分配了空间,但是您不允许为可能需要的进位留出空间。将两个二进制数相加可能会产生比较长的输入多一位的结果-十进制加法或其他任何基数的加法运算也是如此。

  • 您不检查分配是否成功;您会愉快地假设他们这样做。这很危险。

  • 目前尚不清楚为什么需要两份。

  • 您没有提供返回任何数据的机制。您的sumOfBinString()函数被声明为返回char *,但不包含return语句。那是个错误。据推测,您应该退还其中一份副本,但是您应该如何处理另一份副本?释放它是最低限度的-但您可能仍然不需要它。

  • 您可以替换代码:

    int i;
    for(i = size; i >= 0; i--)
    {
      num1Copy[i] = '0';
      num2Copy[i] = '0';
    }
    

    具有:

    memset(num1Copy, '0', size);
    memset(num2Copy, '0', size);
    num1Copy[size] = '\0';
    num2Copy[size] = '\0';
    

    这为您提供了两个以空值结尾的字符串-malloc()返回的内存不能保证为零,这就是为什么也有calloc()的原因。

  • 我可能会在isNum()中使用局部变量作为计数器,并在返回之前将其一次分配给指针参数。但是,您写的东西是可以辩护的。

  • 您有代码片段:

    if (isNum(num1, sizeOfNum1) && isNum(num2, sizeOfNum2)) {
    
        if (*sizeOfNum1 > *sizeOfNum2) {
          int size = (*sizeOfNum1);
        }
        else {
          int size = (*sizeOfNum2);
        }
    }
    
    char *num1Copy = (char *)malloc((size+1) * sizeof(char));
    

    两个不同的变量size不在其代码块中使用,调用malloc()时也无法访问。该代码将无法编译。如果您提供未编译的代码,则应这样说,并在问题中包含错误消息的文本。

  • “二进制补码”注释是神秘的。在不知道值有多大的情况下,不能有二进制补码二进制值。您可以使用32位或64位二进制补码,但是在不知道需要多少位的情况下,您无法确定前一位是符号位还是仅是常规幅度位。类似的评论也适用于一个人的补语值。您可以使用-字符表示负数来管理符号和大小。然后,您必须对处理进行大量修改。您的代码只能处理无符号的二进制数字。

    我想,如果您强制要求正数的前导零和负数的前导1,则可以使用二进制补码,但是前导零通常被视为无关紧要。如果您确实使用了二进制补码,那么您还有很多工作要做。

  • 我相当确定还有其他问题-但进一步的诊断可能并不明智。

合成

这是我为完成comments中的任务而编写的代码:

  

实现函数const char* binarySum(const char* num1, const char* num2),该函数获得2个二进制数,以字符串表示,并返回它们的总和,以字符串(二进制数)表示。注意:如果输入无效,该函数应返回字符串“ 0”。

printf("%s\n", binarySum("101", "1"))  // ---> "110"

我编写的代码使用了一些库代码,这些代码在GitHub上的SOQ(堆栈溢出问题)存储库中以文件stderr.cstderr.hdebug.c的形式提供和src/libsoq子目录中的debug.h(以及间接kludge.ckludge.h)。提供的宏和函数使我可以在代码中包含调试信息。

要编译代码(源代码binsum83.c;测试程序binsum83),我在一个带有子目录inc的目录中构建了该程序,该子目录包含标头和另一个子目录lib包含一个库libsoq.a,其中包含库函数:

gcc -O3 -g -I./inc -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
    -DTEST -DDEBUG binsum83.c -o binsum83 -L./lib  -lsoq 

-DTEST标志用于构建程序-如果省略该程序,它将创建一个仅包含公开函数binarySum()和不包含static的隐藏(main())函数的文件功能。 -DDEBUG标志启用跟踪机制-如果省略该跟踪机制,则设置设置调试级别的-d level选项仍然会被接受,但是它没有任何用处。

#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "debug.h"
#include "stderr.h"

/* External interface - result is not constant */
extern char *binarySum(const char *s1, const char *s2);

static bool is_binary(const char *str)
{
    assert(*str != '\0');
    for (const char *digit = str; *digit != '\0'; digit++)
    {
        if (*digit != '0' && *digit != '1')
            return false;
    }
    return true;
}

static inline size_t max(size_t s1, size_t s2) { return (s1 > s2) ? s1 : s2; }

static void reverse_bytes(char *s1, char *s2)
{
    assert(s2 >= s1);
    while (s1 < s2)
    {
        char t = *s1;
        *s1++ = *s2;
        *s2-- = t;
    }
}

static inline int binary_digit(const char *str, size_t len, size_t idx)
{
    int result = 0;
    if (idx < len)
        result = str[len - 1 - idx] - '0';
    DB_TRACE(3, "%s(): %16s (%2zu) [%2zu] = %d\n", __func__, str, len, idx, result);
    return result;
}

static const char *skip_leading_zeros(const char *s1)
{
    while (s1[0] == '0' && s1[1] != '\0')
        s1++;
    return s1;
}

char *binarySum(const char *s1, const char *s2)
{
    DB_TRACE(1, "-->> %s(): evaluate %s + %s\n", __func__, s1, s2);
    /* Return 0 if either of the inputs is not a valid binary number */
    if (!is_binary(s1) || !is_binary(s2))
        s1 = s2 = "0";
    s1 = skip_leading_zeros(s1);
    s2 = skip_leading_zeros(s2);
    size_t len1 = strlen(s1);
    size_t len2 = strlen(s2);
    size_t maxlen = max(len1, len2);
    DB_TRACE(2, "%s(): len(%s) = %zu; len(%s) = %zu; max = %zu\n", __func__, s1, len1, s2, len2, maxlen);
    char *result = malloc(maxlen + 2);
    if (result == 0)
    {
        DB_TRACKING();
        err_sysrem("%s(): failed to allocate %zu bytes of memory\n", __func__, maxlen);
        return 0;
    }
    char *rp = result;
    int carry = 0;
    for (size_t i = 0; i < maxlen; i++)
    {
        int d1 = binary_digit(s1, len1, i);
        int d2 = binary_digit(s2, len2, i);
        int r = d1 + d2 + carry;
        DB_TRACE(2, "%s(): d1 = %d, d2 = %d, c = %d, r = %d\n", __func__, d1, d2, carry, r);
        assert(r >= 0 && r <= 3);
        *rp++ = (r & 1) + '0';
        carry = r >> 1;
    }
    if (carry)
        *rp++ = '1';
    *rp = '\0';
    DB_TRACE(2, "%s(): reverse = %s\n", __func__, result);
    reverse_bytes(result, rp - 1);
    DB_TRACE(2, "%s(): forward = %s\n", __func__, result);
    DB_TRACE(1, "<<-- %s(): %s + %s = %s\n", __func__, s1, s2, result);
    return result;
}

#ifdef TEST

#include <unistd.h>

static const char optstr[] = "hd:";
static const char usestr[] = "[-h][-d debug] binary1 binary2";
static const char hlpstr[] =
    "  -d debug  Set debug level (0..3)\n"
    "  -h        Print this help message and exit\n"
    ;

int main(int argc, char **argv)
{
    err_setarg0(argv[0]);
    int opt;
    while ((opt = getopt(argc, argv, optstr)) != -1)
    {
        switch (opt)
        {
        case 'd':
            db_setdebug(atoi(optarg));
            break;
        case 'h':
            err_help(usestr, hlpstr);
            /* NOTREACHED */
        default:
            err_usage(usestr);
            /* NOTREACHED */
        }
    }
    if (optind != argc - 2)
        err_usage(usestr);

    const char *num1 = argv[optind + 0];
    const char *num2 = argv[optind + 1];
    char *result = binarySum(num1, num2);
    if (result == 0)
        exit(EXIT_FAILURE);
    printf("%s + %s = %s\n", num1, num2, result);
    free(result);
    return EXIT_SUCCESS;
}

#endif /* TEST */

binarySum()的函数声明应放在需要该函数时可以包含的标头中。除main()以外的所有其他功能都是static,因为它们不是关键功能。可能会公开认为适当的其他功能-is_binary()函数可能会有用地公开。

is_binary()函数报告字符串是否代表二进制数。如果禁用了断言(在编译器命令行上为-DNEBUG),则它将空字符串视为有效-其余代码可以正常工作,将其视为零(但诊断打印有些麻烦)。

max()函数通常被编写为宏-使用static inline函数是等效的,但是强加了一些类型安全性,这是不值得尝试使用宏的。

reverse_bytes()函数反转s1s2之间(包括两端)的字节。对于最主要的函数,最简单的方法是首先在字符串中使用LSB(最低有效位)生成结果。此代码用于反转字符串。请注意,只有在s1s2都指向同一数组中的有效地址的情况下,声明才是安全的-否则,您将调用未定义的行为。该代码符合该要求。

binary_digit()函数是一个关键函数。给它一个字符串,字符串的长度(添加assert(strlen(str) == len)几乎是合理的)和一个位置。字符串中的字节已编号,因此最后一个字节为0,第一个为len - 1;如果请求的位置在字符串长度之外,则将其视为(前导)零字节。 (请注意,字节是位的字符表示;这可能会造成混淆。)

skip_leading_zeros()函数正是这样做的,它返回一个指向字符串中第一个1数字的指针,但是如果数字为零,它将返回一个指向最后一个0的指针。前1个中的第一个。这种改进使调试输出更加理智。

核心功能是binarySum()。我已将返回类型从const char *修改为char *,因为如果不这样做,则必须在将值传递给free()时强制转换值(必须编写{ {1}}或类似名称(看起来很笨重)。它会在跳过前导零之后找到字符串的长度,然后为较长的字符串加上一个额外的数字和一个空终止符分配足够的空间(因此,free((void *)result)的调用中为+ 2)。如果内存分配失败,它将通过malloc()强行报告警告并返回空指针。您可以删除错误消息,并仅返回空指针。然后,它使用err_sysrem()从右到左扫描两个字符串以建立正确的数字。这样可以以相反的顺序存储结果,但可以轻松处理最终进位。然后,它将数字反转以正常顺序得到结果,并将其返回给调用代码。

binary_digit()函数具有选项处理功能,可让您设置调试级别(main())并获得帮助(我使用-d debug获得帮助; GNU建议使用{{1} },但我不使用-h)。然后,它检查是否只剩下两个参数,并将其添加。此版本静默接受无效输入,并将结果转换为--help;先前的版本在调用getopt_long()之前扫描了参数并确认它们是二进制的。

请注意,至关重要的是捕获0返回的值,以便可以释放它。因此,分配中的示例代码有缺陷;应该更像是:

binarySum()

删除调试代码或错误报告代码并不难。尚存的断言也可以删除。

我使用了这样的测试脚本(binarySum()):

const char *result = binarySum("101", "1");
printf("%s\n", result);
free(result);

长号是从我的评论到问题。输出为:

test.binsum83.sh

使用binsum83 -d 3 001 000001 binsum83 -d 4 000 00000 binsum83 -d 4 000 000001 binsum83 -d 4 001 000001 binsum83 -d 5 00011010110101 000001 binsum83 -d 5 001 000001 binsum83 0 0 binsum83 0 1 binsum83 000 00000 binsum83 000 000001 binsum83 00011010110101 000001 binsum83 001 000001 binsum83 011011101 000001 binsum83 1 1 binsum83 101 1 binsum83 101 111 binsum83 101010101101101010101101010101110101010101010100010101111101010101010011100110101101010100100 101010111111010101011101110101011010101110001000011110101110101011011010101001010101011101010101010110111111111111110101010111111 binsum83 101111 10001 binsum83 11001 1111 binsum83 11010 000001 binsum83 111 1 确认加长。请注意,您需要先设置$ sh -x test.binsum83.sh + binsum83 -d 3 001 000001 -->> binarySum(): evaluate 001 + 000001 binarySum(): len(1) = 1; len(1) = 1; max = 1 binary_digit(): 1 ( 1) [ 0] = 1 binary_digit(): 1 ( 1) [ 0] = 1 binarySum(): d1 = 1, d2 = 1, c = 0, r = 2 binarySum(): reverse = 01 binarySum(): forward = 10 <<-- binarySum(): 1 + 1 = 10 001 + 000001 = 10 + binsum83 -d 4 000 00000 -->> binarySum(): evaluate 000 + 00000 binarySum(): len(0) = 1; len(0) = 1; max = 1 binary_digit(): 0 ( 1) [ 0] = 0 binary_digit(): 0 ( 1) [ 0] = 0 binarySum(): d1 = 0, d2 = 0, c = 0, r = 0 binarySum(): reverse = 0 binarySum(): forward = 0 <<-- binarySum(): 0 + 0 = 0 000 + 00000 = 0 + binsum83 -d 4 000 000001 -->> binarySum(): evaluate 000 + 000001 binarySum(): len(0) = 1; len(1) = 1; max = 1 binary_digit(): 0 ( 1) [ 0] = 0 binary_digit(): 1 ( 1) [ 0] = 1 binarySum(): d1 = 0, d2 = 1, c = 0, r = 1 binarySum(): reverse = 1 binarySum(): forward = 1 <<-- binarySum(): 0 + 1 = 1 000 + 000001 = 1 + binsum83 -d 4 001 000001 -->> binarySum(): evaluate 001 + 000001 binarySum(): len(1) = 1; len(1) = 1; max = 1 binary_digit(): 1 ( 1) [ 0] = 1 binary_digit(): 1 ( 1) [ 0] = 1 binarySum(): d1 = 1, d2 = 1, c = 0, r = 2 binarySum(): reverse = 01 binarySum(): forward = 10 <<-- binarySum(): 1 + 1 = 10 001 + 000001 = 10 + binsum83 -d 5 00011010110101 000001 -->> binarySum(): evaluate 00011010110101 + 000001 binarySum(): len(11010110101) = 11; len(1) = 1; max = 11 binary_digit(): 11010110101 (11) [ 0] = 1 binary_digit(): 1 ( 1) [ 0] = 1 binarySum(): d1 = 1, d2 = 1, c = 0, r = 2 binary_digit(): 11010110101 (11) [ 1] = 0 binary_digit(): 1 ( 1) [ 1] = 0 binarySum(): d1 = 0, d2 = 0, c = 1, r = 1 binary_digit(): 11010110101 (11) [ 2] = 1 binary_digit(): 1 ( 1) [ 2] = 0 binarySum(): d1 = 1, d2 = 0, c = 0, r = 1 binary_digit(): 11010110101 (11) [ 3] = 0 binary_digit(): 1 ( 1) [ 3] = 0 binarySum(): d1 = 0, d2 = 0, c = 0, r = 0 binary_digit(): 11010110101 (11) [ 4] = 1 binary_digit(): 1 ( 1) [ 4] = 0 binarySum(): d1 = 1, d2 = 0, c = 0, r = 1 binary_digit(): 11010110101 (11) [ 5] = 1 binary_digit(): 1 ( 1) [ 5] = 0 binarySum(): d1 = 1, d2 = 0, c = 0, r = 1 binary_digit(): 11010110101 (11) [ 6] = 0 binary_digit(): 1 ( 1) [ 6] = 0 binarySum(): d1 = 0, d2 = 0, c = 0, r = 0 binary_digit(): 11010110101 (11) [ 7] = 1 binary_digit(): 1 ( 1) [ 7] = 0 binarySum(): d1 = 1, d2 = 0, c = 0, r = 1 binary_digit(): 11010110101 (11) [ 8] = 0 binary_digit(): 1 ( 1) [ 8] = 0 binarySum(): d1 = 0, d2 = 0, c = 0, r = 0 binary_digit(): 11010110101 (11) [ 9] = 1 binary_digit(): 1 ( 1) [ 9] = 0 binarySum(): d1 = 1, d2 = 0, c = 0, r = 1 binary_digit(): 11010110101 (11) [10] = 1 binary_digit(): 1 ( 1) [10] = 0 binarySum(): d1 = 1, d2 = 0, c = 0, r = 1 binarySum(): reverse = 01101101011 binarySum(): forward = 11010110110 <<-- binarySum(): 11010110101 + 1 = 11010110110 00011010110101 + 000001 = 11010110110 + binsum83 -d 5 001 000001 -->> binarySum(): evaluate 001 + 000001 binarySum(): len(1) = 1; len(1) = 1; max = 1 binary_digit(): 1 ( 1) [ 0] = 1 binary_digit(): 1 ( 1) [ 0] = 1 binarySum(): d1 = 1, d2 = 1, c = 0, r = 2 binarySum(): reverse = 01 binarySum(): forward = 10 <<-- binarySum(): 1 + 1 = 10 001 + 000001 = 10 + binsum83 0 0 0 + 0 = 0 + binsum83 0 1 0 + 1 = 1 + binsum83 000 00000 000 + 00000 = 0 + binsum83 000 000001 000 + 000001 = 1 + binsum83 00011010110101 000001 00011010110101 + 000001 = 11010110110 + binsum83 001 000001 001 + 000001 = 10 + binsum83 011011101 000001 011011101 + 000001 = 11011110 + binsum83 1 1 1 + 1 = 10 + binsum83 101 1 101 + 1 = 110 + binsum83 101 111 101 + 111 = 1100 + binsum83 101010101101101010101101010101110101010101010100010101111101010101010011100110101101010100100 101010111111010101011101110101011010101110001000011110101110101011011010101001010101011101010101010110111111111111110101010111111 101010101101101010101101010101110101010101010100010101111101010101010011100110101101010100100 + 101010111111010101011101110101011010101110001000011110101110101011011010101001010101011101010101010110111111111111110101010111111 = 101010111111010101011101110101011011011000110110001001011100000001001111111110101001110011010010101100010011100110100010101100011 + binsum83 101111 10001 101111 + 10001 = 1000000 + binsum83 11001 1111 11001 + 1111 = 101000 + binsum83 11010 000001 11010 + 000001 = 11011 + binsum83 111 1 111 + 1 = 1000 $ ,然后再设置bc,或者需要指定obase。如果粘贴ibase分成两行的输出,并在第一行的末尾加反斜杠,则与上面的测试脚本输出相同。

ibase = 2; obase = 10
相关问题