указатель int, являющийся realloc'd, не был размещен - PullRequest
0 голосов
/ 10 ноября 2018

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

#include <stdio.h>
#include <stdlib.h>

void addInteger(int **iArr, int *newI, int * count);
int main(){
    int* iArr = malloc(0);
    int iCount = 0;
    int newInt = 0;
    int i;
    for(i=0;i<5;i++){
        printf("Enter number: ");
        scanf("%d",&newInt);
        iCount++;
        iArr = realloc(iArr, sizeof(int*) * iCount);
        addInteger(&iArr, &newInt, &iCount);
    }
    free(iArr);
    return 0;
}
void addInteger(int **iArr, int *newI, int * count){

    iArr[*count-1] = malloc(sizeof(int));
    iArr[*count-1] = newI;
}

Запуск его с моими входами выдает ошибку на втором числе:

Введите номер: 1

Введите номер: 3

a.out (1291,0x7fffb62df380) malloc: *** ошибка для объекта 0x7ffeed674b78: указатель, являющийся realloc'd, не был выделен

*** установить точку останова в malloc_error_break для отладки

Отмена прерывания: 6

Ответы [ 2 ]

0 голосов
/ 10 ноября 2018

Давайте пройдем по программе один оператор за раз.

int* iArr = malloc(0);

iArr равен либо NULL или указывает на объект размером 0.

int iCount = 0;
int newInt = 0;
int i;
for(i=0;i<5;i++){

Inпервая итерация, у нас есть i = 0.

    printf("Enter number: ");
    scanf("%d",&newInt);

Допустим, пользователь ввел здесь 42, поэтому newInt = 42.

    iCount++;

Теперь iCount = 1.

    iArr = realloc(iArr, sizeof(int*) * iCount);

Это подозрительно: iArr объявлен как указатель на int (который может использоваться для указания на массив целых чисел), но вы не выделяете место для iCount целых чисел, вы 'перераспределение пространства для iCount указателей на int.

Если iArr подразумевается как динамический массив указателей на int, он должен был быть объявлен как int ** iArr;

Если iArr подразумевается как динамический массив int, этот вызов должен быть изменен на

iArr = realloc(iArr, sizeof (int) * iCount);

или (предпочтительно):

iArr = realloc(iArr, sizeof *iArr * iCount);

Эта последняя форма всегда верна 1 , независимо от того, как объявлено iArr.

(Передача NULL в качестве первого аргумента realloc - это нормально, поэтому не имеет значения, что именно malloc(0)возвращенныйизначально.)

    addInteger(&iArr, &newInt, &iCount);

Давайте встроим эту функцию здесь (я изменил имена параметров, чтобы было более понятно, что происходит):

    int **addInteger_iArr = &iArr;
    int *addInteger_newI = &newInt;
    int *addInteger_count = &iCount;

Мы инициализируем параметры функции.

    addInteger_iArr[*addInteger_count-1] = malloc(sizeof(int));

ОК, так что же на самом деле делает эта строка?Мы знаем значение addInteger_count;это &iCount, поэтому давайте просто подключим это:

    addInteger_iArr[*(&iCount)-1] = malloc(sizeof(int));

* и & отменяем друг друга, давая:

    addInteger_iArr[iCount-1] = malloc(sizeof(int));

iCount равно 1 и 1-1 равно 0, поэтому это становится:

    addInteger_iArr[0] = malloc(sizeof(int));

Аналогично, давайте подключим значение addInteger_iArr, которое равно &iArr:

    (&iArr)[0] = malloc(sizeof(int));

a[b] определяется как *(a + b) как C, поэтому эта строка означает:

    *(&iArr + 0) = malloc(sizeof(int));

Добавление 0 ничего не делает, а * и & отменяют друг друга, поэтому мы получаем:

    iArr = malloc(sizeof(int));

Привет!Мы только что потеряли старое значение iArr (указатель возвращается realloc).Это утечка памяти.

    addInteger_iArr[*addInteger_count-1] = addInteger_newI;

Левая часть назначения такая же, как в предыдущем выражении;addInteger_newI совпадает с &newInt:

    iArr = &newInt;

Эй!Мы только что потеряли старое значение iArr (указатель, возвращенный malloc в предыдущем выражении).Это еще одна утечка памяти.

Кроме того, iArr больше не указывает на динамически распределенную память;он указывает на newInt, который является просто локальной переменной.

}

Теперь мы начинаем вторую итерацию цикла.Это приводит к сбою в realloc(iArr, ...), потому что в этот момент iArr имеет значение &newInt.


Есть несколько возможных способов исправить этот код.

Если вы просто хотитепростой динамический массив целых чисел, вы должны изменить свой цикл на:

    iCount++;
    iArr = realloc(iArr, iCount * sizeof *iArr);
    iArr[iCount-1] = newInt;

И если вы хотите переместить этот последний оператор в функцию:

    addInteger(iArr, iCount, newInt);

с помощью

void addInteger(int *iArr, int iCount, int newInt) {
    iArr[iCount-1] = newInt;
}

1 Ну, расчет размера правильный.Вам все еще нужно проверить, не удалось ли realloc, в этом случае он возвращает NULL, и вам нужно free указатель вручную, и, как правило, вы должны проверить на целочисленное переполнение в расчете size * items.

0 голосов
/ 10 ноября 2018

У вас есть ошибки при разыменовании:

Переменная iArr является указателем на массив типа int.

Но вы передаете его адрес addInteger, а затем заменяете этот адрес случайным входным значением.

Затем это случайное входное значение передается в realloc вместо указателя, который вы указали, а теперь он пропал.

Итак, вы получите ошибку.

Позволяет исправить ваш код, чтобы избежать этого:

//NOTE: there is no need to pass newI and count as pointers, because the function does not change them!
void addInteger(int **iArr, int newI, int count);
int main(){
    //1. If you want iArr to be array of pointers, you need to start with ** pointer to pointer
    //2. Just initialize with NULL, when realloc gets NULL it works just like malloc
    int** iArr = NULL;
    int iCount = 0;
    int newInt = 0;
    int i;

    for(i=0;i<5;i++){
        printf("Enter number: ");
        scanf("%d",&newInt);
        iCount++;
        iArr = realloc(iArr, sizeof(int*) * iCount);
        //You do not need to pass addresses here because your function does not change its parameters
        addInteger(iArr, newInt, iCount);
    }

    free(iArr); //this will cause a memory leak!
    //you need to loop over the array and free each integer first.

    return 0;
}

void addInteger(int **iArr, int newI, int count){
    iArr[count - 1] = malloc(sizeof(int));
    *iArr[count - 1] = newI;
    /* Note the * here - it is important!
       Without it, you would overwrite the pointer you just allocated in the prevoius line
       But the * tells the compiler "put the int value at the address specified by the array
    */
}
...