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



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

void num_to_binary(int *number_b, int size_of_number);

此处:

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

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):是一个函数,如果number_b中存储的数字为0,则返回1,否则返回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被分配了一个等于大小为1int。因此,现在tmp_pointer可以存储一个整数
  2. 现在我们进入while循环。循环将仅终止当存储在CCD_ 30中的数字等于0时
  3. 现在,我们检查i是否等于0。如果不等于零,则这意味着循环至少运行了一次,并且为了存储下一个二进制数字,我们调整内存大小分配给CCD_ 32以便其可以存储下一个比特
  4. 如果数字的最后一位是奇数,那么这意味着相应的二进制数字将为1,否则将为0。这个CCD_ 33和CCD_。它们也会增加i,并且还将该数字除以2
  5. 现在,我们脱离了循环。该倒二进制数了存储在CCD_ 36中以获得最终答案
  6. 为此,我们创建了一个名为fin_ans的新指针,并分配它是用于存储正确二进制文件的存储器数字的表示
  7. 最后一个for循环用于反转二进制表示并将正确的二进制表示存储在CCD_ 39中

问题:

该代码适用于123等小数字,但对于1234567891等大数字,它会给出分段错误。这可以通过尝试打印存储在fin_ans中的数字来进行检查。

我尝试使用GDB调试器,并了解到Segmentation Fault的原因在于while循环。我确信函数divide_by_2is_zero不是Segmentation Fault的原因,因为我已经对它们进行了彻底的测试。

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

我怀疑realloc()是Segmentation Fault的原因,但我不确定。

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

提前谢谢你帮我!

代码中存在多个问题:

  • 您没有检查内存分配失败
  • 您在离开该功能之前忘记释放tmp_pointer
  • 您分配了一个新的数组fin_ans来保留数组tmp_pointer并执行反向操作,但您没有将此数组返回给调用者,也没有返回其大小的方法。您应该更改原型以返回此信息
  • 如果数字为零,则转换后的数字可能会有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;
}

最新更新