Как realloc может не работать, а malloc может? - PullRequest
1 голос
/ 10 мая 2011

Я достиг точки, где realloc прекращает возвращать указатель - я предполагаю, что для расширения или перемещения массива недостаточно места.Единственная проблема в том, что мне действительно нужно, чтобы память существовала, или приложение не может работать так, как ожидалось, поэтому я решил попробовать malloc - ожидая, что он не будет работать, поскольку realloc не будет работать - но он это сделал.Почему?

Затем я запомнил массив указателей в новый выделенный массив, но обнаружил, что он сломал его, указатели типа 0x10 и 0x2b были помещены в массив.Существуют настоящие указатели, но если я заменю memcpy на цикл for, это исправит это.Почему memcpy сделал это?Разве я не должен использовать memcpy в моем коде?

Код:

float * resizeArray_by(float *array, uint size)
{
    float *tmpArray = NULL;
    if (!array)
    {
        tmpArray = (float *)malloc(size);
    }
    else
    {
        tmpArray = (float *)realloc((void *)array, size);
    }

    if (!tmpArray)
    {
        tmpArray = (float *)malloc(size);
        if (tmpArray)
        {
            //memcpy(tmpArray, array, size - 1);
            for (int k = 0; k < size - 1; k++)
            {
                ((float**)tmpArray)[k] = ((float **)array)[k];
            }
            free(array);
        }
    }

    return tmpArray;
}

void incrementArray_andPosition(float **& array, uint &total, uint &position)
{
    uint prevTotal = total;
    float *tmpArray = NULL;
    position++;
    if (position >= total)
    {
        total = position;
        float *tmpArray = resizeArray_by((float *)array, total);
        if (tmpArray)
        {
            array = (float **)tmpArray;

            array[position - 1] = NULL;
        }
        else
        {
            position--;
            total = prevTotal;
        }
    }
}

void addArray_toArray_atPosition(float *add, uint size, float **& array, uint &total, uint &position)
{
    uint prevPosition = position;
    incrementArray_andPosition(array, total, position);

    if (position != prevPosition)
    {
        float *tmpArray = NULL;
        if (!array[position - 1] || mHasLengthChanged)
        {
            tmpArray = resizeArray_by(array[position - 1], size);
        }

        if (tmpArray)
        {
            memcpy(tmpArray, add, size);
            array[position - 1] = tmpArray;
        }
    }
}

После всех моих исправлений, код, вероятно, начался.Интересно, что после сортировки массивов я выделяю с помощью malloc огромный массив, чтобы переупорядочить массивы в один массив, который будет использоваться как GL_ARRAY_BUFFER.Если realloc не выделяется из-за нехватки места, то почему не выделяет?

Наконец, в конце концов это приводит к краху.После прохождения через функцию рендеринга однажды она вылетает.Если бы я удалил все свои исправления и просто поймал, когда realloc не выделяет, он бы работал нормально.В связи с этим возникает вопрос: что плохого в том, чтобы неправильно использовать мой массив вместо того, чтобы перераспределять, что вызывает проблемы в дальнейшем?

Массивы My Array являются указателями на указатели с плавающей точкой.Когда я расту массив, он преобразуется в указатель на float и перераспределяется.Я строю на Android, поэтому я предположил, что там не хватает памяти.

Ответы [ 3 ]

3 голосов
/ 10 мая 2011

Судя по разным битам информации (realloc не находит память, memcpy ведет себя неожиданно, вылетает), это звучит очень похоже на повреждение кучи. Без некоторых примеров кода того, что вы делаете, трудно сказать наверняка, но кажется, что в какой-то момент вы неправильно управляете памятью, из-за чего куча переходит в недопустимое состояние.

Можете ли вы скомпилировать свой код на альтернативной платформе, такой как Linux (вам может понадобиться заглушить некоторые специфичные для Android API)? Если это так, вы можете увидеть, что происходит на этой платформе, и / или использовать valgrind, чтобы выследить его.

Наконец, поскольку у вас есть этот тег C ++, почему вы используете malloc / realloc вместо, например, vector (или другого стандартного контейнера) или new?

1 голос
/ 10 мая 2011

Вы путаете size и типы указателей.При выделении памяти size - это число байтов, и вы конвертируете тип указателя в float *, создавая массив размером float size / sizeof(float).В коде, эквивалентном memcpy, вы обрабатываете массив как float ** и копируете size из них.Это уничтожит кучу, если предположить, что sizeof(float *) > 1, и, вероятно, является источником последующих проблем.

Более того, если вы копируете, скажем, массив размером 100 в массив размером 200, вам нужноскопировать более 100 элементов, а не 200. Копирование за конец массива (что вы и делаете) может привести к сбоям программы.

Динамически распределенный массив указателей на float s будеттипа float **, а не float * и, конечно, не является смесью двух.Размер массива - это количество байтов для malloc и друзей, а также количество элементов во всех операциях массива.

memcpy будет верно копировать байты, предполагая, что блоки источника и назначения не перекрываются (и отдельно выделенных блоков памяти нет).Однако вы указали size - 1 для количества копируемых байтов, когда копируемое число должно быть точным размером байта старого массива.(В любом случае, где вы получаете неверные значения указателя? Если он находится в расширенной части массива, вы все равно копируете туда мусор.) Если memcpy дает вам бессмыслицу, то с самого начала она получает глупость, и это не так.твоя проблема.

0 голосов
/ 10 мая 2011

И, кстати, вам не нужно проверять, является ли array NULL

Вы можете заменить

if (!array)
{
    tmpArray = (float *)malloc(size);
}
else
{
    tmpArray = (float *)realloc((void *)array, size);
}

от

tmpArray = realloc(array, size*sizeof (float));

realloc действует как malloc при указании NULL указателя.

Еще одна вещь, будьте осторожны, размер не равен 0, так как realloc с 0, так как размер совпадает с free.

Третий пункт, указывайте не тип указатели, когда это не является строго необходимым. Вы определили возврат функций распределения, это считается плохой практикой начиная с ANSI-C. Это обязательно в C ++, но поскольку вы используете распределение C, вы явно не в C ++ (в этом случае вы должны использовать new / delete). Преобразование переменной массива в (void *) также не является необходимым, поскольку оно может скрывать некоторые предупреждения, если ваш параметр был объявлен неверно (это может быть int или указатель на указатель, и при приведении вы бы подавили предупреждение).

...