Неверное исключение элементов из массива
Задание: Определить, есть ли в целочисленном массиве Q (10) заданное число Х, и если есть, удалить его (если встречается неоднократно, то удалить все такие значения), а если нет, добавить в конец массива.
Си
#include <stdlib.h>
int main()
{
int size = 5, *Q, i, j, x, count = 0;
Q = malloc(size * sizeof*Q);
for(i = 0; i < size; i++)
scanf("%d", &Q[i]);
for(i = 0; i < size; i++)
printf("%d ", Q[i]);
putchar('\n');
printf("Enter number:");
while(1 != scanf("%d", &x)){
printf("Incorrect data enter!Try again.");
while(getchar() != '\n');
}
for(i = 0; i < size; i++){
if(Q[i] == x){
count++;
for(j = i; j < size - 1; j++)
Q[j] = Q[j + 1];
}
}
if(count){
size -= count;
for(i = 0; i < size; i++)
printf("%d ", Q[i]);
putchar('\n');
}
else{
size++;
Q = realloc(Q, size * sizeof*Q);
if(!Q){
printf("Error allocate memory!");
return 0;
}
for(i = 0; i < size; i++){
if(i == size - 1)
Q[i] = x;
printf("%d ", Q[i]);
}
putchar('\n');
}
return 0;
}
В результате компиляции происходит неверное исключение элементов:
43
23
65
87
23
43 23 65 87 23
Enter number:23
43 65
Знакомый сказал, что это ошибка индексации, но я не понимаю в чём проблема.
Ответы (2 шт):
Массив Q изменяется три раза на итерациях 1, 3 и 4. Изменяется - громко сказано. Два последних изменения оставляют массив в прежнем состоянии. Для нас важно значение переменной count в конце. Предполагается что count считает элементы равные 23. Их два в исходном массиве. Но массив меняется, последнее значение удваивается и два раза подсчитывается:
i Q count 0 [43 23 65 87 23] 0 1 [43 65 87 23 23] 1 2 [43 65 87 23 23] 1 3 [43 65 87 23 23] 2 4 [43 65 87 23 23] 3
Вот правка, которая починит ваш код. Надо остановить цикл раньше чем кончится массив Q:
// for(i = 0; i < size; i++){
for(i = 0; i < size - count; i++){
По мере удаления элементов из массива
Qего размер уменьшается, и в хвосте массива остаются значения, оставшиеся после сдвига элементов. Их не следует удалять, но циклfor(i = 0; i < size; i++)никак не учитывает уменьшение размера массиваQи продолжает удаление элементов в хвосте. Поэтому счётчик количества удалённых элементовcountнаращивается больше, чем следует.Предположим, что элементы массива
Qс индексамиiиi+1должны быть удалены. Наi-той итерации циклаforвсе элементы массиваQначиная с индексаi+1будут сдвинуты на одну позицию левее. Т.е. элементi+1, который необходимо удалить, займёт позицию элементаiи на следующей итерации цикла избежит удаления.Сдвигать хвост массива на одну позицию левее при каждом удалении — не эффективно. Можно завести два индекса:
dest— позиция в массивеQ, в которую будем копировать элементы,src— позиция из которой копируем элементы.
В цикле перебираем элементы массива. Если наткнулись на элемент массива не подлежащий удалению, то копируем его изsrcвdestи наращиваем оба индекса.
Если наткнулись на элемент подлежащий удалению, то ничего не копируем и наращиваем только индексsrc.
Примерно так:
size_t src = 0, dest = 0;
while (src < size)
{
if (Q[src] != x)
{
Q[dest] = Q[src];
++dest;
}
++src;
}
if (src - dest > 0)
size -= src - dest;
else
{
++size;
int* Q_new = realloc(Q, size * sizeof *Q);
if (!Q_new)
{
free(Q);
printf("Error allocate memory!");
return EXIT_FAILURE;
}
Q = Q_new;
Q[size - 1] = x;
}
for (size_t i = 0; i < size; ++i)
printf("%d ", Q[i]);
putchar('\n');