Странное поведение функции с mallo c () и reallo c (), приводящее к ошибке сегментации - PullRequest
0 голосов
/ 26 января 2020

У меня есть функция с именем 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 l oop. Он также используется для целей перераспределения, что я объяснил чуть позже.

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. Теперь мы go в while l oop. Значение l oop завершится только тогда, когда число, сохраненное в number_b, равно 0.
  3. Теперь мы проверяем, равно ли i 0 или нет. Если он не равен нулю, то это означает, что цикл был запущен как минимум один раз, и для сохранения следующего двоичного файла di git мы изменяем размер памяти, выделенной для tmp_pointer, чтобы она могла хранить следующий бит .
  4. Если последнее число di git является нечетным, то это означает, что соответствующий двоичный код di git будет равен 1, в противном случае он будет равен 0. Условие if и else сделать это задание Они также увеличивают i каждый раз, когда выполняется одно из них, а также делят число на 2.
  5. Теперь мы вышли из l oop. Пришло время перевернуть двоичное число, хранящееся в tmp_pointer, чтобы получить окончательный ответ.
  6. Для этого мы создадим новый указатель с именем fin_ans и выделим ему память, которая будет использоваться для хранения правильного двоичное представление числа.
  7. Последнее for l oop используется для обращения двоичного представления и сохранения правильного двоичного представления в fin_ans.

Проблема :

Код выполняется для небольших чисел, таких как 123, но для больших чисел, таких как 1234567891, выдает ошибку ошибки сегментации. Это можно проверить, попытавшись напечатать цифры, хранящиеся в fin_ans.

. Я попытался использовать отладчик GDB и узнал, что причина ошибки сегментации заключается в while l oop. Я уверен, что функции divide_by_2 и is_zero не являются причиной ошибки сегментации, поскольку я тщательно их протестировал.

Я также использовал DrMemory, который указывал, что я пытаюсь получить доступ (читай или запись) ячейка памяти, которая не была выделена. К сожалению, я не могу понять, где лежит ошибка.

Я подозреваю, что realloc() является причиной ошибки сегментации, но я не уверен.

Извиняюсь за такой длинный вопрос, однако я был бы очень признателен за любую помощь, оказанную мне для этот код.

Заранее спасибо за помощь!

Ответы [ 2 ]

1 голос
/ 27 января 2020

В коде есть несколько проблем:

  • вы не проверяете ошибку выделения памяти
  • вы забыли освободить tmp_pointer перед выходом из функции.
  • Вы выделяете новый массив fin_ans для резервирования массива tmp_pointer и выполняете обратную операцию, но вы не возвращаете этот массив вызывающей стороне и не можете вернуть его размер. Вы должны изменить прототип так, чтобы он возвращал эту информацию.
  • если число ноль, преобразованное число должно иметь 1 di git, инициализированное как 0, но вы используете malloc, который не инициализирует массив выделяется таким образом, чтобы tmp_pointer[0] не было инициализировано.
  • Вы не предоставили код для is_zero() или divide_by_two(). Возможно, что ошибки в этих функциях вызывают ошибку сегментации, особенно если l oop не достигает нуля и память в конечном итоге исчерпывается в течение этого бесконечного l oop.

Вот модифицированный версия:

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;
}
0 голосов
/ 27 января 2020

Нет необходимости в нескольких перераспределениях памяти. Размер буфера памяти результатов можно легко оценить как двоичный логарифм десятичного входного значения. Вычисление двоичного представления числа также может быть упрощено:

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