首页 > 解决方案 > malloc() 和 realloc() 函数的奇怪行为导致分段错误

问题描述

我有一个名为 的函数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):它是一个函数,1如果存储的数字number_b为0,则返回,否则返回1。

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。如果它不等于 0,那么这意味着循环至少运行了一次,为了存储下一个二进制数字,我们调整分配的内存大小,tmp_pointer以便它可以存储下一位。
  4. 如果数字的最后一位是奇数,则意味着相应的二进制数字将为 1,否则将为 0。and if条件else执行此任务。i每次执行其中一个时,它们也会递增 ,并将数字除以 2。
  5. 现在,我们脱离了循环。是时候反转存储的二进制数tmp_pointer以获得最终答案了。
  6. 为此,我们创建一个名为 的新指针fin_ans,并为其分配内存,用于存储数字的正确二进制表示。
  7. 最后一个for循环用于反转二进制表示并将正确的二进制表示存储在fin_ans.

问题:

该代码对 123 等小数运行,但对于 1234567891 等大数,它会给出分段错误错误。这可以通过尝试打印存储在fin_ans.

我尝试使用 GDB Debugger,并了解到 Segmentation Fault 的原因在于while循环。我确信这些功能并不是分段错误的原因,因为我已经对它们进行了彻底的测试divide_by_2is_zero

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

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

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

提前感谢您帮助我!

标签: cpointersmallocrealloc

解决方案


代码中存在多个问题:

  • 你不检查内存分配失败
  • tmp_pointer您在离开该功能之前忘记释放。
  • 您分配一个新数组fin_ans来保留该数组tmp_pointer并执行相反的操作,但是您没有将此数组返回给调用者,也没有办法返回其大小。您应该更改原型以返回此信息。
  • 如果数字为零,则转换后的数字可能应该有 1 位初始化为 0,但您使用malloc的不会初始化它分配的数组,因此tmp_pointer[0]未初始化。
  • 您没有提供is_zero()nor的代码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;
}

推荐阅读