【问题标题】:Weird behaviour of function with malloc() and realloc() resulting in Segmentation Faultmalloc() 和 realloc() 函数的奇怪行为导致分段错误
【发布时间】:2020-01-26 16:29:43
【问题描述】:

我有一个名为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):它是一个函数,如果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 分配的内存等于 大小为 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 中。

问题:

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

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

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

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

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

提前感谢您帮助我!

【问题讨论】:

  • 起始数字是字符串,但是转换为数字是通过循环遍历字符串的每个字符,然后将每个字符转换为对应的数字,最后将每个数字存储在数组number_b中。跨度>

标签: c pointers malloc realloc


【解决方案1】:

代码中存在多个问题:

  • 你不检查内存分配失败
  • 您忘记在离开函数之前释放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;
}

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 2018-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-10
      • 2013-06-16
      • 2016-03-27
      • 1970-01-01
      相关资源
      最近更新 更多