Trying to delete pointers triggers breakpoints - c++

The purpose of the program that I'm working on is creating a class to "improve" the default integer array data type by simulating a dynamic array of pointers. I keep running into errors when trying to delete pointers and arrays of pointers where it says "Windows has triggered a breakpoint in project4.exe.
This may be due to a corruption of the heap, which indicates a bug in project4.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while project4.exe has focus.
The output window may have more diagnostic information."
class Array
{
private:
int length;
int* data;
public:
Array();
Array(const Array &cpy);
~Array();
bool addint(int toadd);
bool deletelast();
int getlength();
friend ostream& operator<<(ostream &out, const Array &n);
};
ostream& operator<<(ostream &out, const Array &n);
Array::Array()
{
length = -1;
data = NULL;
}
Array::Array(const Array &cpy)
{
length = cpy.length; //value of length is copied
if (length < 0)
data = NULL;
else
{
data = new int [length];
for (int i=0; i<=length; i++)
data[i] = cpy.data[i];
}
}
Array::~Array()
{
if (length != 0)
delete [] data;
else
delete data;
data = NULL;
}
bool Array::addint(int toadd)
{
length ++;
int* point = new int[length];
for (int i=0; i < length; i++)
point[i] = data[i];
point[length] = toadd;
if (length != 0)
delete [] data;
data = point;
point = NULL;
return true;
}
bool Array::deletelast()
{
int* temppoint;
if (length > 0)
temppoint = new int [length-1];
else
temppoint = new int[0];
for (int i=0; i<length; i++)
temppoint[i] = data[i];
if (length == 0)
temppoint[0] = 0;
length --;
delete [] data;
data = temppoint;
temppoint = NULL;
return true;
}
void menu(Array var)
{
int selection=0,
input;
bool success;
Array* arrcpy;
while (selection != 3)
{
if (var.getlength() == -1)
{
cout << "What would you like to demonstrate?" << endl << "1) Add an integer " << endl
<< "2) Exit" << endl << "Enter your selection: ";
cin >> selection;
if (selection == 2)
selection = 4;
}
else
{
cout << endl << "Now what would you like to demonstrate?" << endl << "1) Add an integer " << endl
<< "2) Delete the last entered integer" << endl << "3) Copy constructor" << endl << "4) Exit" << endl << "Enter your selection: ";
cin >> selection;
}
if (selection==1)
{
cout << endl << "The length of the array before adding a new value is: " << var.getlength() + 1 << endl;
cout << "Please enter the integer that you wish to add: ";
cin >> input;
success = var.addint(input);
if (success)
cout << endl << "The data input was a success!" << endl << "The length of the array is now: "
<< var.getlength() + 1 << endl << "The new value of the array is: " << var << endl;
else
cout << endl << "The input failed" << endl;
}
if (selection == 2)
{
cout << endl << "The lenght of the array before the deletion is: " << var.getlength() + 1 << endl
<< "and the value held in the array is: " << var << endl;
success = var.deletelast();
if (success)
cout << endl << "The data deletion was a success!" << endl << "The length of the array is now: "
<< var.getlength() + 1 << endl << "The new value of the array is: " << var << endl;
else
cout << endl << "The deletion failed" << endl;
}
if (selection == 3)
{
cout << endl << "The lenght of the array being copied is: " << var.getlength() + 1 << endl
<< "and the value held in the array is: " << var << endl;
arrcpy=new Array(var);
cout << endl << "The length of the copied array is: " << arrcpy->getlength() +1 << endl
<< "and the value contained in the array is: " << *arrcpy;
delete arrcpy;
}
}
}
This is all of the relevant source code that I have in terms of the issue that I'm having. It's coming up that every instance of the delete operator and the delete [] operator has resulted in this breakpoint error and I'm not sure what I'm doing wrong.
Edit: Rewrote the code to have the value of length default to 0 instead of -1 and everything works now!

I believe the for (int i=0; i<=length; i++) in the copy constructor should contain i<length (less than, not less than or equal to). That's one clear problem.
Also you're passing the bound in the addint() method. The last element in an array is at index [length-1].

int* point = new int[length];
Since your length starts at -1, the first call of this line would be to do new int[0]. Could be the problem.. If you insist on not fixing the semantics of length, you want length+1 here
Unrelated point, you should look at how std::vector does it, instead of reallocating every addition, you should try overallocating and only reallocating if the space is filled.

I understand this is an old thread and I'll admit I haven't read all the comment but on the topic of why it seems to work when lenght is changed to 0 I believe it could be due to a nullptr being given to an array being made of an invalid size and later, trying to delete such pointer would result in the breakpoint.

Related

C++ - How to sort data in a linked list and display it?

I'm currently working on a program that has a linked list. My program need to have a function that can sort all the data based on its months and then display all of the data but I can't find a good example for me to refer because in my case I need to search the string expireDate; which is input this way dd/mm/yyyy which means that I need to take its subtring by using std::string str2 = temp->expireDate.substr(3,2); in order for me to get the month and then convert the substring into integer using int month;. Please take a look at my code, it is sorted but it doesn't display anything when I run it, I think there must be a very little mistake. I've already figured out my mistakes, it's just a silly mistake actually. There's no error on this code tho.
carInsurance* remove_next(carInsurance* prev)// pass NULL if start_ptr is the Node to be removed
{
if(prev)
{
if( prev->next )// ensure prev isn't pointing to the last Node in the list
{
carInsurance* temp = prev->next;// temp will be removed
prev->next = temp->next;// link across temp
return temp;
}
}
else if(start_ptr)// ensure list not empty
{
carInsurance* temp = start_ptr;// start_ptr will be removed
start_ptr = start_ptr->next;
return temp;
}
return NULL;// if called on empty list, or if prev->next is NULL
}
void carInsurance::sortMonth(int *x) // sort by month in ascending order
{
carInsurance *start_ptr2 = NULL;// head of sorted list
float price, addPrice;
while(start_ptr)// repeat until no nodes left in unsorted list
{
// pointers for iterating through the unsorted list
carInsurance *prev = NULL;// always previous to the current node considered (below)
carInsurance *curr = start_ptr;// start at beginning of list
carInsurance *prevMax = NULL;// pointer to node before the node with the highest age
int max = start_ptr->month;// 1st node holds max age to start
while(curr)// iterate through the list
{
if(curr->month > max )// new highest age found
{
max = curr->month;// save new max age
prevMax = prev;// save pointer to node before the max
}
prev = curr;// advance iterators
curr = curr->next;
}
// Node with the highest age found this pass through the list.
carInsurance *xferNode = remove_next(prevMax);// obtain node to be moved into sorted list
if( xferNode )// check that it's not NULL
{
xferNode->next = start_ptr2;// add to beginning of sorted list
start_ptr2 = xferNode;
}
}
start_ptr = start_ptr2;// list now sorted. Reassign start_ptr to point to it.
while(temp != NULL)// Display details for what temp points to
{
cout << "\n___Customer Information___\n" << endl;
cout << "\nName : " << temp->name << endl;
cout << "IC: "<< temp->iCno << endl;
cout << "Date of Birth: " << temp->dob << endl;
cout << "Nationality: " << temp->nationality << endl;
cout << "Address: " << temp->address << endl;
cout << "Mobile Number: " << temp->phoneNo << endl;
cout << "Email: " << temp->email << endl;
cout << "Occupation: " << temp->occupation << endl;
cout << "\n_____Car Information_____\n" << endl;
cout << "Car Plate Number: " << temp->carNo << endl;
cout << "Insurance Expire Date: " << temp->expireDate << endl;
cout << "Usage of Car Model/Make: " << temp->carUsage << endl;
cout << "Manufacturing Date: " << temp->manufacturingDate << endl;
cout << "\n___Insurance Information___\n" << endl;
cout << "Insurance Package:" << endl;
if(temp->package == 1)
{
cout << "\nPackage A (Comprehensive Cover)" << endl;
cout << "\t-Covers losses or damages to your car due to accident, fire and theft " << endl;
cout << "\t-Covers Third Party death and bodily injuries " << endl;
cout << "\t-Covers Third Party property losses or damages " << endl;
price = 1000;
}
else if (temp->package == 2)
{
cout << "\nPackage B (Third Party Cover)" << endl;
cout << "\t-Covers Third Party death and bodily injuries" << endl;
cout << "\t-Covers Third Party property losses or damages" << endl;
price = 1500;
}
else if (temp->package == 3)
{
cout << "\nPackage C (Third Party, Fire & Theft Cover)" << endl;
cout << "\t-Covers losses or damages to your car due to fire or theft" << endl;
cout << "\t-Covers Third Party death and bodily injuries" << endl;
cout << "\t-Covers Third Party property losses or damages" << endl;
price = 900;
}
else
cout << "No package available" << endl;
if(temp->additional == 1)
{
cout << "\nAdditional package: "<< endl;
if (temp->option==1){
cout << "Road tax renewal" << endl;
addPrice = 50;
}
else if (temp->option==2){
cout << "Name of second driver" << endl;
addPrice = 0;
}
else if (temp->option==3){
cout << "Windscreen coverage" << endl;
addPrice = 20;
}
else if (temp->option==4){
cout << "Rental reimbursement" << endl;
addPrice = 50;
}
else if (temp->option==5){
cout << "Roadside assistance or towing insurance" << endl;
addPrice = 80;
}
else if (temp->option==6){
cout << "Full glass coverage" << endl;
addPrice = 70;
}
else
cout << "Not availabe"<< endl;
}
else{
cout << "No additional package" << endl;
price = 0;
}
temp->insuranceAmount = price + addPrice;
cout << "Amount to be insured: RM" << temp->insuranceAmount << endl;
//temp = temp->next;
}//End of While Loop
}//End of sortMonth
Are you allowed to use all of C++ or are you really only allowed to use C with std::string and std::cout?
If you can use C++ here is how I would do it (still using a linked list since you specified that in your question - std::vector and std::sort would be more performant if you don't need to use a linked list):
#include <iostream>
#include <sstream>
#include <iterator>
#include <locale>
#include <vector>
#include <list>
// define a facet that adds slash to the list of delimiters
class slash_is_space : public std::ctype<char> {
public:
mask const *get_table() {
static std::vector<std::ctype<char>::mask>
table(classic_table(), classic_table()+table_size);
table['/'] = (mask)space;
return &table[0];
}
slash_is_space(size_t refs=0) : std::ctype<char>(get_table(), false, refs) { }
};
// define a class (with public members) that adds splits the date using the new facet
struct extract_date
{
int day, month, year;
extract_date(std::string date) {
std::stringstream ss(date);
ss.imbue(std::locale(std::locale(), new slash_is_space));
ss >> day >> month >> year;
}
};
// your struct containing the date that will be used for sorting
struct carInsurance
{
std::string carNo;
std::string expireDate;
std::string carUsage;
std::string manufacturingDate;
};
// a function that can print your struct
std::ostream& operator << ( std::ostream& out, const carInsurance& rhs )
{
out << rhs.carNo << ", "
<< rhs.expireDate << ", "
<< rhs.carUsage << ", "
<< rhs.manufacturingDate;
return out;
}
int main()
{
// your linked list of data
std::list<carInsurance> cars{{"a","00/01/0000","a","a"},
{"b","00/03/0000","b","b"},
{"c","00/02/0000","c","c"}};
// sort the list by expireDate month
cars.sort([](carInsurance& a, carInsurance& b){
extract_date a_date(a.expireDate);
extract_date b_date(b.expireDate);
return a_date.month < b_date.month;
});
// print the sorted list
std::copy(cars.begin(), cars.end(), std::ostream_iterator<carInsurance>(std::cout, "\n"));
return 0;
}

Using pointers to duplicate and grow an existing array

I am failing to reach expected output when testing my 'grow'and 'subArray' functions. I've tried dereferencing back and forth in the function and also in main(). I'm wondering if there's something wrong with my memory allocation that is causing the lapse. I am extremely stuck and was hoping someone could potentially see something that I am missing, thanks.
#include <iostream>
#include <iomanip>
using namespace std;
bool isSorted(int *arr, int size){
for(int index = 0; index < size - 1; index ++){
if(*(arr + index) > *(arr + index + 1)){
return false;
}
}
return true;
}
double chain (int totalInches, int *feet, int *inches){
*feet = totalInches/12;
*inches = totalInches%12;
return *(feet)*3.49 + *(inches)*.30;
}
int *grow (int *arr, int size){
int *newArray;
newArray = new int[size*2]; //alocate new array
for(int i = 0; i < size*2; i+=2){
*(newArray + i) = *(arr+i);
*(newArray + i + 1) = *(arr+i);
}
return newArray;
}
int *duplicateArray (int *array, int size) {
int *newArray;
if (size <= 0)
return NULL;
newArray = new int [size]; //allocate new array
for (int index = 0; index < size; index++){
newArray[index] = array[index]; //copy to new array
}
return newArray;
}
int *subArray( int *array, int start, int length){
int *result = duplicateArray(array,5);
return result;
}
void showArray( int *arr, int size){
for(int i = 0; i < size; i ++)
{
cout << *(arr + i) << " ";
}
}
int main(){
int size = 8;
int testArray[] = {1,2,3,4,5,6,7,8};
cout << "testing isSorted: " << endl;
cout << "test data array 1: ";
showArray(testArray, size);
cout << endl;
cout << "Expected result: true" << endl;
cout << "Actual result: " << boolalpha << isSorted(testArray, size);
cout << endl;
int testArray2[]= {8,7,6,5,4,3,2,1};
cout << "test data array 2: ";
showArray(testArray2, size);
cout << endl;
cout << "Expected result: false" << endl;
cout << "Actual result: " << boolalpha << isSorted(testArray2, size);
cout << endl << endl << endl;
int chainTest = 53;
cout << "Checking chain for 53 inches: " << endl;
cout << "Expected result: 15.46 " << " " << "feet: 4 " <<
" " << "inches: 5"<< endl;
int in;
int ft;
cout << "Actual results : " << chain(chainTest,&ft,&in);
cout << " " << "feet: " << ft << " " << "inches: " << in << endl;
cout << endl << endl;
cout << "testing grow: " << endl;
cout << "test data 1: ";
showArray(testArray, size);
cout << endl;
cout << "Expected result: 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 " << endl;
cout << "Actual results: " << *(grow(testArray, size));
cout << endl << endl;
cout << "testing subArray:" << endl;
cout << "test data: ";
showArray(testArray, size);
cout << endl;
int start = 5;
int length = 3;
cout << "start: " << start << " " << "length: " << length << endl;
cout << "Expected result: " << "6 7 8" << endl;
cout << "Actual result: " << *(subArray(testArray, start, length));
cout << endl;
return 0;
}
Output:
As you notice, the loop is terminating after one traversal. The grow function is intended to duplicate and expand. In other words, it's supposed to make a copy of itself and append as it traverses. Any ideas as to why I am getting hung on the first element of the array?
You are actually doubling the array but only the first element is being printed because you are dereferencing an int* . To print all the elements, write a loop and print all the elements.
Also there is so much memory leak here. Please free memory after you are done using it. You are read about the delete[] operator.
Your loop going two at a time is good but it prevents you from selecting every element in the original array causing you to skip the even numbers. check your for loop and consider using two counters or if you want to modify your for loop to
for(int i = 0; i < size*2; i+=2){
*(newArray + i) = *(arr+i/2);
*(newArray + i + 1) = *(arr+i/2);
}
to ensure every element is reached
also as stated in the comments, use the showArray method you implemented
showArray(grow(testArray, size),size*2);

Search in Dynamic Array

When I'm searching an integer in my dynamic array, the search function isn't working well as its always showing its positioned at 1. whether the data is actually there or not.
What i'm actually trying to do is using dynamic data structure, I'm adding the data. Deleting, searching and saving to txt file. and Loading it back. But the problem is search. I used switch cases and search is at Case 4.
#include<iostream>
#include<string>
#include<fstream> //to save file in text
using namespace std;
int main()
{
int *p1;
int size = 0;
int counter = 0;
p1 = new int[size];
int userchoice;
int i;
int position;
while (1)
{
cout << "Please enter your choice " << endl;
cout << endl;
cout << "To insert Press '1'" << endl;
cout << "To Delete press '2'" << endl;
cout << "To View press '3'" << endl;
cout << "To Search press '4'" << endl;
cout << "To Save Press '5'" << endl;
cout << "To Load Previously saved Data press '6'" << endl;
cout << "To Exit press '7'" << endl;
cout << endl;
cout << "Enter your choice: ";
cin >> userchoice;
switch (userchoice) // User's selection from the menu
{
case 1: //Insert Number
cout << "Enter a Number: ";
cin >> p1[size];
counter++;
size++; //Add's memory space
break;
case 2: //Delete Number
int udelete;
cout << "Enter a number to delete: ";
cin >> udelete; //User enters Number to be deleted
//Checking if the number is in an array.
for (position = 0; position<size; position++)
{
if (p1[position] == udelete)
break;
}
if (position>size)
{
cout << "The number is not in the memory: ";
cout << endl;
break;
}
for (i = position; i<size; i++) {
p1[i] = p1[i + 1];
}
size--;
cout << "Successfully Deleted!!! ";
cout << endl;
break;
case 3: // View
for (i = 0; i<size; i++)
{
cout << "Your data" << " " << i << " " << "-->" << p1[i] << endl;
}
break;
case 4:
{
int usearch;
cout << "Please enter the figure you would like to search ";
cout << "->";
cin >> usearch;
for (i = 0; i>size; i++)
{
if (p1[size] == usearch)
break;
}
if (usearch == size)
{
cout << "not found. ";
}
cout << "Position at: " << i + 1 << endl;
break;
}
case 5: // Save
{
ofstream save;
save.open("Dynamicdata.txt", ofstream::out | ofstream::app);
for (i = 0; i<size; i++)
{
save << p1[i] << endl;
}
save.close();
cout << "File Saved " << endl;
break;
}
case 6: //Read from File
{
string read;
ifstream file_("Dynamicdata.txt");
if (file_.is_open())
{
while (getline(file_, read))
{
cout << read << "\n";
}
file_.close();
}
else
cout << "File Not open" << endl;
cin.get();
break;
}
case 7:
{
return 0;
}
}
}
}
Your problem is that the size of your array is 0. Here you set size to 0 and then size for the size of p1
int size=0;
int counter=0;
p1 = new int[size];
You are going to need to make size bigger so that you can actually store elements in p1 or instead of using arrays and dynamic memory allocation use a std::vector and let it handle that for you.
The code has undefined behaviour because initailly the dynamically allocated array pointed to by pointer p1 has no elements
int size=0;
^^^^^^^^^^
//...
p1 = new int[size]; // size is equal to 0
So in the following code snippet an atttempt to write data to p1[size] results in undefined behaviour
case 1: //Insert Number
cout<<"Enter a Number: ";
cin>>p1[size]; // undefined behaviour
^^^^^^^^^^^^^
counter++;
size++; //Add's memory space
break;
You need to reallocate the array to reserve memory for the added new element.
Take into account that for example this loop
for (i = 0; i>size; i++)
^^^^^^^
{
if (p1[size] == usearch)
break;
}
will never iterate because variable i set to zero can not be greater than size that at least equal to zero.
And it would be logically more correct to write
if (p1[i] == usearch)
^^^^^
instead of
if (p1[size] == usearch)
^^^^^^^^
Consequently this if statement
if (usearch == size)
^^^^^^^
{
cout << "not found. ";
}
should be replaced with this for statement
if (i == size)
^^
{
cout << "not found. ";
}

Creating and clearing an array of structures

I've been trying to write a short program allowing the user to add entries to a "database", listing the entries they have put in, and the ability to clear all the entries without ending the program. Here's what i've got
#include <cstdlib>
#include <iostream>
#include <string>
using namespace std;
struct BIRTH
{int month; int year;};
struct ID
{string name; bool vip; float score;
struct BIRTH date;} ;
int main(int argc, char** argv) {
ID **ptrarr;
ptrarr = new ID * [10];
for (int r=0; r<10; r++)
{ptrarr[r] = new ID[1] ;}
int counter = 0;
while(counter<100){
cout << "Type add to create a new entry" << endl;
cout << "Type list to see all entries" << endl;
cout << "Type clear to delete all entries" << endl;
cout << "Type exit to terminate" << endl;
string command = "0";
getline (cin,command);
if(command=="add")
{
cout << "Enter name" << endl;
getline (cin,ptrarr[counter][1].name);
cout << "VIP? 1 for yes, 0 for no" << endl;
cin >> ptrarr[counter][1].vip;
cout << "Enter score" << endl;
cin >> ptrarr[counter][1].score;
cout << "Month of birth" << endl;
cin >> ptrarr[counter][1].date.month;
cout << "Year of birth" << endl;
cin >> ptrarr[counter][1].date.year;
counter++;
}
else if(command=="list")
{
for (int i=0; i<counter; i++)
{int n=i+1;
cout << n << " "
<< ptrarr[i][1].name << " ";
if (ptrarr[i][1].vip)
{cout << "VIP ";}
cout << "Score: " << ptrarr[i][1].score << " "
<< "Born: " << ptrarr[i][1].date.month << "/" << ptrarr[i][1].date.year << endl;
}
}
else if(command=="clear")
{delete[] ptrarr;
cout << "Entries cleared" << endl;}
else if(command=="exit")
{return 0;}
else
cout << "try again" << endl;
}
return 0;
}
Now here's the deal: the following code successfully compiles, but when I type in the "add" command, the program crashes (achievement unlocked, didn't think it's possible to obtain with such a short code). The most important thing is that the array is made of a multitype structure and that the "clear" command wipes out all the entries in the array.
NOTE: I understand that there are thousand better ways to write this piece of code, but I'm writing it to practice the things I have covered so far regarding C++. So unless it is absolutely necessary for the code to run, please do not introduce any new gimmicks =)
Replace all ptrarr[counter][1] with ptrarr[counter][0] fixes the problem.
Further advices:
I. This code has redundancy:
ID **ptrarr;
ptrarr = new ID * [10];
for (int r=0; r<10; r++)
{ptrarr[r] = new ID[1] ;}
Replace it with:
ID *ptrarr;
ptrarr = new ID [10];
Then you do not need extra [0] at the end of each ptrarr[counter]
II. functions make your code more readable:
if(command=="add")
add();
else if(command=="list")
list();
else if(command=="clear")
clear();
else if(command=="exit")
return 0;
else
cout << "try again" << endl;
Then decisions are made in a smaller area (Good practice for large programs.)
III. There is another mistake in your code:
else if(command=="clear")
{delete[] ptrarr;
cout << "Entries cleared" << endl;}
Here you should reset the counter. Also if you regard my point (I) this part is fine. Otherwise, if you use new with a for loop, I am afraid that you need to delete with a for loop too. Merely removing the root of the array tree brings you memory leak!
Also, if you cleared the list by delete, wont you need to store data in the list anymore? Using delete in linked lists is a good idea, but it does not apply here. Just reseting the counter does the job and it does not show IDs in the list anymore. The for inside the list does only count up to the counter.
If you exit the program don't you free the memory?
I say
delete [] ptrarr;
is good for being at exit.
You are creating an an array of pointers, each one of which points to one element:
ptrarr[r] = new ID[1] ;
The maximum index that you can use with ptrarr[r] is 0. Since you are using ptrarr[counter][1], you are accessing memory that is out of bounds. This leads to undefined behavior. Crashing is one such undefined behavior.
There are other issues with your code that you may want to fix.
More out of bounds memory access
You are using:
int counter = 0;
while(counter<100){
...
getline (cin,ptrarr[counter][1].name);
That is again going to lead to undefined behavior if counter > 10 since you allocated only 10 pointers for ptrarr.
Deleting the contents
You are using:
else if(command=="clear")
{
delete[] ptrarr;
cout << "Entries cleared" << endl;
}
There are couple of problems with this:
You have memory leak. You never call delete [] on what ptrarr[0] - ptrarr[9] point to. You'll have to use:
else if(command=="clear")
{
for ( int i = 0; i < 10; ++i )
{
delete [] ptrarr[i];
}
delete[] ptrarr;
cout << "Entries cleared" << endl;
}
Remember that every allocation must have a corresponding deallocation. Otherwise, you are leaking memory.
Once you call delete [] ptrarr;, it points to dangling memory. I don't see any code that reallocates memory for ptrarr while you continue to use it.
You need to reallocate memory and reset counter to 0 when the user chooses "clear".
My suggestion
You don't two levels of pointers. You just need something like:
int const MAX_ITEMS = 100;
ID* IDarr = new ID[MAX_ITEMS];
Instead of ptrarr[counter][1], use IDarr[counter].
Use MAX_ITEMS in the expression of the while statement instead of the magic number 100.
int counter = 0;
while(counter<MAX_ITEMS){
When processing "clear", you don't need to deallocate or allocate memory. Just reset counter.
else if(command=="clear")
{
counter = 0;
cout << "Entries cleared" << endl;
}
Make sure to deallocate memory before returning from main.
Here's the complete main function with the changes:
int main(int argc, char** argv) {
const int MAX_ITEMS = 100;
ID* IDarr = new ID[MAX_ITEMS];
int counter = 0;
while(counter < MAX_ITEMS){
cout << "Type add to create a new entry" << endl;
cout << "Type list to see all entries" << endl;
cout << "Type clear to delete all entries" << endl;
cout << "Type exit to terminate" << endl;
string command = "0";
getline (cin,command);
if(command=="add")
{
cout << "Enter name" << endl;
getline (cin, IDarr[counter].name);
cout << "VIP? 1 for yes, 0 for no" << endl;
cin >> IDarr[counter].vip;
cout << "Enter score" << endl;
cin >> IDarr[counter].score;
cout << "Month of birth" << endl;
cin >> IDarr[counter].date.month;
cout << "Year of birth" << endl;
cin >> IDarr[counter].date.year;
counter++;
}
else if(command=="list")
{
for (int i=0; i<counter; i++)
{
int n=i+1;
cout << n << " " << IDarr[i].name << " ";
if (IDarr[i].vip)
{
cout << "VIP ";
}
cout
<< "Score: " << IDarr[i].score << " "
<< "Born: " << IDarr[i].date.month << "/" << IDarr[i].date.year << endl;
}
}
else if(command=="clear")
{
counter = 0;
cout << "Entries cleared" << endl;
}
else if(command=="exit")
{
// Don't use return 0;
// Just break out of the while loop so that memory
// can be deallocated at the end of this function.
break;
}
else
cout << "try again" << endl;
}
delete [] IDarr;
return 0;
}
Array indices start at 0.
ptrarr[counter][1] refers to the second element of ptrarr[counter]. ptrarr[counter] points to an array of one element.
try this :
if(command=="add") {
cout << "Enter name" << endl;
getline (cin,ptrarr[counter][0].name);
cout << "VIP? 1 for yes, 0 for no" << endl;
cin >> ptrarr[counter][0].vip;
cout << "Enter score" << endl;
cin >> ptrarr[counter][0].score;
cout << "Month of birth" << endl;
cin >> ptrarr[counter][0].date.month;
cout << "Year of birth" << endl;
cin >> ptrarr[counter][0].date.year;
counter++;
}
else if(command=="list") {
for (int i=0; i<counter; i++){
int n=i+1;
cout << n << " "<< ptrarr[i][0].name << " ";
if (ptrarr[i][0].vip){
cout << "VIP ";
}
cout << "Score: " << ptrarr[i][0].score << " "
<< "Born: " << ptrarr[i][0].date.month << "/" << ptrarr[i][0].date.year << endl;
}
}
Conclusion :
Just as you initialized counter with 0 you should have used 0 index to access the first element;
Same goes while listing.
Arrays are 0 index based.

C++ inventory item removal

Increase the inventory to be 10 items. DONE!!!
Create a for loop that asks the user to input the initial items in the inventory.DONE!!!
After the for loop create a minor story where the healer changes two items (i.e. items 4 and 8).What I want is to SWAP an item for another item ie would you like to trade your {[item] for [item2] y or n
Sort the inventory in alphabetical order. You can use your own sort if you want, but here is a bubble sort algorithm:
// A simple inventory program using a struct to store data
// in an array.
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
// define a data structure
struct InventoryRecord
{
string name; // inventory item name
int qty; // how many are in stock
double value; // the value
};
// const for the max size of the record array
const int MAX_SIZE = 9;
// function prototypes
void addData(InventoryRecord list[], int& size);
void dispData(const InventoryRecord list[], int size);
void remData( const InventoryRecord list[], int size);
void saveFile(const InventoryRecord list[], int size);
void openFile(InventoryRecord list[], int& size);
char getMenuResponse();
int main(int argc, char *argv[])
{
InventoryRecord recList[MAX_SIZE];
int numOfRecs = 0;
bool run = true;
do
{
cout << "Hero's Inventory - " << numOfRecs << " items in your bag" << endl;
switch ( getMenuResponse() )
{
case 'A': addData(recList, numOfRecs); break;
case 'D': dispData(recList, numOfRecs); break;
case 'R': remData(recList, numOfRecs); break;
case 'O': openFile(recList, numOfRecs); break;
case 'S': saveFile(recList, numOfRecs); break;
case 'Q': run = false; break;
default : cout << "That is NOT a valid choice" << endl;
}
} while (run);
cout << endl << "Program Terminated" << endl;
// system("PAUSE"); // Program exits immediatly upon "Quit" if commented out
return EXIT_SUCCESS;
}
// Task: Allow data entry of one inventory item
// Accepts: References to the inventory array and its size
// Returns: Nothing
// Modifies: The array and size 'actual parameter'
// NOTE: Could be modified to allow entry of more than one item
void addData(InventoryRecord list[], int& size)
{
InventoryRecord tmp; // declare a temp item that we will load before putting in the array
char response;
char str[256]; // needed for cin.getline; we are going to use a char array
if (size < MAX_SIZE) {
system("cls");
cout << "Please enter 10 items helpful to your quest! " << endl;
cout << "Enter item: " << endl << endl;
cout << "Name: ";
// Get up to 256 characters from the keyboard including white space.
// Stop reading if encounter the \n first. If there's any chance of
// more than 256 characters you will have to clean up cin with
// cin.ignore before the next input.
cin.getline(str, 256, '\n'); // for char arrays; different from the other getline
tmp.name = str;
cout << "Quantity: ";
cin >> tmp.qty;
cout << "Value: ";
cin >> tmp.value;
cout << endl;
// see if this record should be added to the array
cout << "Add to inventory? (y/n) ";
cin >> response;
if (toupper(response) == 'Y')
list[size++] = tmp;
} else {
cout << "Inventory is full; cannot enter more units." << endl;
system("pause");
}
system("cls");
}
void dispData(const InventoryRecord list[], int size)
{
system("cls");
double cost = 0;
if(size < 1) {
cout << "Nothing to display" << endl;
} else {
cout << "All Items in your Bag" << endl << endl;
cout << fixed << setprecision(2);
cout << "Item Name Qty Value" << endl;
cout << "~~~~~~~~~~~~~~~~~~" << endl;
cout << left;
for (int i = 0; i < size; i++) {
cout << setw(21) << list[i].name << right
<< setw(4) << list[i].qty
<< setw(10) << list[i].value << left << endl;
cost = cost + list[i].value * list[i].qty;
}
cout << "~~~~~~~~~~~~~~~~~~~" << endl;
cout << right << setw(3) << size;
cout << " items listed";
cout << right << setw(19) << cost << endl << endl;
}
system("PAUSE");
system("cls");
}
void remData(const InventoryRecord list[], int size) {
system("cls");
cout <<"Enter Item you wish to remove from your inventory: " << endl;// This is being displayed so user can see items in the inventory
double cost = 0;
if(size < 1) {
cout << "Nothing to display" << endl;
} else {
cout << "All Items in your Bag" << endl << endl;
cout << fixed << setprecision(2);
cout << "Item Name Qty Value" << endl;// It is not displaying right the alignment is off
cout << "~~~~~~~~~~~~~~~~~~" << endl;
cout <<"Item Name: ";/* from here I do not know what to do! What I want is have use type the item name they want removed
also display an error if they enter an item wrong*/
cout << left;
for (int i = 0; i < size; i++) {
cout << setw(21) << list[i].name << right
<< setw(4) << list[i].qty
<< setw(10) << list[i].value << left << endl;
cost = cost + list[i].value * list[i].qty;
}
cout << "~~~~~~~~~~~~~~~~~~~" << endl;
cout << right << setw(3) << size;
cout << " items listed";
cout << right << setw(19) << cost << endl << endl;
}}
// Save records to disc
void saveFile(const InventoryRecord list[], int size) {
ofstream outfi("Inventory.txt");
// make sure the file stream is open before doing IO
if (!outfi.fail()) {
system("cls");
cout << "Saving inventory to the disc ";
for(int i = 0; i < size; i++) {
outfi << list[i].name << ';'
<< list[i].qty << ';'
<< list[i].value;
// Start a new line after all but the last record
// Simplifies reading the file as EOF is at end of last line
if (i < size-1) outfi << endl;
}
cout << endl << size << " records writen to the disc." << endl;
outfi.close();
system("PAUSE");
system("cls");
}
else {
cout << "ERROR: problem with file" << endl;
system("PAUSE");
system("cls");
}
}
// Open file and load array
void openFile(InventoryRecord list[], int& size)
{
ifstream infi("Inventory.txt");
string str;
stringstream strstrm;
// make sure the file stream is open before doing IO
if (!infi.fail()) {
system("cls");
cout << "Reading inventory from the disc ";
size = 0; // overwrite any existing records
while(!infi.eof() && size < MAX_SIZE) {
// get and store the name
getline(infi, str, ';');
list[size].name = str;
// get, convert and store the quantity
getline(infi, str, ';');
strstrm.str(""); strstrm.clear(); // empty and clear the stringstream
strstrm << str;
strstrm >> list[size].qty;
// get, convert and store the cost
getline(infi, str);
strstrm.str(""); strstrm.clear(); // empty and clear the stringstream
strstrm << str;
strstrm >> list[size++].value;
}
cout << endl << size << " records read from the disc." << endl;
system("PAUSE");
system("cls");
}
else { // something went wrong with opening the file
cout << "ERROR: problem with file" << endl;
system("PAUSE");
system("cls");
}
}
char getMenuResponse()
// Task: Put the menu on screen and get a response
// Accepts: Nothing
// Returns: The users response
// Modifies: Nothing
// NOTE: Characters are far more intuitive at the command
// line than numbers; avoid using numbers.
{
char response;
cout << endl << "Make your selection" << endl
<< "(A)dd Items, (D)isplay Items, (R)emove items, (O)pen File, (S)ave File, (Q)uit" << endl
<< "> ";
cin >> response;
cin.ignore(256, '\n');
// clean-up up to 256 chars including the delimiter specified (\n, the endl)
// OR stop when the \n is encountered after removing it.
return toupper(response);
}
To remove an element from your inventory, you just need to move all elements after the removed element one position forward. Once that is done, you also need to reduce the lengthy by one. For example, to remove the elements at the position index from an array array with currently length elements you could use
if (index < length) {
std::copy(array + index + 1, array + length, array + index);
++length;
}
There are essentially two ways to remove the element, the easiest is swap the element which you want to delete with the last one and resize the list:
void deleteElem(Data[] list, int & listLength, int ix) {
if (ix < listLength - 1) {
list[ix] = list[listLength - 1];
}
--listLength;
}
The second solution is memmove everthing after the to deleting element one to the left:
void deleteElem(Data[] list, int & listLength, int ix) {
memmove(list[ix], list[ix + 1], (listLength - ix - 1) * sizeof(Data));
--listLength;
}
EDIT: There was an error in the length for memmove, always the same. You should read the documentation.