Давайте пройдем по программе один оператор за раз.
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
.