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

问题描述 投票:0回答:2

我知道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];
}

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

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

c string binary point
2个回答
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
}

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';
    }
    

    with:

    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.cdebug.h(以及间接的[C0 ]和kludge.c)在kludge.h子目录中。提供的宏和函数使我可以在代码中包含调试信息。

[要编译代码(源代码src/libsoq;测试程序binsum83.c),我在一个目录中构建了该程序,该目录包含一个包含标题的子目录binsum83和另一个包含库的子目录inclib,其中包含库函数:

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()s1之间的范围内的字节取反。对于最主要的函数,最简单的方法是首先在字符串中使用LSB(最低有效位)生成结果。此代码用于反转字符串。请注意,只有当s2s1都指向同一数组中的有效地址时,该声明才是安全的-否则,您将调用未定义的行为。该代码符合该要求。

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

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

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

binary_digit()函数具有选项处理,可让您设置调试级别(main())并获取帮助(我使用-d debug寻求帮助; GNU建议使用-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分成两行并在第一行的末尾加反斜杠的输出,则与上面的测试脚本输出相同。

bc
© www.soinside.com 2019 - 2024. All rights reserved.