Firstly, I've taken this out of a larger program to try reduce the complexity because I'm only really having a problem with the 'DeleteStudent' function. Therefore, my apologies if this looks messy.
I need the user to be able to delete one of the structures in the array of structures (each structure representing one student) and then the program should remove the wasted empty memory from the array. This is my ultimate goal for this function, but at the moment it displays garbage in the deleted structure, or all the structures.
#include <stdio.h> #include <stdlib.h> #include <conio.h> #include <math.h> #include <ctype.h> #include <string.h> #define TRUE 1 #define FALSE 0 #define NOT_FOUND -1 struct STUDENT* DeleteStudent(struct STUDENT* StudentPointer, int NumStudentsInMemory); int FindStudent(struct STUDENT *StudentPtr, int NumberOfStudents); void ClearArray(struct STUDENT Array[], int ArraySize, int MaxNameLength); struct STUDENT* GetUserToAddStudents(struct STUDENT* StudentPtr, int* StudentsCurrentlyInMemory); struct STUDENT* AddStudent(struct STUDENT *StudentPtr, int* StudentsCurrentlyInMemory); void DisplayAllStudents(struct STUDENT *StudentPtr, int NumberOfStudents); char GetValidatedYesOrNo(); int GetValidatedInteger(int Min, int Max); char* Getvalidatedstring(char StringName[], int Minlen, int Maxlen); void Pause(); struct STUDENT { char Name[10]; int Mark; }; int main() { struct STUDENT *StudentPointer = NULL; int NumStudentsInMemory = 0; StudentPointer = GetUserToAddStudents(StudentPointer, &NumStudentsInMemory); DeleteStudent(StudentPointer, NumStudentsInMemory); DisplayAllStudents(StudentPointer, NumStudentsInMemory); Pause(); return 0; } struct STUDENT* DeleteStudent(struct STUDENT* StudentPointer, int NumStudentsInMemory) { int a = 0, Placeholder = 0; struct STUDENT *StudentPtr_temp = NULL; a = FindStudent(StudentPointer, NumStudentsInMemory); for(Placeholder = a; Placeholder < NumStudentsInMemory; Placeholder++) { StudentPointer[Placeholder] = StudentPointer[(Placeholder + 1)]; } StudentPtr_temp = (struct STUDENT*)malloc(sizeof(struct STUDENT) * (NumStudentsInMemory - 1) ); ClearArray(StudentPtr_temp, (NumStudentsInMemory - 1), 10); for(Placeholder = 0; Placeholder < NumStudentsInMemory; Placeholder++) { if(Placeholder != a) { StudentPtr_temp[Placeholder] = StudentPointer[Placeholder]; } } if (StudentPointer != NULL) { free(StudentPointer); } StudentPointer = StudentPtr_temp; StudentPtr_temp = NULL; return StudentPointer; } int FindStudent(struct STUDENT *StudentPtr, int NumberOfStudents) { int i = 0, Index = NOT_FOUND; char Name[11]; printf("\nEnter student's name to search for: "); Getvalidatedstring(Name, 1, 10); for(i = 0; i < NumberOfStudents; i++) { /* Check each book against search-string */ if(stricmp(StudentPtr[i].Name, Name) == 0) { Index = i; break; } } return(Index); } void ClearArray(struct STUDENT Array[], int ArraySize, int MaxNameLength) { int Index = 0; for(Index = 0; Index < ArraySize; Index ++) { memset(Array[Index].Name, ' ', MaxNameLength); strcpy(Array[Index].Name, ""); Array[Index].Mark = 0; } } struct STUDENT* GetUserToAddStudents(struct STUDENT* StudentPtr, int* StudentsCurrentlyInMemory) { char Continue = 'Y'; printf("\nAdd a student\n"); do { StudentPtr = AddStudent(StudentPtr, StudentsCurrentlyInMemory); (*StudentsCurrentlyInMemory)++; printf("\nDo you want to add another student? (Y/N)"); Continue = GetValidatedYesOrNo(); }while(toupper(Continue) == 'Y'); return StudentPtr; } struct STUDENT* AddStudent(struct STUDENT *StudentPtr, int* StudentsCurrentlyInMemory) { int Count = 0; struct STUDENT *StudentPtr_temp = NULL; //allocate enough memory to make a copy of student records currently in memory plus space for 1 extra to be added StudentPtr_temp = (struct STUDENT*)malloc(sizeof(struct STUDENT) * (*StudentsCurrentlyInMemory + 1) ); ClearArray(StudentPtr_temp, *StudentsCurrentlyInMemory + 1, 10);//clear any garbage in newly allocated memory //copy student records currently in memory into newly allocated memory for(Count = 0; Count < *StudentsCurrentlyInMemory; Count++) { StudentPtr_temp[Count] = StudentPtr[Count]; } //get user to enter values for new student record which will be added to the last element of the newly allocated memory printf(" Student's Name: "); Getvalidatedstring(StudentPtr_temp[Count].Name, 1, 10); printf(" Student's Mark: "); StudentPtr_temp[Count].Mark = GetValidatedInteger(0, 100); if (StudentPtr != NULL) { free(StudentPtr);//free up redundant memory - *very important* - prevents memory leaks!! } StudentPtr = StudentPtr_temp;//now make StudentPtr point to the newly created memory StudentPtr_temp = NULL;//set StudentPtr_temp to NULL ready for the next time return StudentPtr; } void DisplayAllStudents(struct STUDENT *StudentPtr, int NumberOfStudents) { int Count = 0; printf("\n\nAll records currently in memory\n---------------------------\n%10s %s\n", "Name", "Mark"); for(Count = 0; Count < NumberOfStudents; Count++) { printf("%10s %d\n", StudentPtr[Count].Name, StudentPtr[Count].Mark); } } char GetValidatedYesOrNo() { int ItemRead = FALSE; char Input = '\0'; int Valid = FALSE; /* MUST be initialised to FALSE */ do { /* Read. NB scanf() returns the number of items successfully read */ ItemRead = scanf("%c", &Input); fflush(stdin); Input = toupper(Input); if(ItemRead == FALSE) { printf("Sorry, something went wrong with scanf. Please try again: "); } /* Validate - 'Y' or 'N'? */ else if( (Input != 'Y') && (Input != 'N') ) { printf("Invalid - must be either 'Y' or 'N'! Please try again: "); } else { Valid = TRUE; } } while(Valid == FALSE); return(Input); } /* Gets user-inputted integer value. Validated for data type & value (Min->Max). */ int GetValidatedInteger(int Min, int Max) { int ItemRead = FALSE; double Input = 0; /* NB Input read into a FLOAT */ int Valid = FALSE; /* MUST be initialised to FALSE */ do { /* Read. NB scanf() returns the number of items successfully read */ ItemRead = scanf("%lf", &Input); fflush(stdin); /*Validate - Non-numeric? (In which case scanf() will not have read in anything)*/ if(ItemRead == FALSE) { printf("Invalid - can only be a number (not a letter, a string or a symbol)"); } /* Validate - Not whole number? */ else if(Input != (int)Input) /* NB (int)Input truncates a float value */ { printf("Invalid - must be whole number! Please try again (%d-%d): ", Min, Max); } /* Validate - Invalid value? (ie Not in range Min->Max) */ else if((Input < Min) || (Input > Max)) { printf("Invalid - out-of-range! Must be a number between %d & %d! Please try again: ", Min, Max); } else { Valid = TRUE; } } while(Valid == FALSE); return((int)Input); /* NB Cast (store) as int before returning */ } /* Note: Validated, user-inputted array passed back twice: 1. as reference parameter, and 2. as a return value (Note “pointer” syntax "char*"). Reason - To offer calling code maximum flexibility of use. */ char* Getvalidatedstring(char StringName[], int Minlen, int Maxlen) { char Input[200]; /* Very big to avoid array over-run. */ do { gets(Input); if((strlen(Input) < Minlen) || (strlen(Input) > Maxlen)) { printf("Invalid! Please try again (Length %d-%d): ", Minlen, Maxlen); } } while((strlen(Input) < Minlen) || (strlen(Input) > Maxlen)); /* Using string handling library function (strcpy()) */ strcpy(StringName, Input);/* 1. Populate reference parameter */ printf("%s\n", StringName); return(StringName);/* 2. Return value */ } void Pause() { printf("\n\nPress enter to exit.\n"); getch(); }