Copying Array - Crashes After Doubling Array - c++

I'm having some trouble with this program, I'm aware I can use a vector but I'm trying to do it only using arrays. Once the program gets to the initial array size of 1000, it should double the array (in this case to 2000) after copying the data. So for example if I had a list of 3000 names, it'd double once at 1000, then again at 2000 - making the total list 4000. I'm not entirely sure why it crashes after I double the array size. Can someone help me with this?
#include <iostream>
#include <fstream>
#include <string.h>
using namespace std;
struct Information {
char functionality;
string SSN;
string name;
};
Information* person;
int numPeople = 1000;
int numRetrieved = 0;
int numArray = 0;
int numInserted = 0;
int numDeleted = 0;
void doubleArray(Information *person){
numPeople = numPeople * 2;
Information* temp = new Information[numPeople];
memcpy(temp, person, numPeople/2);
delete[] person;
person = temp;
cout << "Person 1: " << person[0].name << " " << person[0].SSN << endl;
}
//Currently not using this until I figure out the double...
void halfArray(Information *person){
numPeople = numPeople / 2;
}
void deleteInfo(Information *person, string SSN){
for(int i = 0; i < numArray; i++){
if(person[i].SSN == SSN){
for(int k = i; k < numArray-1; k++){
person[k].SSN = person[k+1].SSN;
person[k].name = person[k+1].name;
}
numArray--;
numDeleted++;
if((numArray+1) < (numPeople / 4)){
//halfArray(person);
}
}
}
}
void retrieve(Information *person, string findSSN, int lastPerson){
for(int i = 0; i < lastPerson; i++){
if(person[i].SSN == findSSN){
numRetrieved++;
}
}
}
void insert(Information *person, string SSN, string name){
if(numArray == (numPeople - 1)){
doubleArray(person);
}
bool dontInsert = false;
for(int i = 0; i <= numArray; i++){
if(person[i].SSN == SSN){
dontInsert = true;
}
}
if(dontInsert){
dontInsert = false;
}else{
person[numArray].SSN = SSN;
person[numArray].name = name;
numArray++;
numInserted++;
}
}
int main(int argc, char* argv[]) {
person = new Information[numPeople];
char firstLetter;
string SSN, firstName, lastName, name;
fstream input(argv[1]);
for(int i = 0; !input.eof(); i++){
input >> firstLetter >> SSN >> firstName >> lastName;
name = firstName + " " + lastName;
switch(firstLetter){
case 'd':{
deleteInfo(person, SSN);
break;
}
case 'i':{
insert(person, SSN, name);
break;
}
case 'r':{
retrieve(person, SSN, numArray);
break;
}
}
}
input.close();
}

You delete the memory that the Information* points at, but you have a copy of that pointer, and assigning it to your temp variable has no effect outside of doubleArray.
Let's say that the value of person passed in is 0xC001C001;
void doubleArray(Information *person){
numPeople = numPeople * 2;
Information* temp = new Information[numPeople];
memcpy(temp, person, numPeople/2);
delete[] person;
person = temp;
cout << "Person 1: " << person[0].name << " " << person[0].SSN << endl;
}
You create a new pointer temp which has a value of 0xBAD1BAD1. You delete person (0xC001C001), then assign 0xBAD1BAD1 to person. Execution then continues in the insert function ...
void insert(Information *person, string SSN, string name){
if(numArray == (numPeople - 1)){
doubleArray(person);
}
bool dontInsert = false;
for(int i = 0; i <= numArray; i++){
if(person[i].SSN == SSN){
dontInsert = true;
}
}
The person variable here still has the value 0xC001C001, which has been deallocated. Your program blows up when you deference person with person[i].SSN.
When you want to change a pointer, the classic pattern is to pass a pointer pointer. (Two star programming)
void redo(P** p)
{
P* temp = new P();
delete *p;
*p = temp;
}

Related

string subscript out of range - string bubble sort

First post here but I've been digging around for a solution to this bug.
I am getting an error "string subscript out of range"
PhoneBook is an array of class Contact object pointers.
static const int maxSize = 10;
Contact* phoneBook[maxSize]; //array of contact pointers
where Contact is defined as
class Contact
{
public:
Contact();
std::string firstName;
std::string lastName;
std::string name; //lName + fName
std::string phoneNumber;
std::string address;
};
Here is my bubble sort function.
void AddressBook::bubbleSort(Contact phoneBook[], int length)
{
Contact temp;
for (int i = 0; i < length; i++)//for n-1 passes
{
for (int j = 0; j < length - 1; j++)
{
if (phoneBook->name[j] > phoneBook->name[j + 1])
{
temp = phoneBook[j];
phoneBook[j] = phoneBook[j + 1];
phoneBook[j + 1] = temp;
}
}
}
}
here is addContact
void AddressBook::addContact(std::string fName, std::string lName, std::string pNumber, std::string addr)
{
if (isFull())
{
std::cout << "Is full" << std::endl;
return;
}
Contact *contact = new Contact;
contact->firstName = fName;
contact->lastName = lName;
contact->name = lName + ", " + fName;
contact->phoneNumber = pNumber;
contact->address = addr;
std::cout << contact->name + " has been added!" << std::endl;
phoneBook[length] = contact;
length++;
bubbleSort(phoneBook[maxSize], length);
}
and lastly, where i use it (source.cpp)
switch (choice)
{
case 1:
addrBook.addContact("Ty", "Le", "6191231234", "1234 State Street");
addrBook.addContact("Zak", "Zachary", "6191231234", "1234 Avenue Drive");
I know for a fact that the problem originates from the bubbleSort function because it'll work fine when I comment it out of addContact().
Here's a picture of my error
(too long to copy and paste)
FULL CODE
.h
https://pastebin.com/TrtQW8Tc
.cpp
https://pastebin.com/EaGBUe9e
source
https://pastebin.com/1BR5pXZE
This is almost a typo. Instead of indexing the name string in
if (phoneBook->name[j] > phoneBook->name[j + 1])
you want to index phonebook
if (phoneBook[j].name > phoneBook[j + 1].name)

Program runs through compiler but not giving answers(C++ Classes)

I'm new to C++ OOP and I find difficulties in implementing the following task:
The program is about taking information from a file, storing it in vector pointers and then printing it, but it gives proccess failure.
Basically doesn't call the second constructor in class Car and I don't seem to find a way to fix this issue.
Would like to get some tips.
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
class Person{
protected:
string name;
int age;
public:
Person(string n, int a) {
name = n;
age = a;
cout << "Constructor called" << endl;
}
void IncAge(){
age++;
}
string get_name() {
return name;
}
int get_age() {
return age;
}
};
class Car{
public:
string brand;
Person* owner;
Person* driver;
Car(string b, Person* o, Person* d){
brand = b;
owner = o;
driver = d;
cout << "Constructor 2 called" << endl;
}
string get_brand(){ return brand; }
void get_owner(){ cout << owner; }
void get_driver(){ cout << driver; }
};
void printall(vector<Car*> car){
for(int i =0; i < car.size(); i++){
cout << car[i]->get_brand();
}
}
int main() {
vector<Person*> people;
vector<Car*> cars;
ifstream openFile;
string filename = "input.txt";
openFile.open(filename.c_str());
if(openFile.fail()){
cout << "Failed opening targeted file!" << endl;
return 1;
}
else{
int n;
int read_age;
string read_name, read_car, read_owner,read_driver;
openFile >> n;
for(unsigned int i = 0; i < n; i++){
openFile >> read_name;
openFile >> read_age;
people[i] = new Person(read_name, read_age);
}
openFile >> n;
for(unsigned int i = 0; i < n; i++){
openFile >> read_car;
openFile >> read_owner;
openFile >> read_driver;
unsigned int j = 0;
unsigned int k = 0;
for(; j < people.size(); j++){
if(read_owner == people[j]->get_name()) break;
}
for(; k < people.size(); k++){
if(read_driver == people[k]->get_name()) break;
}
cars[i] = new Car(read_car, people[j], people[k]);
}
openFile.close();
for(unsigned int i = 0; i < people.size(); i++) {
people[i]->IncAge();
}
printall(cars);
}
return 0;
}
I am also learning c++, I want to comment instead of writing this as an answner, but I can't do it now.
people[i] = new Person(read_name, read_age);
use push_back() function to add person to vector
I don't think [index] will properly increase the size of vector and reallocate memory for new element

How can I check if array is full and double/half the size of it?

This program reads information from a text file, stores it in an array, and performs one of 3 functions. I need to be able to check if the array is full and double the size if it is or half the size if their is a deletion 1/4 of the size of the array. Tried to be brief so if you need more information, let me know.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
struct info{
char letter;
string SSN;
string firstName;
string lastName;
};
void insertion(int &count, int &validInsertationCount, string &SSN, char &letter, string &firstName, string &lastName, info *list);
void deletion(int &count, int &validDeletionCount, string &SSN, char &letter, string &firstName, string &lastName, info *list);
void retrieval(int &count, int &validRetrievalCount, string &SSN, string &firstName, string &lastName, info *list);
int main(int argc, char* argv[]){
int arraySize = 1000;
struct info list[1000];
fstream input(argv[1]);
int count = 0;
int validInsertationCount = 0;
int validDeletionCount = 0;
int validRetrievalCount = 0;
while(!input.eof()){
input >> list[count].letter >> list[count].SSN >> list[count].firstName >> list[count].lastName;
if(list[count].letter == 'i'){
insertion(count, validInsertationCount, list[count].SSN, list[count].letter, list[count].firstName, list[count].lastName, list);
}
else if(list[count].letter == 'd'){
deletion(count, validDeletionCount, list[count].SSN, list[count].letter, list[count].firstName, list[count].lastName, list);
}
else if(list[count].letter == 'r'){
retrieval(count, validRetrievalCount, list[count].SSN, list[count].firstName, list[count].lastName, list);
}
count++;
}
input.close();
int numberOfItems = validInsertationCount - validDeletionCount;
cout << "The Number of Valid Insertation: " << validInsertationCount << endl;
cout << "The Number of Valid Deletion: " << validDeletionCount << endl;
cout << "The Number of Valid Retrieval: " << validRetrievalCount << endl;
cout << "Item Numbers in the array: " << numberOfItems << endl;
cout << "Array Size is: " << arraySize << endl;
//cout << "Time Elapsed: " << <<endl;
}
void insertion(int &count, int &validInsertationCount, string &SSN, char &letter, string &firstName, string &lastName, info *list){
for(int i = 0; i < count; i++){
if(SSN == list[i].SSN && list[i].letter == 'i'){
for(int k = i; k < count; k++){
list[k].SSN = list[k+1].SSN;
list[k].letter = list[k+1].letter;
list[k].firstName = list[k+1].firstName;
list[k].lastName = list[k+1].lastName;
}
count--;
return;
}
}
validInsertationCount++;
return;
}
void deletion(int &count, int &validDeletionCount, string &SSN, char &letter, string &firstName, string &lastName, info *list){
for(int i = 0; i < count; i++){
if(SSN == list[i].SSN && firstName == list[i].firstName && lastName == list[i].lastName){
for(int k = i; k < count; k++){
list[k].SSN = list[k+1].SSN;
list[k].letter = list[k+1].letter;
list[k].firstName = list[k+1].firstName;
list[k].lastName = list[k+1].lastName;
}
count--;
validDeletionCount++;
return;
}
}
}
void retrieval(int &count, int &validRetrievalCount, string &SSN, string &firstName, string &lastName, info *list){
for(int i = 0; i < count; i++){
if(SSN == list[i].SSN && firstName == list[i].firstName && lastName == list[i].lastName){
validRetrievalCount++;
}
}
return;
}
You can't simply resize a statically allocated array so you'll want to either use std::vector or malloc/new to allocate a dynamic array. However in that case you can't determine the size of the array using sizeof(). So you either keep a size variable or use a "delimiter" value in order to pinpoint the end of the array.

C++ none of the 3 overloads could convert all the argument types line 39 1

So after coding this I got an error : C++ none of the 3 overloads could convert all the argument types line 39 1 in w5.cpp
do you know where is the problem? and could you help me to fix it? I actually dont know why it is showing this because I got the default constructor for this code.
//w5.h
#define MAX_LINE_LENGTH 256
#define MAX_PURCHASES 5
// w5.cpp
#include <iostream>
#include <cstring>
#include "w5.h"
#include "CreditStatement.h"
using namespace std;
void sort(CreditStatement* statement, int n);
int main()
{
double price;
int n = 0;
CreditStatement statement[MAX_PURCHASES];
cout << "Credit Statement Processor\n";
cout << "==========================\n";
do
{
cout << "Item price (0 to quit): ";
cin >> price;
if (cin.fail() || (cin.get() != '\n'))
{
cin.ignore(2000, '\n');
cerr << "Bad character. Try again." << endl;
cin.clear();
}
else if ((int)price != 0)
{
cout << "Statement item: ";
char item[MAX_LINE_LENGTH];
cin.getline(item, MAX_LINE_LENGTH);
if (strlen(item) > 0)
{
statement[n] = CreditStatement(item, price);
n++;
}
}
} while ((int)price != 0 && n < MAX_PURCHASES);
cout << endl;
sort(statement, n);
cout << " Credit Statement\n\n";
cout << " Item Price\n";
cout << "----------------------------------\n";
for (int i = 0; i < n; i++)
{
statement[i].display();
}
cout << endl;
return 0;
}
// sort sorts the elements of Credit Card Statement[n] in ascending order
//
void sort(CreditStatement* s, int n)
{
int i, j;
CreditStatement temp;
for (i = n - 1; i > 0; i--)
{
for (j = 0; j < i; j++)
{
if (s[j].isGreaterThan(s[j + 1]))
{
temp = s[j];
s[j] = s[j + 1];
s[j + 1] = temp;
}
}
}
}
//CreditStatement.h
class CreditStatement{
bool _valid;
double* _price;
char* _item;
public:
CreditStatement();
CreditStatement(char*, double*);
CreditStatement(const CreditStatement&);
CreditStatement& operator=(const CreditStatement&);
//output
void display() const;
//mutators
bool isGreaterThan(const CreditStatement&) const;
};
//CreditStatement.cpp
#include <iostream>
#include <new>
#include "CreditStatement.h"
using namespace std;
void CreditStatement::display() const{
cout << " Something" << _price << _item;
}
bool CreditStatement::isGreaterThan(const CreditStatement&) const{
return _valid;
}
CreditStatement::CreditStatement(){
_item = NULL;
_price = NULL;
}
CreditStatement::CreditStatement(char* iP, double* pP){
_price = NULL;
_item = NULL;
if (pP != NULL){
int sizepP = sizeof(pP) / sizeof(pP[0]);
_price = new (nothrow) double[sizepP];
if (_price){
for (int i = 0; i <sizepP; i++){
_price[i] = pP[i];
};
}
if (iP != NULL){
int sizeiP = sizeof(iP) / sizeof(iP[0]);
_item = new (nothrow) char [sizeiP];
if (_item){
for (int i = 0; i < sizeiP; i++){
_item[i] = iP[i];
};
}
}
}
}
CreditStatement::CreditStatement(const CreditStatement& otherCS){
*this = CreditStatement(otherCS._item, otherCS._price);
}
CreditStatement& CreditStatement::operator=(const CreditStatement& otherCS){
if (this != &otherCS)
{
if (_item){
delete[] _item;
_item = NULL;
}
if (_price){
delete[] _price;
_price = NULL;
}
else{
if (otherCS._price != NULL){
int sizepP = sizeof(otherCS._price) / sizeof(otherCS._price[0]);
_price = new (nothrow) double[sizepP];
if (_price){
for (int i = 0; i < sizepP; i++){
_price[i] = otherCS._price[i];
};
}
if (otherCS._item != NULL){
int sizeiP = sizeof(otherCS._item) / sizeof(otherCS._item[0]);
_item = new (nothrow) char[sizeiP];
if (_item){
for (int i = 0; i < sizeiP; i++){
_item[i] = otherCS._item[i];
};
}
}
}
}
}
return *this;
}
I also got this error
"no instance of constructor "CreditStatement::CreditStatement" matches the argument list
argument types are: (char [256], double) c:*\Project1\w5.cpp 38 20.
I think the problem is your call statement[n] = CreditStatement(item, price);
Here, price is a double, but there's a constructor CreditStatement(char*, double*); but none with signature CreditStatement(char*, double);
You might want to fix that.

Deleting a record from array of pointers of my own class type

I have created an Employee class:
class Employee {
private:
int idNumber;
string name, department, position;
public:
Employee() {
idNumber = 0;
name = department = position = "";
}
Employee(string n, int idn) {
name = n;
idNumber = idn;
department = position = "";
}
Employee(string n, int idn, string dep, string pos) {
name = n;
idNumber = idn;
department = dep;
position = pos;
}
void setName(string n) {
name = n;
}
void setidNumber(int idn) {
idNumber = idn;
}
void setDepartment(string dep) {
department = dep;
}
void setPosition(string pos) {
position = pos;
}
string getName() {
return name;
}
int getidNumber() {
return idNumber;
}
string getDepartment() {
return department;
}
string getPosition() {
return position;
}
};
Now, i created a 2D array of Pointers of type Employee:
int n=2;
Employee **p = new Employee * [n];
for (int i=0; i < n; i++)
p[i] = new Employee;
I stored two records successfully as under:
Name ID Number Department Position
FS 30 CS BS
AT 27 CS BS
I have this code to delete the record of Employees:
string del_name;
int flag = 0;
cin.ignore();
cout << "Enter name: ";
getline(cin, del_name);
for (int i=0; i < n; i++) {
while (del_name == p[i]->getName() && i < n) {
if (del_name == p[i]->getName()) {
delete p[i];
p[i] = NULL;
--k;
++flag;
cout << "Record deleted." << endl;
break;
}
else
{
flag = 0;
}
}
}
if (flag == 0)
cout << "No record found having name " << del_name << "." << endl;
Now, What's the problem:
If a record is found at multiple times. It deletes successfully even if all the records gets deleted.
But if ALL the records are unique and I delete the records one by one and all the records get deleted in this way then the program gets terminated.
Also, is there any other optimized approach to delete records without using VECTORS.
I hope i have clearly explained my problem. I can provide further details if needed.
Thank you for your time
First, usage of std::vector<> or some other container object is the way to go about this. If you can write code that beats (in terms of speed) written by professional library writers, then go ahead.
Second, what is your goal? If it's to simply deallocate entries in that array depending on some criteria, the loop you wrote is overly complex.
bool recordDeleted = false;
for (int i=0; i < n; ++i)
{
if (del_name == p[i]->getName())
{
delete p[i];
p[i] = NULL;
recordDeleted = true;
}
}
if ( !recordDeleted )
{
// record not found
}