Reputation: 3
I'm working on my C programming skills, but i'm kinda stuck on a problem:
I have an array of Animal structs, which i can add animals to. One of the values is the animalId, however, there is no check for duplicate id's. So for example, I can add three dogs with the same id, but they can be on different positions within the array.
I'm trying to write a function which lets me remove alle the animals with the same id from the array. With the code below, the program only removes the first animal with the found id. Also when I try to remove the same id again, the program does not find the rest. For the return I want to return the total number of animals removed.
Can you guys give me some tips what I'm doing wrong?
EDIT: moved the line "*newNumberOfAnimalsPresent = numberOfAnimalsPresent - 1;" outside of the j loop.
int removeAnimal(int animalId, Animal *animalArray, size_t numberOfAnimalsPresent, size_t *newNumberOfAnimalsPresent)
{
for (size_t i = 0; i < numberOfAnimalsPresent; ++i)
{
if (animalId == animalArray[i].Id)
{
for (size_t j = i; j < numberOfAnimalsPresent - 1; ++j)
{
animalArray[j] = animalArray[j + 1];
}
*newNumberOfAnimalsPresent = numberOfAnimalsPresent - 1;
}
}
return numberOfAnimalsPresent - *newNumberOfAnimalsPresent;
}
Upvotes: 0
Views: 78
Reputation: 8286
Use two counters to iterate through the array. check
is always incremented so every array element is checked. good
is only incremented when there is no match so it reflects the array element that are good and will be kept.
#include <stdio.h>
typedef struct {
int Id;
} Animal;
int removeAnimal(int animalId, Animal *animalArray, size_t numberOfAnimalsPresent, size_t *newNumberOfAnimalsPresent)
{
size_t good = 0;
size_t check = 0;
for ( good = 0, check = 0; check < numberOfAnimalsPresent; ++check)
{
if (animalId != animalArray[check].Id)//not a match
{
if ( good != check) {//not equal
animalArray[good] = animalArray[check];//make a copy
}
++good;//increment
}
}
*newNumberOfAnimalsPresent = good;
return check - good;
}
int main ( void) {
Animal pets[10] = {
{ 1}
, { 2}
, { 3}
, { 4}
, { 5}
, { 2}
, { 7}
, { 8}
, { 9}
, { 2}
};
int duplicates = 0;
size_t elements = 0;
size_t show = 0;
duplicates = removeAnimal ( 2, pets, 10, &elements);
printf ( "2 found %d times\n", duplicates);
while ( show < elements) {
printf ( "pet[%zu] id is %d\n", show, pets[show].Id);
++show;
}
return 0;
}
Upvotes: 0
Reputation: 350
Since you will only iterate over every item if there is no removal, I think it is better to forget the for loop and use a while instead:
int removeAnimal(int animalId, Animal *animalArray, size_t numberOfAnimalsPresent, size_t *newNumberOfAnimalsPresent)
{
*newNumberOfAnimalsPresent = numberOfAnimalsPresent;
int i = 0;
while (1)
{
if (*newNumberOfAnimalsPresent <= i)
{
break;
}
Animal animal = animalArray[i];
if (animalId == animal.Id)
{
for (size_t j = i; j < *newNumberOfAnimalsPresent - 1; j++)
{
animalArray[j] = animalArray[j + 1];
}
(*newNumberOfAnimalsPresent)--;
}
else
{
i++;
}
}
return numberOfAnimalsPresent - *newNumberOfAnimalsPresent;
}
Upvotes: 0
Reputation: 350
*newNumberOfAnimalsPresent = numberOfAnimalsPresent - 1;
should go after the j loop no?
Upvotes: 2