How to remove elements from Struct - c

I am wondering how the previously entered info can be deleted using decrement.
case 4: printf("Remove Employee\n");
printf("===============\n");
do{
printf("Enter Employee ID: ");
scanf("%d", &number);
int i;
for(i=0;i<NOE; i--){
if(number == emp[i].Int_Num){
printf("Employee %d will be removed", emp[i].Int_Num);
// for(i=0;i<NOE; i++){
-- emp[i].Int_Num, --emp[i].Salary, --emp[i].Age;
// scanf("%11lf", &emp[i].Salary);
flag = 1;
break;

The typical data structure for a collection whose number of elements changes frequently, in arbitrary order, is a linked list. (Or, if you need faster access and have an order criteria like your employee number, a sorted tree). You would allocate new elements (here: employees) with malloc() and truly remove them from memory with free.
Alternatively, if there is a known maximum number of employees and you have enough memory you can use an array, which you appear to do here. The number of elements in the array would be the expected maximum number of employees; the program would therefore always need the maximum amount of memory, even with very few employees. On the other hand the memory footprint of the program would be statically known at compile time which can be an advantage.
The number of elements in an array cannot be changed (unless you allocate the whole array dynamically and reallocate if and when needed). Adding new employees or deleting existing ones would be done, as Bo Persson suggested, through a marker for those elements which are in use. That could be an extra boolean flag, or a special value in one of the existing fields.
In effect though you will be programming your own crude dynamic memory management that way, using the array as an "arena". It will probably be more buggy and slower than if you just used the built-in one.

Related

Implementing a Hash Table using C

I am trying to read a file of names, and hash those names to a spot based on the value of their letters. I have succeeded in getting the value for each name in the file, but I am having trouble creating a hash table. Can I just use a regular array and write a function to put the words at their value's index?
while (fgets(name,100, ptr_file)!=NULL) //while file isn't empty
{
fscanf(ptr_file, "%s", &name); //get the first name
printf("%s ",name); //prints the name
int length = strlen(name); // gets the length of the name
int i;
for (i =0; i <length; i++)
//for the length of the string add each letter's value up
{
value = value + name [i];
value=value%50;
}
printf("value= %1d\n", value);
}
No, you can't, because you'll have collisions, and you'll thus have to account for multiple values to a single hash. Generally, your hashing is not really a wise implementation -- why do you limit the range of values to 50? Is memory really really sparse, so you can't have a bigger dictionary than 50 pointers?
I recommend using an existing C string hash table implementation, like this one from 2001.
In general, you will have hash collisions and you will need to find a way to handle that. The two main ways of handling that situation are as follows:
If the hash table entry is taken, you use the next entry, and iterate until you find an empty entry. When looking things up, you need to do similarly. This is nice and simple for adding things to the hash table, but makes removing things tricky.
Use hash buckets. Each hash table entry is a linked list of entries with the same hash value. First you find your hash bucket, then you find the entry on the list. When adding a new entry, you merely add it to the list.
This is my demo-program, which reads strings (words) from stdin, and
deposit into hashtable. Thereafter (at EOF), iterate hashtable, and compute number of words, distinct words, and prints most frequent word:
http://olegh.cc.st/src/words.c.txt
In hashtable, utilized double hashing algorithm.

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.

Malloc Realloc Free

Hello I for an exercise at University i need to malloc an array with this way. The array at stars has 1 slot. If the inputs are more than one then the array is doubled. If the inputs are more than 2 then it is doubled again etc. After this I have to crop the array to fit to the number of inputs. For example if I have 5 inputs then the array will have 8 slots and I must make it to have 5 slots which I cannot figure out how. Here is my code so far:
nameInfoT* ReadNames(int* size){
nameInfoT* names ;
int array_size=1;
int entries=0;
char input[length];
names=(nameInfoT*) malloc(sizeof(nameInfoT)*array_size);
do{
scanf("%s",input);
if(!strcmp(input,"END")) break;
if(entries==array_size){
array_size=array_size*2;
names= (nameInfoT*) realloc(names,sizeof(nameInfoT)*array_size);
}
names[entries].name=(char*)malloc(sizeof(char)*strlen(input));
strcpy(names[entries].name,input);
entries++;
}while(1);
printf("there are %d free spaces \n",array_size-entries);
*size=entries;
printf("there are %d entries \n",*size);
int i;
for(i=array_size;i>entries;i--){
free(names[i]);//here it won't compile
}
return names;
}
You can only free the result of malloc/calloc/realloc. You cannot free individual elements. So in the end you can simply realloc again to the desired final size.
You have a couple of other problems:
1) when you allocate space for the input string, you need to add 1 to keep the trailing '\0'
2) before your realloc, you should have a switch statement which will take the array_size and use that to determine the new size. If I understand your problem, you want to go from 1 -> 2 -> 4 -> n (where n is the next number). Your realloc code just doubles each time. You need to change that.
3) when you free the entries, you need to be careful since you don't seem to be freeing the 'name' member of the class/struct.
4) after freeing the members in the loop, then do one free on the names class/struct.
I could look into it more carefully later.

Remove element from c array

I need to remove a specific element from an array, that array is dynamically resized in order to store an unknown number of elements with realloc.
To control the allocated memory and defined elements, I have two other variables:
double *arr = NULL;
int elements = 0;
int allocated = 0;
After some elements being placed in the array, I may need to remove some of them. All texts that I've found says to use memmove and reduce the variables by the number of elements removed.
My doubt is if this method is secure and efficient.
I think this is the most efficient function you can use (memcpy is not an option) regarding secured - you will need to make sure that the parameters are OK, otherwise bad things will happen :)
Using memmove is certainly efficient, and not significantly less secure than iterating over the array. To know how secure the implementation actually is, we'd need to see the code, specifically the memmove call and how return results from realloc are being checked.
If you get your memmove wrong, or don't check any realloc returns, expect a crash.
In principle, assuming you calculate your addresses and lengths correctly, you can use memmove, but note that if you overwrite one or more elements with the elements at higher indexes, and these overwritten elements were structs that contained pointers to allocated memory, you could produce leaks.
IOW, you must first take care of properly disposing the elements you are overwriting before you can use memmove. How you dispose them depends on what they represent. If they are merely structs that contain pointers into other structures, but they don't "own" the allocated memory, nothing happens. If the pointers "own" the memory, it must be deallocated first.
The performance of memmove() and realloc() can be increased by data partitioning. By data partitioning I mean to use multiple array chunk rather than one big array.
Apart from memmove(), I found memory swaping is efficient way. But there is drawback. The array order may be changed in this way.
int remove_element(int*from, int total, int index) {
if(index != (total-1))
from[index] = from[total-1];
return total-1; // return the number of elements
}
Interestingly array is randomly accessible by the index. And removing randomly an element may impact the indexes of other elements as well. If this remove is done in a loop traversal on the array, then the reordering may case unexpected results.
One way to fix that is to use a is_blank mask array and defer removal.
int remove_element(int*from, int total, int*is_valid, int index) {
is_blank[index] = 1;
return total; // **DO NOT DECREASE** the total here
}
It may create a sparse array. But it is also possible to fill it up as new elements are added in the blank positions.
Again, it is possible to make the array compact in the following efficient swap algorithm.
int sparse_to_compact(int*arr, int total, int*is_valid) {
int i = 0;
int last = total - 1;
// trim the last blank elements
for(; last >= 0 && is_blank[last]; last--); // trim blank elements from last
// now we keep swapping the blank with last valid element
for(i=0; i < last; i++) {
if(!is_blank[i])
continue;
arr[i] = arr[last]; // swap blank with the last valid
last--;
for(; last >= 0 && is_blank[last]; last--); // trim blank elements
}
return last+1; // return the compact length of the array
}
Note that the algorithm above uses swap and it changes the element order. May be it is preferred/safe to be used outside of some loop operation on the array. And if the indices of the elements are saved somewhere, they need to be updated/rebuilt as well.

Escaping loop whilst adding to dynamic array - C

Currently my program allows the user to enter 5 integers which are used to create an average number. This is set to five as after the fifth number is entered the loop is broken.
I am trying to implement a method which will let the user continue to add as many numbers as they like to an array from which i can then use to create an average without a limit on the amount of numbers that can be entered.
I have come across a few problems, firstly i cannot create an array which is dyamic as i have no idea how many numbers the user may wish to enter which means i can't give it a definitive size.
Secondly the way my program currently creates the average is by looping through the elements in the array and adding the consecutively to an integer, from which the the average is made. I cannot specify the limit for the loop to continue running if i cannot determine the array.
Hopefully my example explains this better.
#include <stdio.h>
#include <string.h>
void main()
{
int i = 0;
int arrayNum[5];
int temp = 1;
int anotherTemp = 0;
int answer = 0;
printf("Enter as many numbers as you like, when finished enter a negative number\n");
for(i = 0; i < 5; i++)
{
scanf("%d", &temp);
arrayNum[i] = temp;
anotherTemp = anotherTemp + arrayNum[i];
}
answer = anotherTemp / 5;
printf("Average of %d,%d,%d,%d,%d = %d",arrayNum[0],arrayNum[1],arrayNum[2],arrayNum[3],arrayNum[4],answer);
}
Although this may not be the best way to implement it, it does work when the amount of numbers are specified beforehand.
What would be the best way to get around this and allow the user to enter as many number as necessary?
Edit: Although i needed to use an array I have decided that it is not necessary as the solution is much simpler without being restricted to it.
In terms of code simplicity, you might want to check out the realloc() function; you can allocate an initial array of some size, and if the user enters too many numbers call realloc() to get yourself a bigger array and continue from there.
You don't, however, actually need to keep the numbers as you go along at all, at least if you only care about the average:
int input;
int sum = 0;
int count = 0;
int average;
while (1) {
scanf("%d", &input);
if (input < 0) {
break;
}
sum += input;
count++;
}
average = sum / count;
If you're trying to compute an average, then you don't need to save the numbers. Save yourself the work of worrying about the array. Simply accumulate (add) each number to a single total, count each number, then divide when you're done. Two variables are all that you need.
With this method, you aren't in any risk of overflowing your array, so you can use a while loop... while (temp != -1)
Basically you start with a dynamically allocated array with a fixed size, and then allocate a new array that is bigger (say, twice as big as initial size) and copy the stuff from the old array to the new one whenever you run out of space.
For the second part of the problem, keep a counter of the number of items the user entered and use it when averaging.
Something like this.
Use a dynamic array data structure, like Vector in Java (java.util.Vector).
You can implement such a dynamic array yourself easily:
allocate array of size N
as soon as you need more elements than N, allocate a new bigger array (e.g. with size N+10), copy the content of the old array into the new array and set your working reference to the new array and your array size variable N to the new size (e.g. N+10). Free the old array.

Resources