Hello guys, just wondering why my program crashes when I try to delete a struct from my array. I'm trying to code so that the user searches for a student via a student ID, then opt to delete the searched student's record. I thought I got it right and the search works fine, but it crashes when I opt to delete the student's record! I know it's due to the actual deleting part in my code. Here's my whole code:

#include <iostream>
#include <iomanip>
#include <string>

using namespace std;

void clrscr()
{
  system("cls");
}

void pause()
{
  system("echo.");system("echo.");system("pause");
}

void displayMenu(string msg)
{
  clrscr();
  cout << msg << "\n\nMAIN MENU\n"
"\n0. Exit"
"\n1. Search for a student"
"\n2. List students enrolled in a course"
"\n3. List students eligible to graduate"
"\n4. List all students"
"\n5. Update a student record"
"\n6. Add a student record"
"\n7. Delete a student record"
"\n\nYour choice is ->";
};

const int MAXRECORD = 500;
struct stdRecord
{
string studentID;
string studentName;
int courseCode;
int creditPoint;
};

const int NUMRECS = 3;

int main()
{
  int option, i;
  string word, stdIDInput, msg="Please type in the number of the corresponding \ntask you wish to perform then press enter.";
  char choice;
  
  stdRecord stdRec[NUMRECS]={{"15000000","Joshua Andrew Smith", 3506, 240},
                               {"16666666", "Jack Williams", 3506, 180},
                               {"17000010", "Lily Jones", 3639, 110}};
  do
  {
    displayMenu(msg);
    cin.clear();
    if(!(cin >> option))
    {
      if(!cin.eof())
      {
        cin.clear();
        cin >> word;
      }
     continue;
    }
   
    switch(option)
    {
    case 1: // this searches for a student via their studentID
        do
        {
        cout << "Please type in the student ID number\nof the student you want to search,\nthen press enter.\n";
        cin >> stdIDInput;
        cout << "\nStudent ID  Student Name         Course Code  Credit Points\n\n";
        cout << setiosflags(ios::left);
        bool found = false;
        for(i = 0; i < NUMRECS; i++)
        {
            if(stdIDInput == stdRec[i].studentID)
            {
                found = true;
                cout << setw(12) << stdRec[i].studentID
                     << setw(21) << stdRec[i].studentName
                     << setw(13) << stdRec[i].courseCode
                     << setw(5)  << stdRec[i].creditPoint << endl;
            }
        }
        if(!found)
        {
            cout << "Not Found.\n";
        }
        cout << "Would you like to search for a student again? Y or N.\n";
        cin >> choice;
        }while(choice != 'N');
        pause ();
        break;
    case 2: // this searches for students enrolled in a course, searches via course code
        int courseCodeIn;
        do
        {
        cout << "Please type in a valid course code (the SCM offers courses 3506, 3633, 3634 \nand 3639) to display students in that course, then press enter.\n"
             << "Note: there may or may not be students enrolled ina a course,\nin the case of the latter, 'Not Found' will be displayed.";
        cin >> courseCodeIn;
        cout << "\nStudent ID  Student Name         Course Code  Credit Points\n\n";
        cout << setiosflags(ios::left);
        bool found = false;
        for(i = 0; i < NUMRECS; i++)
        {
            if(courseCodeIn == stdRec[i].courseCode)
            {
                found = true;
                cout << setw(12) << stdRec[i].studentID
                     << setw(21) << stdRec[i].studentName
                     << setw(13) << stdRec[i].courseCode
                     << setw(5)  << stdRec[i].creditPoint << endl;
            }
        }
        if(!found)
        {
            cout << "Not Found.\n";
        }
        cout << "Would you like to search via a course code again? Y or N.\n";
        cin >> choice;
        }while(choice != 'N');
        pause ();
        break;
    case 3: // lists students eligible to graduate
        cout << "\nStudent ID  Student Name         Course Code  Credit Points\n\n";
        cout << setiosflags(ios::left);
        for(i = 0; i < NUMRECS; i++)
        {
            if(stdRec[i].creditPoint == 240)
            {
                cout << setw(12) << stdRec[i].studentID
                     << setw(21) << stdRec[i].studentName
                     << setw(13) << stdRec[i].courseCode
                     << setw(5)  << stdRec[i].creditPoint << endl;
            }
        }
        pause ();
        break;
    case 4: // lists all students
        cout << "\nStudent ID  Student Name         Course Code  Credit Points\n\n";
        cout << setiosflags(ios::left);
        for (i = 0; i < NUMRECS; i++)
            cout << setw(12) << stdRec[i].studentID
                 << setw(21) << stdRec[i].studentName
                 << setw(13) << stdRec[i].courseCode
                 << setw(5)  << stdRec[i].creditPoint << endl;             
        pause ();
        break;
    case 5: // allows the user to alter a student's course code and/or credit points
        int courseCodeUpdate, creditPointsUpdate;
        char decision;
        do
        {
        cout << "Please type in the student ID number\nof the student you want to search,\nthen press enter.\n";
        cin >> stdIDInput;
        cout << "\nStudent ID  Student Name         Course Code  Credit Points\n\n";
        cout << setiosflags(ios::left);
        bool found = false;
        for(i = 0; i < NUMRECS; i++)
        {
            if(stdIDInput == stdRec[i].studentID)
            {
                found = true;
                cout << setw(12) << stdRec[i].studentID
                     << setw(21) << stdRec[i].studentName
                     << setw(13) << stdRec[i].courseCode
                     << setw(5)  << stdRec[i].creditPoint << endl;
            }
        }
        if(!found)
        {
            cout << "Not Found.\n";
        }
        if(found == true)
        {
            do
            {
                cout << "Please type in the number\n of the corresponding choice below, then press enter.\n\n"
                     << "Z. Exit\nA. Update course code\nB. Update credit points\nC. Update both course code and credit points\n";
                cin >> decision;
                if (decision == 'A')
                {
                    cout << "Please type in the updated course code.\n";
                    cin >> courseCodeUpdate;
                    stdRec[i].courseCode = courseCodeUpdate;
                    cout << "The student's course code has now been updated to "
                         << stdRec[i].courseCode << endl;
                }
                else if (decision == 'B')
                {
                    cout << "Please type in the updated credit points.\n";
                    cin >> creditPointsUpdate;
                    stdRec[i].creditPoint = creditPointsUpdate;
                    cout << "The student's credit points have now been updated to "
                         << stdRec[i].creditPoint << endl;
                }
                else if (decision == 'C')
                {
                    cout << "Please type in the updated course code.\n";
                    cin >> courseCodeUpdate;
                    stdRec[i].courseCode = courseCodeUpdate;
                    cout << "The student's course code has now been updated to "
                         << stdRec[i].courseCode
                         << "\nNow please type in the updated credit points.\n";
                    cin >> creditPointsUpdate;
                    stdRec[i].creditPoint = creditPointsUpdate;
                    cout << "The student's credit points have now been updated to "
                         << stdRec[i].creditPoint << endl;
                }
                else
                {
                    cout << "No valid character from options Z, A, B, or C have been chosen.";
                }
            } while (decision != 'Z');
        }
    cout << "\nWould you like to search for a student again? Y or N.\n";
    cin >> choice;
    } while (choice != 'N');
    pause ();
    break;
// case 6 is still in the works and chucks up errors, so I've removed it temporarily
    case 7: // this allows the user to delete a student's record
        char decision2, choice2;
        int studentCount;
        studentCount = NUMRECS;
        do
        {
            cout << "Please type in the student ID number\nof the student you want to search,\nthen press enter.\n";
            cin >> stdIDInput;
            cout << "\nStudent ID  Student Name         Course Code  Credit Points\n\n";
            cout << setiosflags(ios::left);
            bool found = false;
            for(i = 0; i < NUMRECS; i++)
            {
                if(stdIDInput == stdRec[i].studentID)
                {
                    found = true;
                    cout << setw(12) << stdRec[i].studentID
                         << setw(21) << stdRec[i].studentName
                         << setw(13) << stdRec[i].courseCode
                         << setw(5)  << stdRec[i].creditPoint << endl;
                }
            }
            if(!found)
            {
                cout << "Not Found.\n";
            }
            if(found == true)
            {
                do
                {
                    cout << "Would you like to delete this student's record? Y/N.\n";
                    cin >> decision2; // ***HERE! It crashes just after the decision is input and I'm pretty sure my loop for overwriting the deleting record is wrong so...
                    stdRec[i].studentID = stdRec[i+1].studentID;
                    stdRec[i].studentName = stdRec[i+1].studentName;
                    stdRec[i].courseCode = stdRec[i+1].courseCode;
                    stdRec[i].creditPoint = stdRec[i+1].creditPoint;
                } while (decision2 != 'N');
            }
            cout << "Would you like to search and/or delete another student's record?.\n";
            cin >> choice2;
        } while (choice2 != 'N');
        pause ();
        break;
    default:
      cout << "No options from choices one to seven have been typed.";
      pause ();
      break;
    }
    
  } while (option!=0);
  return 0;
}

Just case 7 (so you don't have to worry about the rest of the code getting in the way):

case 7:
        char decision2, choice2;
        int studentCount;
        studentCount = NUMRECS;
        do
        {
            cout << "Please type in the student ID number\nof the student you want to search,\nthen press enter.\n";
            cin >> stdIDInput;
            cout << "\nStudent ID  Student Name         Course Code  Credit Points\n\n";
            cout << setiosflags(ios::left);
            bool found = false;
            for(i = 0; i < NUMRECS; i++)
            {
                if(stdIDInput == stdRec[i].studentID)
                {
                    found = true;
                    cout << setw(12) << stdRec[i].studentID
                         << setw(21) << stdRec[i].studentName
                         << setw(13) << stdRec[i].courseCode
                         << setw(5)  << stdRec[i].creditPoint << endl;
                }
            }
            if(!found)
            {
                cout << "Not Found.\n";
            }
            if(found == true)
            {
                do
                {
                    cout << "Would you like to delete this student's record? Y/N.\n";
                    cin >> decision2;            
                    stdRec[i].studentID = stdRec[i+1].studentID;
                    stdRec[i].studentName = stdRec[i+1].studentName;
                    stdRec[i].courseCode = stdRec[i+1].courseCode;
                    stdRec[i].creditPoint = stdRec[i+1].creditPoint;
                } while (decision2 != 'N');
            }
            cout << "Would you like to search and/or delete another student's record?.\n";
            cin >> choice2;
        } while (choice2 != 'N');
        pause ();
        break;

Any direction as to how I can change my loop/s would be MUCH appreciated! Please and thank-you!

Your deletion mechanism essentially writes over location i with location i+1. What happens when you get to the highest member of your array?

stdRec.studentID = stdRec[i+1].studentID;

If i is the last member of the array, you are then trying to read i+1 - this is not your memory to read. You should stop at location i-1, copy location i over it, and then just set location i to whatever you use for a blank record.

Your deletion mechanism essentially writes over location i with location i+1. What happens when you get to the highest member of your array?

stdRec.studentID = stdRec[i+1].studentID;

If i is the last member of the array, you are then trying to read i+1 - this is not your memory to read. You should stop at location i-1, copy location i over it, and then just set location i to whatever you use for a blank record.

erm, well the lecturer said that you're supposed to shift all the above structs one down so as to overwrite the one you want to delete, then when you get to the end you get a duplicate of the last one so you length-- so you don't process the duplicate. So I don't think my do-while loop is right... I don't know how to keep shifting the structs down until the end though...

So I don't think my do-while loop is right... I don't know how to keep shifting the structs down until the end though...

The idea is to pretend the record being deleted is a hole in the array and fill it in with everything after it:

// Find the record and store its index in i...

// Fill in the "hole" starting at i to delete stdRec[i]
for (int x = i; x < n - 1; x++)
    stdRec[x] = stdRec[x + 1];

// Decrement the length of the array to reflect the deletion
--n;
commented: awesome! +1

The idea is to pretend the record being deleted is a hole in the array and fill it in with everything after it:

// Find the record and store its index in i...

// Fill in the "hole" starting at i to delete stdRec[i]
for (int x = i; x < n - 1; x++)
    stdRec[x] = stdRec[x + 1];

// Decrement the length of the array to reflect the deletion
--n;

GAH! I totally understand now! The shifting can be linear like the search! Thank-you so much for this! I can't believe I looked over the for loop for this! Thank-you again!

GAH! I totally understand now! The shifting can be linear like the search! Thank-you so much for this! I can't believe I looked over the for loop for this! Thank-you again!

erm... I tried to implement something to what you said but it still crashes. I know it still has something to do with my loop and I switched some statements around, but it still crashes! What do you think could be making it crash? It's just the loop that makes it crash though:

do
            {
                for(x = i; x <= studentCount; x++)
                {
                    if (found == true)
                    {
                        cout << "Would you like to delete this student's record? Y/N.\n";
                        cin >> decision2;
                        stdRec[x] = stdRec[x+1];
                    }
                }
                studentCount--;
            } while (decision2 != 'N');

Any suggestions would be greatly appreciated! Please and thank-you!

Ignoring the array overflow for a moment, you're trying to do too much in a single loop. Use two loops to simplify as in my previous example:

cout << "Please type in the student ID number\n"
     << "of the student you want to search,\n"
     << "then press enter: ";
cin >> stdIDInput;

// Find the record *first*
for (i = 0; i < studentCount; i++) {
    if (stdIDInput == stdRec[i].studentID) {
        cout << "\nStudent ID  Student Name         Course Code  Credit Points\n\n";
        cout << setw(12) << stdRec[i].studentID
             << setw(21) << stdRec[i].studentName
             << setw(13) << stdRec[i].courseCode
             << setw(5)  << stdRec[i].creditPoint << '\n';
        break;
    }
}

if (i < studentCount) {
    // Now give the user the option to delete
    cout << "Would you like to delete this student's record? Y/N: ");
    cin >> decision2;

    if (decision2 == 'Y') {
        // Finally, delete the record you found if the user says yes
        // Notice how the loop stops at (studentCount - 1), that's important
        while (i < studentCount - 1)
            stdRec[i] = stdRec[i + 1];
    }
}

Since you failed to fully understand my previous post, I've given you the logic for finding and deleting a single record in it's entirety. But before you run off and use that code, first walk through the code you wrote with a test case, line by line. It makes no sense at all if you think about each step as it's executed, and it's important that you see the problem before mindlessly using code that works.

Ignoring the array overflow for a moment, you're trying to do too much in a single loop. Use two loops to simplify as in my previous example:

cout << "Please type in the student ID number\n"
     << "of the student you want to search,\n"
     << "then press enter: ";
cin >> stdIDInput;

// Find the record *first*
for (i = 0; i < studentCount; i++) {
    if (stdIDInput == stdRec[i].studentID) {
        cout << "\nStudent ID  Student Name         Course Code  Credit Points\n\n";
        cout << setw(12) << stdRec[i].studentID
             << setw(21) << stdRec[i].studentName
             << setw(13) << stdRec[i].courseCode
             << setw(5)  << stdRec[i].creditPoint << '\n';
        break;
    }
}

if (i < studentCount) {
    // Now give the user the option to delete
    cout << "Would you like to delete this student's record? Y/N: ");
    cin >> decision2;

    if (decision2 == 'Y') {
        // Finally, delete the record you found if the user says yes
        // Notice how the loop stops at (studentCount - 1), that's important
        while (i < studentCount - 1)
            stdRec[i] = stdRec[i + 1];
    }
}

Since you failed to fully understand my previous post, I've given you the logic for finding and deleting a single record in it's entirety. But before you run off and use that code, first walk through the code you wrote with a test case, line by line. It makes no sense at all if you think about each step as it's executed, and it's important that you see the problem before mindlessly using code that works.

Ooooh, so I was trying to do too much in too little loops! Okay, so why do you ignore array overflow if you're deleting from it? And why is the studentCount-1 important to stop at? Sorry for asking so many questions by the way... you're advice is always awesome!

Ooooh, so I was trying to do too much in too little loops!

For the record, it's possible to do it all with one loop, but it's best to keep things simple whenever you can. :)

Okay, so why do you ignore array overflow if you're deleting from it?

You don't. I simply refrained from bringing up the fact that your loop was begging for an overflow. Here's how you can tell. Following is a reduced example of the loop you posted:

for(x = i; x <= studentCount; x++)
{
    stdRec[x] = stdRec[x+1];
}

Notice how x controls the loop, but x is also used to index stdRec inside the loop body. If stdRec has stduentCount items then the smallest value i can have is 0, and the largest value x can have is studentCount - 1 . This immediately follows the fact that an array is 0-based and has the range of [0,N).

So looking at that code, the loop is inherently wrong because stdRec[studentCount] is accessed when it should not be. Further, because the loop body is accessing stdRec[x + 1] , the loop should stop at studentCount - 1 because if it stops at studentCount then you'll still be performing an out of bounds access at the end due to that one item look-ahead. The corrected loop is thus:

for(x = i; x < studentCount - 1; x++)
{
    stdRec[x] = stdRec[x+1];
}

Long story short, if you're using a loop counter to access an array inside the loop, the counter must never exceed the smallest or largest allowable index for the array. If you add to or subtract from the counter during an array access, that must also be taken into account when setting up the loop condition.

For the record, it's possible to do it all with one loop, but it's best to keep things simple whenever you can. :)


You don't. I simply refrained from bringing up the fact that your loop was begging for an overflow. Here's how you can tell. Following is a reduced example of the loop you posted:

for(x = i; x <= studentCount; x++)
{
    stdRec[x] = stdRec[x+1];
}

Notice how x controls the loop, but x is also used to index stdRec inside the loop body. If stdRec has stduentCount items then the smallest value i can have is 0, and the largest value x can have is studentCount - 1 . This immediately follows the fact that an array is 0-based and has the range of [0,N).

So looking at that code, the loop is inherently wrong because stdRec[studentCount] is accessed when it should not be. Further, because the loop body is accessing stdRec[x + 1] , the loop should stop at studentCount - 1 because if it stops at studentCount then you'll still be performing an out of bounds access at the end due to that one item look-ahead. The corrected loop is thus:

for(x = i; x < studentCount - 1; x++)
{
    stdRec[x] = stdRec[x+1];
}

Long story short, if you're using a loop counter to access an array inside the loop, the counter must never exceed the smallest or largest allowable index for the array. If you add to or subtract from the counter during an array access, that must also be taken into account when setting up the loop condition.

Ohhhhh, so if I did it that way, there's a bigger possibility that information can "run off" the end of the array? Also, I thought this code would work, but it still doesn't! The search section works fine, it's just when it doesn't find a match it just stops! What I'd like is that if a match to a student ID is not found, the user has the option to add new student information to the record. Any ideas? Relevant code:

case 6://add a student record
        {
        int first = 0;
        int last = NUMRECS;
        int mid = (first + last)/2;
        int studentCount, newStdCourseCode, newStdCreditPoint;
        studentCount = NUMRECS;
        char decision3, option2;
        string newStdName;
        do
        {
        cout << "Please type in the student ID number\nof the student you want to input,\nthen press enter.\n";
        cin >> stdIDInput;
        bool found = false;
        while (first <= last && !found)//search for a student ID match
        {
            if (stdRec[mid].studentID == stdIDInput)
            {
                found = true;
                cout << "This student ID already exists in the system.\n";
                cout << "\nStudent ID  Student Name         Course Code  Credit Points\n\n";
                cout << setiosflags(ios::left);
                cout << setw(12) << stdRec[mid].studentID
                     << setw(21) << stdRec[mid].studentName
                     << setw(13) << stdRec[mid].courseCode
                     << setw(5)  << stdRec[mid].creditPoint << endl;
            }
            else if (stdRec[mid].studentID > stdIDInput)
            {
                last = mid -1;
            }
            else
            {
                first = mid +1;
            }
        }
        if(!found)//***HERE I don't know why this doesn't work! Any suggestions???
        {
            cout << "Would you like to add the student to the records? Y/N\n";
            cin >> decision3;
            if(decision3 == 'Y')
            {
                last = NUMRECS;
                studentCount++;
                stdRec[last+1].studentID = stdIDInput;
                cout << "Please input the new student's name.\n";
                cin >> newStdName;
                stdRec[last+1].studentName = newStdName;
                cout << "Please input the new student's course code.\n";
                cin >> newStdCourseCode;
                stdRec[last+1].courseCode = newStdCourseCode;
                cout << "Please input the new student's credit points.\n";
                cin >> newStdCreditPoint;
                stdRec[last+1].creditPoint = newStdCreditPoint;
                cout << "The student's information has now been added to the records.\n";
                cout << "\nStudent ID  Student Name         Course Code  Credit Points\n\n";
                cout << setiosflags(ios::left);
                cout << setw(12) << stdRec[last+1].studentID
                     << setw(21) << stdRec[last+1].studentName
                     << setw(13) << stdRec[last+1].courseCode
                     << setw(5)  << stdRec[last+1].creditPoint << endl;
             }
        }
        cout << "Would you like to search and/or add another student record? Y/N\n";
        cin >> option2;
        if(option2 == 'N')
        {
            break;
        }
        }while (option2 == 'Y');
        pause ();
        break;
        }

Can you post the code of case 7: Deleting from array of struct? I mean the refine and executable ones.
Thanks

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.