Условие программы: удалить все нули в одномерном массиве (тема: массивы и указатели)
На массив нужно динамически выделить и перевыделить память, к элементам массива нужно обращаться через указатели. Проблема с реаллоком - работает коряво. Помогите разобраться, как мне уменьшить (или увеличить, например, если по условию нужно будет добавлять элементы) размер массива в моём цикле, заранее спасибо.
#include "stdio.h"
#include "time.h"
#include "stdlib.h"
int main()
{
int i, j, n, c = 0, * a, *A, k = 0;
printf("N: ");
scanf_s("%d", &n);
srand(time(NULL));
a = (int*)malloc(n * sizeof(int));
if (!a) return -1;
for (i = 0; i < n; i++)
printf("%d ", *(a + i) = rand() % 9 - 6);
printf("\n");
for (i = j = 0; i + j < n; i++)
{
while (c == *(a + i + j))
{
j++;
*(a + i) = *(a + i + j);
k++;
}
}
i -= *(a + n - 1) == c;
A = (int*)realloc(a, (n-k) * sizeof(int));
if (!A) return -1;
for (j = 0; j < i; j++)
{
printf("%d ", *(a + j));
}
free(A);
return 0;
}
Примеры:
1 пример:
1)входные данные: 2 1 -6 -5 2 2 0 -1 -1 -2;
2)итоговые данные: 2 1 -6 -5 2 2 -1 -1 -1;
3)ожидаемые данные: 2 1 -6 -5 2 2 -1 -1 -2;
2 пример:
1)входные данные: -1 0 0 -5 -3 -2 -5 -1;
2)итоговые данные: -1 -5 0 -5 -3 -2;
3)ожидаемые данные: -1 -5 -3 -2 -5 -1;
Ответы (3 шт):
Объясню на примере в чем ошибка вашего кода:
1 0 -4 3
На моменте когда вы доходите до 0 вы заменяете его на -4 и увеличиваете k до 1.
Получаете вот такую картину:
1 -4 -4 3
И перевыделяете память удаляя последний элемент. Получаете вот это:
1 -4 -4
Вот пример кода с комментариями:
//2 итератора i и j
//i - итератор замены, j - итератор сравнения
//то есть *(a + i) вы будете заменять на *(a + j)
//алгоритм основывается на том чтобы *(a + j) было ближайшее справа число != 0
for (i = j = 0; i < n && j < n; i++, j++)
{
//Сдвигаем итератор j вправо пока не дойдем до числа != 0
//увеличивая k
while (j < n && *(a + j) == c) {
j++;
k++;
}
//Если i != j то мы нашли как минимум один 0
//производим замену
if (j < n && i != j)
*(a + i) = *(a + j);
}
Например возьмем те же числа, как в примере выше:
1 0 -4 3
Дойдя до 0 мы будем иметь i = 1, j = 1, k = 0 после выполнения цикла получим i = 1, j = 2, k = 1 и следующее что мы делаем это заменяем *(a + 1) на *(a + 2), то есть 0 на -4. И теперь каждую итерацию мы будет заменять i элемент на i + 1 (в нашем случае т.к. у нас один 0).
В итоге получим:
1 -4 3 3
И т.к. k = 1 обрежем последний элемент, получив:
1 -4 3
Предложу ещё модифицированный вариант программы, с некоторыми комментариями. На мой взгляд, он более понятный и тут лучше раскрыта тема работы с указателями:
#include "stdio.h"
#include "time.h"
#include "stdlib.h"
int main()
{
int i, n, k;
int c = 0;
int *a, *A, *a_end, *p, *p_next;
printf("Enter n: ");
scanf("%d", &n);
a = (int*)malloc(n*sizeof(int));
if (!a) return -1;
a_end = a+n; //указатель за конец масива
srand(time(NULL));
for (p = a; p < a_end; ++p)
printf("%d ", *p = rand()%9-6);
printf("\n");
//ищем первый ноль
for (p = a; p<a_end; ++p)
if (*p==c) break;
//удаляем нули
p_next = p;
while ((++p_next)<a_end)
{
if (*p_next==c) continue;
*(p++) = *p_next;
}
k = p-a; //новый размер масива
if (k)
{
A = (int*)realloc(a, k*sizeof(int));
if (!A)
{
free(a); //функция realloc() сама не освобождает память при неудаче
return -1;
}
a_end = A+k;
for (p = A; p<a_end; ++p)
printf("%d ", *p);
printf("\n");
free(A);
return 0;
}
printf("Empty array!\n");
free(a);
return 0;
}
Проще всего выкинуть из массива нули -- это тупо переписать массив сам в себя, пропуская нули.
Если хочется сделать это с указателями (а не индексами массива), то вот возможный фрагмент кода
int *end = a + n; // `a` -- это исходный масив из `n` элементов, выделенный по `malloc()`
int *to = a;
for (int *f = a; f < end; f++) // вот и весь цикл, выбрасывающий нули
if (*f)
*to++ = *f;
printf("now %d elements\n", n = to - a);
a = (int *)realloc(a, n * sizeof(int));