Deleting rows from a structure - c

My project was to create a program with a menu that extracts data from a file and arranges it in a structure. Via the menu you are able to insert rows to the end of the structure or delete rows from the structure. The program then copies the structure and saves it to the same file.
So far I have everything working fine except for deleting rows.
Right now my code will just delete the last row of the structure no matter what.
else if( input == 3)
{
int delete;
printf("Enter row number to be deleted:\n");
scanf("%i", &delete);
if( delete > i )
{
printf("ERROR: Please enter a valid integer\n");
}
strcpy(data[delete].First, data[(delete+1)].First);
strcpy(data[delete].Last, data[(delete+1)].Last);
data[delete].Gender = data[(delete+1)].Gender;
data[delete].Age = data[(delete+1)].Age;
data[delete].Weight = data[(delete+1)].Weight;
data[delete].Height = data[(delete+1)].Height;
i = i - 1;
}
The variable i is a counter that keeps track of the number of rows in the structure. The code seems to me like it should replace the data of whatever the input delete is and replace it with the data above it in the structure, however it is not working.
Am I going about this the wrong way?

The variable i is a counter that keeps track of the number of rows …
Since you delete data[delete], the rows are apparently numbered from 0 to i-1. The if error condition delete > i should then rather be delete >= i.
if order isn't important, swap the last element with the one being
removed (unless you're removing the last element, obviously), then
just decrement i by one. No loop required. – WhozCraig
That's right, of course, albeit there is no point in the part of the swap which copies the element being removed to the position of the last element.
If the order is to be preserved, we can also do without an explicit loop:
memmove(data+delete, data+delete+1, (--i-delete) * sizeof *data);

Related

Printing values using loop

How can print following values using loop.
Basically i am taking size of array and adding first entry to middle of array if array is of size odd. If it is of even then taking first entry to below to half of array.Just like below i add 1 to 5th location.
Then second entry to first location. Third entry to below of first entry. Fourth entry to below to second entry. Fifth entry to below to Third entry and up to so on.
In simple First entry to center, second entry to top, third entry to below of center and up to so on.
2,4,6,8,1,3,5,7
Convention of pseudocode varies from author to author. This cannot be done in-place. Therefore, you need another array to copy the results.
left = 0, right = res.length/2
for i = 0 to res.length - 1:
if i is even:
res[right] = arr[i]
right++
else
res[left] = arr[i]
left++
arr is your original array and res is the empty array you are populating.

removing set interval of struct

im having trouble "removing" my struct/array. Right now i can define max array to be size 10. I can fill the array with struct containing name, age, ect. My search function will let me search between a set of interval, say age 10 to 25. What i want my remove function do is remove those all those people between age 10-25. I should be able to re-enter new people into the database as long as it doesn't exceed my defined limit. Right now it seems to randomly remove stuff from the array.
struct database
{
float age,b,c,d;
char name[WORDLENGTH];
};
typedef struct database Database;
search func();
.........
void remove(Database inv[], int *np, int *min, int *max, int *option)
{
int i;
if (*np == 0)
{
printf("The database is empty\n");
return;
}
search(inv, *np, low, high, option);
if (*option == 1)
{
for (i = 0; i<*np; i++)
{
if (inv[i].age >= *low && inv[i].age <= *high)
{
(*np)--;
}
}
}
}
Right now it seems to randomly remove stuff from the array.
The items that your code removes are not random at all. This line
(*np)--;
removes the last item. Therefore, if the range contains two items that match the search condition at the beginning of the inv, your code would remove two items off the end. Things get a little more complicated if matching items are located in the back of the valid range of inv, so deletions start looking random.
Deleting from an array of structs is not different from deleting from an array of ints. You need to follow this algorithm:
Maintain a read index and a write index, initially set to zero
Run a loop that terminates when the read index goes past the end
At each step check the item at read index
If the item does not match the removal condition, copy from read index to write index, and advance both indexes
Otherwise, advance only the read index
Set new np to the value of write index at the end of the loop.
This algorithm ensures that items behind the deleted ones get moved toward the front of the array. See this answer for an example implementation of the above approach.
You can't remove an array element simply by decreasing the count of number of elements.
If you want to remove the n'th element in the array, you have to overwrite the n'th element with the (n+1)'th element and overwrite the (n+1)'th element with the (n+2)'th element and so on.
Something like:
int arr[5] = { 1, 2, 3, 4, 5};
int np = 5;
// Remove element 3 (aka index 2)
int i;
for (i = 2; i < (np-1); ++i)
{
arr[i] = arr[i+1];
}
--np;
This is a simple approach to explain the concept. But notice that it requires a lot of copy so in real code, you should use a better algorithm (if performance is an issue). The answer from #dasblinkenlight explains one good algorithm.

comparing to arrays and returning the item that's missing?

I am not sure why I am not able to get this right, I spend some time on this, and I don't get what I want. and now I am upset. I have a list LL[] of desired items, and a list seenLL[] which may contain items from LL[], but in any random order. I wanted to put the missing items in unseen[] and then print unseen. At-least that is my idea :(
unsigned int i=0, j=0, k=0;
unsigned int LL[] = {0xB173,0xB193,0xB14D,0xB14E}; //Desired items
unsigned int seenLL[5]; // Seen items
unsigned int unseen[5]; // For unseen items
printf("\n List of Logcodes seen in filtered view :");
for(i=0;i<view->numFilters;i++){ // I can't explain this, as it's BIG
if(flt->filterType == LOGCODE_TYPE ){
printf(" 0x%04X,",flt->code); // This will print the list of items in the view. Usually about 2 or 3 items
seenLL[k]=flt->code; // Copy them to seenLL[]
k++;
}
}
k=0;
// At this point though my seenLL[] has a few of my desired items, it also contains junk information, which I am unable to explain.
for(i=0;i<sizeof(LL)/sizeof(LL[0]);i++){
for(j=0;j<sizeof(seenLL)/sizeof(seenLL[0]);j++){
if(LL[i] != seenLL[j]){
unseen[k]=LL[i]; // I was trying to copy to unseen[] items that are missing from the desired list LL[]
k++;
}
//else{ // Dumb, but what if seenLL[] had items from LL[] but not in the same order as they are in the array LL[], it can occur in any order
// if(sizeof(unseen)/sizeof(unseen[0])!=0)
// if(LL[i] == unseen[i]{
// k--;
// unseen[i]=0;
// }
}
}
if(k>0) printf(" Missing Logs Pkts :");
if(k>0) for(i=0;i<sizeof(unseen)/sizeof(unseen[0]);i++) //sigh! my pathetic attempt to print missing items.
printf("%d,",unseen[i]);
You must scan the seenLL array for each element of LL but properly detect if the element has been seen:
for (i = 0;i < sizeof(LL) / sizeof(LL[0]); i++) {
for (j = 0; j < sizeof(seenLL) / sizeof(seenLL[0]); j++) {
if (LL[i] == seenLL[j])
break;
}
if (j >= sizeof(seenLL) / sizeof(seenLL[0])) {
unseen[k++] = LL[i]; // scan went to the end, no match.
}
}
I suggest using the macro countof to clarify your code:
#define countof(a) ((sizeof(a) / sizeof((a)[0]))
The logic is wrong.
What you're doing: For each item in LL: if it is different from some item in seenLL, add it to unseen.
What you should do: For each item in LL: if it is different from every item in seenLL, add it to unseen.
(Another way to think of these two possible logics: the first one checks for some item whether it is the same as every item in seenLL, while the second one checks whether it is the same as some item in seenLL. It's clear that the first check cannot succeed if seenLL contains at least two different items.)
Array seenLL has space for only five elements, but there's nothing to suggest or ensure that the number of codes you attempt to record in it will be five or fewer if LL had more than five elements.
Furthermore, after you are done populating seenLL, you discard the value of variable k, which tells you how many of the elements of seenLL actually contain valied data.
Later, you test each element of LL against potentially all the elements of seenLL, possibly including some that do not contain valid data. In fact, you should test against all valid elements but no invalid ones, else you are likely to turn up all elements as unseen (they will fail to match at least one element of seenLL).
Array unseen also has space for only five elements, but there's nothing to suggest or ensure that the number of codes you attempt to record in it will be five or fewer.
Then, at the end, if you in fact did recognize any unseen elements, you print every element of unseen, likely including some that do not contain valid data.

Struct listing , member delete

i'm a freshman computer engineering student. When i preparing an program to store students' info in a C program, some problems appeared.
screen : http://imgim.com/5025incii2829330.jpg
I've added two students and deleted first student's info. But first student's info still appears as empty.
here's the code : http://pastebin.com/R6rSXaft
In your orgListele function, you are iterating through an array of students in order to print out the information. Your for loop prints information like so:
for (i = 0; i<sayi; i++)
{
printf("\n\nStudent:%d\n", i + 1);
printf("ID:%s\n ", listeler[i].id);
printf("National ID:%s\n", listeler[i].tckimlik);
printf("Name:%s\n", listeler[i].isim);
printf("Address:%s\n", listeler[i].adres);
printf("Phone Number:%s\n", listeler[i].telefonnum);
}
It looks like you are not really deleting students from the array (not possible, anyways), just clearing their information. You have created the list of liste structures as an array rather than a list with variable size. When you iterate through it, you are printing the students, even if their information has been cleared.
To achieve the output that you want, I would do one of two things:
Use a linked list and delete the nodes that you want. When you traverse the list to print everything out, you will not be using deleted nodes because they are not referenced by your list any more. The array implementation does not offer this "deletion" aspect. It will also allow this application to scale past 30 students (which is a limitation posed by your array, declared as struct liste listeler[30];. This is the approach I would take. See here for some information on linked lists.
Add another flag to your liste struct to maintain deletion state. If you add something that acts as a boolean value, say int isValid, you will be able to clear that variable (make it 0) for the next time you run through the loop. Then, you can say if (listeler[i].isValid) {//print everything} and skip over those students who have been marked as invalid (isValid = 0)
change
for (i = 0; i<sayi; i++) //kayit sayisi degismediginden
{
printf("\n\nStudent:%d\n", i + 1);
printf("ID:%s\n ", listeler[i].id);
printf("National ID:%s\n", listeler[i].tckimlik);
printf("Name:%s\n", listeler[i].isim);
printf("Address:%s\n", listeler[i].adres);
printf("Phone Number:%s\n", listeler[i].telefonnum);
}
to
for (i = 0; i<sayi; i++) //kayit sayisi degismediginden
{
if(listeler[i].id == 0) contnue; // skip the element if id is zero (zero idicates deleted item)
printf("\n\nStudent:%d\n", i + 1);
printf("ID:%s\n ", listeler[i].id);
printf("National ID:%s\n", listeler[i].tckimlik);
printf("Name:%s\n", listeler[i].isim);
printf("Address:%s\n", listeler[i].adres);
printf("Phone Number:%s\n", listeler[i].telefonnum);
}
You don't keep track of which structures are "empty" or not, you always print all up to the limit imposed by the sayi global variable.
The simple solution is to skip printing those with an empty id, for example, or some other field.
Setting the variable's value to NULL doesn't delete the variable... It simply makes it null. Consider looking into dynamic memory allocation, and using the free() method when you want to delete a student, which has been malloced.
You have removed the information about the student, but you have not deleted the record. You need to delete the record and adjust the list (listeler) so that there are no empty entries within the entries contained.

dynamic array auto shrink

When designing a dynamic array which will shrink, what is a method to keep track of the highest used index, and when that index's held object is deleted, find the new highest used index.
Right now I can think up having a a simple int last_used and then charging the cost of maintaining this variable to the func_delete which must check if it deletes the highest, and if so, check each smaller value looking for a non null. (array will always be null initialized)
if(last_index == deleted_index){
while(last_index >0 && array[--last_index] != NULL)
// if the array is now only half full, I realloc
}
Is there any other smart ways?
It looks okay to me, but logic wise, if the function func_delete always deletes the highest item, then there shouldn't be any NULL values at smaller indices. So this should do:
if(last_index == deleted_index && array[last_index] != NULL) {
//delete last item
free(array[last_index]);
//set to NULL and decrement
array[last_index--] = NULL;
}
Edit:
based on your comments, I understand what you're trying to do, I think you could just keep track of the highest used index in the insertion function instead:
void array_insert(array , element e, int index)
{
if (index > arr->highest_index) {
arr->highest_index = index;
}
//insert element
}
And when you delete you check if the index is the highest or not. like you're doing, don't think there's a better way to do that, without complicating things further, for example, you could keep another sorted list of indices, this way you when you delete the highest index you find the next one in constant time, but like I said, it complicates things. However, I think another data structure might be more useful, a linked list for example, is more efficient when randomly deleting nodes, but not when randomly inserting nodes.

Resources