简体   繁体   English

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

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

I have a function named num_to_binary , which is used to convert a decimal number stored in the form of array.我有一个名为num_to_binary的函数,它用于转换以数组形式存储的十进制数。 The prototype for this function num_to_binary is as below:该函数num_to_binary的原型如下:

void num_to_binary(int *number_b, int size_of_number);

Here:这里:

number_b is pointer to array which stores my number. number_b是指向存储我的号码的数组的指针。 For example, if I would like to convert the number 12345 to binary, then I will be storing 12345 in number_b as follows:例如,如果我想将数字 12345 转换为二进制,那么我将 12345 存储在number_b ,如下所示:

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

Also, size_of_number is the number of digits in the number (or it is the number of elements in the array number_b ).此外, size_of_number是数字中的位数(或者它是数组number_b中元素的数量)。 So for the number 12345, size_of_number has the value 5.因此,对于数字 12345, size_of_number的值为 5。

Below is the full declaration of the function num_to_binary :下面是函数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];
    }
}

In the above function:在上面的函数中:

tmp_pointer : It is initially allocated some memory using malloc() , and is used to store the reverse of the binary representation of the number stored in number_b tmp_pointer :它最初使用malloc()分配了一些内存,用于存储number_b存储的数字的二进制表示的number_b

curr_size : It stores the current size of tmp_pointer . curr_size :它存储的当前大小tmp_pointer It is initially set to 1. i : It is used to keep track of the while loop.它最初设置为 1。 i :它用于跟踪while循环。 It is also used to reallocation purpose, which I have explained a bit later.它也用于重新分配的目的,我稍后会解释。

is_zero(number_b, size_of_number) : It is a function, which returns 1 if the number stored in number_b is 0, else it returns 1. is_zero(number_b, size_of_number)这是一个函数,它返回1 ,如果存储在所述数number_b是0,否则它返回1。

divide_by_2(number_b, size_of_number) : It divides the number stored in number_b by 2. It does NOT change the size of the array number_b . divide_by_2(number_b, size_of_number) :它将存储在number_b的数字number_b 2。它不会改变数组number_b的大小。

fin_ans : It is an integer pointer. fin_ans :它是一个整数指针。 Since the binary representation stored in the array tmp_pointer will be the reverse of the actual binary representation of the number, so fin_ans will store the correct binary representation of number by reversing the content of tmp_pointer .由于数组tmp_pointer存储的二进制表示将与数字的实际二进制表示相反,因此fin_ans将通过反转tmp_pointer的内容来存储数字的正确二进制表示。

Below is the how this function works :以下是此功能的工作原理:

  1. First of all, tmp_pointer is allocated a memory equal to the size of 1 int.首先, tmp_pointer被分配了一个等于 1 个 int 大小的内存。 So, now tmp_pointer can store an integer.所以,现在tmp_pointer可以存储一个整数。
  2. We now go into the while loop.我们现在进入while循环。 The loop will terminate only when the number stored in number_b equals 0.只有当number_b存储的number_b等于 0 时,循环才会终止。
  3. Now, we check if i is equal to 0 or not.现在,我们检查i是否等于 0。 If it is not equal to zero, then this means than the loops has been run atleast once, and in order to store the next binary digit, we resize the memory allocated to tmp_pointer so that it can store the next bit.如果它不等于 0,那么这意味着循环至少运行了一次,为了存储下一个二进制数字,我们调整分配给tmp_pointer的内存大小,以便它可以存储下一位。
  4. If the last digit of the number is odd, then that implies that the corresponding binary digit will be 1, else it will be 0. The if and else condition do this task.如果数字的最后一位是奇数,则意味着相应的二进制数字将为 1,否则为 0。 ifelse条件执行此任务。 They also increment i each time one of them is executed, and also divide the number by 2.每次执行其中一个时,它们也会增加i ,并将数字除以 2。
  5. Now, we are out of the loop.现在,我们脱离了循环。 It's time to reverse the binary number stored in tmp_pointer to get the final answer.是时候反转存储在tmp_pointer的二进制数以获得最终答案了。
  6. For this, we create a new pointer called fin_ans , and allocate it the memory which will be used for storing the correct binary representation of the number.为此,我们创建了一个名为fin_ans的新指针,并为其分配了用于存储数字的正确二进制表示的内存。
  7. The last for loop is used to reverse the binary representation and store the correct binary representation in fin_ans .最后一个for循环用于反转二进制表示并将正确的二进制表示存储在fin_ans

The problem:问题:

The code runs for small numbers such as 123, but for large numbers such as 1234567891, it gives a segmentation fault error.该代码针对小数(例如 123)运行,但对于大数(例如 1234567891),它会给出分段错误错误。 This can be checked by trying to print the digits stored in fin_ans .这可以通过尝试打印存储在fin_ans的数字来检查。

I tried using GDB Debugger, and got to know that the reason for Segmentation Fault lies in the while loop.我尝试使用 GDB Debugger,并了解到 Segmentation Fault 的原因在于while循环。 I am sure that the functions divide_by_2 and is_zero are not the reason for Segmentation Fault, since I have tested them thoroughly.我确信函数divide_by_2is_zero不是Segmentation Fault 的原因,因为我已经对它们进行了彻底的测试。

I also used DrMemory, which indicated that I am trying to access (read or write) a memory location which has not been allocated.我还使用了 DrMemory,这表明我正在尝试访问(读取或写入)尚未分配的内存位置。 Unfortunately, I am not able to figure out where the error lies.不幸的是,我无法弄清楚错误在哪里。

I suspect realloc() to be the cause of Segmentation Fault, but I am not sure.我怀疑realloc()是导致分段错误的原因,但我不确定。

Apologies for such a long question, however, I would highly appreciate any help provided to me for this code.对于这么长的问题,我深表歉意,但我非常感谢您为此代码提供的任何帮助。

Thanks in advance for helping me out !预先感谢您帮助我!

There are multiple problems in the code:代码中存在多个问题:

  • you do not check for memory allocation failure你不检查内存分配失败
  • you forget to free tmp_pointer before leaving the function.您忘记在离开函数之前释放tmp_pointer
  • you allocate a new array fin_ans to reserve the array tmp_pointer and perform the reverse operation but you do not return this array to the caller, nor do you have a way to return its size.您分配一个新数组fin_ans来保留数组tmp_pointer并执行相反的操作,但您没有将此数组返回给调用者,也没有办法返回其大小。 You should change the prototype to return this information.您应该更改原型以返回此信息。
  • if the number of zero, the converted number should probably have 1 digit initialized as 0, but you use malloc which does not initialize the array it allocates so tmp_pointer[0] is uninitialized.如果数字为零,则转换后的数字可能应该将 1 位数初始化为 0,但是您使用malloc不会初始化它分配的数组,因此tmp_pointer[0]未初始化。
  • you did not provide the code for is_zero() nor divide_by_two() .您没有提供is_zero()divide_by_two()的代码。 It is possible that bugs in these functions cause the segmentation fault, especially if the loop does not reach zero and memory is eventually exhausted during this infinite loop.这些函数中的错误可能会导致分段错误,尤其是在循环未达到零且内存最终在无限循环中耗尽的情况下。

Here is a modified version:这是一个修改后的版本:

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

There is no need for multiple memory reallocations.不需要多次内存重新分配。 Result memory buffer size could be easily evaluated as binary logarithm of the decimal input value.结果内存缓冲区大小可以很容易地评估为十进制输入值的二进制对数。 Calculation of the number binary representation could also be simplified:数字二进制表示的计算也可以简化:

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

Testing:测试:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM