malloc() 和 realloc() 函数的奇怪行为导致分段错误

Weird behaviour of function with malloc() and realloc() resulting in Segmentation Fault

我有一个名为num_to_binary的函数,用于将以数组形式存储的十进制数转换。该函数num_to_binary的原型如下:

void num_to_binary(int *number_b, int size_of_number);

这里:

number_b 是指向存储我的号码的数组的指针。例如,如果我想将数字 12345 转换为二进制,那么我会将 12345 存储在 number_b 中,如下所示:

number_b[0] = 1
number_b[1] = 2
number_b[2] = 3
number_b[3] = 4
number_b[4] = 5

还有,size_of_number是数字的位数(或者是数组的元素个数number_b)。所以对于数字 12345,size_of_number 的值为 5.

下面是函数的完整声明num_to_binary:

void num_to_binary(int *number_b, int size_of_number)
{
    int *tmp_pointer = malloc(1 * sizeof(int));
    int curr_size = 1;
    int i = 0;
    while(!is_zero(number_b,size_of_number))
    {
        if(i != 0)
        {
            curr_size += 1;
            tmp_pointer = realloc(tmp_pointer, curr_size * sizeof(int));
        }
        if(number_b[size_of_number - 1] % 2 == 1)
        {
            tmp_pointer[i] = 1;
            divide_by_2(number_b,size_of_number);
            i = i + 1;
        }
        else
        {
            tmp_pointer[i] = 0;
            divide_by_2(number_b,size_of_number);
            i = i + 1;
        }
    }
    int *fin_ans;
    fin_ans = malloc(curr_size * sizeof(int));
    for(int j = 0 ; j < curr_size; j++)
    {
        fin_ans[curr_size-1-j] = tmp_pointer[j];
    }
}

在上面的函数中:

tmp_pointer:它最初使用malloc()分配了一些内存,用于存储number_b

中存储的数字的二进制表示形式的反转

curr_size:存放tmp_pointer的当前大小。它最初设置为 1。 i:用于跟踪while循环。它也用于重新分配目的,我稍后会解释。

is_zero(number_b, size_of_number):是一个函数,returns 1如果number_b中存储的数字是0,否则returns1.

divide_by_2(number_b, size_of_number):它将存储在number_b中的数字除以2。它不会改变数组的大小number_b

fin_ans:整数指针。由于存储在数组 tmp_pointer 中的二进制表示将与数字的实际二进制表示相反,因此 fin_ans 将通过反转 tmp_pointer 的内容来存储数字的正确二进制表示.

以下是此功能的工作原理:

  1. 首先,tmp_pointer分配的内存等于 1 int 的大小。所以,现在tmp_pointer可以存储一个整数。
  2. 我们现在进入 while 循环。循环只会终止 当 number_b 中存储的数字等于 0.
  3. 现在,我们检查 i 是否等于 0。如果不等于 零,那么这意味着循环至少 运行 一次,并且 为了存储下一个二进制数字,我们调整内存大小 分配给 tmp_pointer 以便它可以存储下一位。
  4. 如果数字的最后一位是奇数,则表示 相应的二进制位为 1,否则为 0。 ifelse 条件执行此任务。他们也递增 i每次执行其中一个,同样除以2。
  5. 现在,我们脱离了循环。是时候反转二进制数了 存储在 tmp_pointer 中以获得最终答案。
  6. 为此,我们创建一个名为 fin_ans 的新指针,并分配 它是将用于存储正确二进制文件的内存 数字的表示形式。
  7. 最后一个for循环用于反转二进制表示 并将正确的二进制表示存储在 fin_ans.

问题:

代码运行s对于123这样的小数,但是对于1234567891这样的大数,就报segmentation fault错误。这可以通过尝试打印存储在 fin_ans.

中的数字来检查

我尝试使用 GDB Debugger,发现 Segmentation Fault 的原因在于 while 循环。我确信函数 divide_by_2is_zero 不是分段错误的原因,因为我已经对它们进行了彻底的测试。

我还使用了 DrMemory,这表明我正在尝试访问(读取或写入)尚未分配的内存位置。不幸的是,我无法找出错误所在。

我怀疑 realloc() 是分段错误的原因,但我不确定。

对于这么长的问题深表歉意,但是,我将非常感谢为我提供此代码的任何帮助。

在此先感谢您对我的帮助!

代码中存在多个问题:

  • 你没有检查内存分配失败
  • 您在离开函数前忘记释放 tmp_pointer
  • 你分配了一个新的数组fin_ans来保留数组tmp_pointer并进行反向操作但是你没有return这个数组给调用者,你也没有办法到 return 它的大小。您应该将原型更改为 return 此信息。
  • 如果数字为零,转换后的数字可能应该有1位初始化为0,但是你使用malloc它没有初始化它分配的数组所以tmp_pointer[0]未初始化。
  • 您没有提供 is_zero()divide_by_two() 的代码。这些函数中的错误可能会导致分段错误,特别是如果循环未达到零并且在此无限循环期间内存最终耗尽。

这是修改后的版本:

int *num_to_binary(int *number_b, int size_of_number, int *binary_size) {
    int i, j, curr_size;
    int *p, *newp;

    curr_size = 1;
    p = malloc(1 * sizeof(int));
    if (p == NULL)
        return NULL;
    p[0] = 0;

    for (i = 0; !is_zero(number_b, size_of_number); i++) {
        if (i != 0) {
            curr_size += 1;
            newp = realloc(p, curr_size * sizeof(int));
            if (newp == NULL) {
                free(p);
                return NULL;
            }
            p = newp;
        }
        p[i] = number_b[size_of_number - 1] % 2;
        divide_by_2(number_b, size_of_number);
    }
    for (i = 0, j = curr_size; i < j; i++)
        int digit = p[--j];
        p[j] = p[i];
        p[i] = digit;
    }
    *binary_size = curr_size;
    return p;
}

不需要多次内存重新分配。结果内存缓冲区大小可以很容易地评估为十进制输入值的二进制对数。数字二进制表示的计算也可以简化:

//Transform binary array to actual number
int arr2int(int* pIntArray, unsigned int nSizeIn) {
    if (!pIntArray || !nSizeIn)
        return 0;

    int nResult = 0;
    for (unsigned int i = 0; i < nSizeIn; ++i)
        nResult += pIntArray[i] * (int)pow(10, nSizeIn - i - 1);

    return nResult;
}

int* int2bin(int* pIntArray, unsigned int nSizeIn, unsigned int* nSizeOut){
    //0) Converting int array to the actual value
    int nVal = arr2int(pIntArray, nSizeIn);

    //1)Evaluating size of result array and allocating memory
    if(!nVal)
        *nSizeOut = 1;
    else
        *nSizeOut = (int)floor(log2(nVal)) + 1;

    //2)Allocate and init memory
    int* pResult = malloc(*nSizeOut);
    memset(pResult, 0, *nSizeOut * sizeof(int));

    //3) Evaluate binary representation
    for (unsigned int i = 0; i < *nSizeOut; ++i){
        int nBinDigit = (int)pow(2, i);
        if (nBinDigit == (nVal & nBinDigit))
            pResult[*nSizeOut - i - 1] = 1;
    }

    return pResult;
}

测试:

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#define _DC 9

int main()
{
    int test[_DC];
    for (int i = 0; i < _DC; ++i)
        test[i] = i;

    unsigned int nRes = 0;
    int* pRes = int2bin(test, _DC, &nRes);

    for (unsigned int i = 0; i < nRes; ++i)
        printf("%d", pRes[i]);

    free(pRes);
    return 0;
}