How do I remove an element from an array and move everything up a spot? - c++

I am trying to remove a name from this array and then have an empty spot at the last position of the array once removed. How do I do this? Here is what I tried below. It removes it, but doesnt move to the end.
const int array_size = 16;
string restaurants[array_size] = {"Texas Roadhouse","On The Border","Olive Garden","Panda Express","Cracker Barrel","IHOP","Woohoo","Pei Wei","Mcdonalds","Denny's","Mrs. Fields","Subway","Dairy Queen","Burger King","Pizza Hut","Dominos"};
int current_size = 16;
cout << "Please enter the name of the Restaurant you would like to remove: ";
cin.ignore();
getline(cin, remove_restaurant);
remove(restaurants, restaurants_size, remove_restaurant);//function call
bool remove(string restaurants[], int& current_size, string name)//function to remove array
{
for (int i = 0; i < current_size; i++)//look at each name you want to remove
{
if ( restaurants[i] == name)
{
restaurants[i]=restaurants[i+1];
current_size --;
cout << "Restaurant removed successfully." << endl;
return true;
}
}
return false;
}

Use the remove-erase idiom, with std::remove and std::fill:
bool remove(string restaurants[], int& current_size, string name)//function to remove array
{
auto begin = std::begin(restaurants);
auto end = std::next(begin, current_size);
auto new_end = std::remove(begin, end, name);
std::fill(new_end, end, {});
current_size = std::distance(begin, new_end);
if (new_end != end) {
std::cout << "Restaurant removed successfully." << std::endl;
}
return new_end != end;
}

Create an array of the same size as the original
Begin iterating elements of the original array
If the current item in the array does not equal the item to remove, add it to the new array

Here is one possible way to amend your current solution. I agree with ott--, though, you should probably use a list instead.
for (int i = 0; i < current_size; i++)//look at each name you want to remove
{
if (restaurants[i] == name) {
swap(restaurants[i], restaurants[current_size-1]);
current_size --;
cout << "Restaurant removed successfully." << endl;
return true;
}
}

With std::vector, std::remove, and std::vector::erase:
#include <algorithm>
#include <string>
#include <vector>
// ...
vector<string> restaurants { ... };
string remove_restaurant;
getline(cin, remove_restaurant);
restaurants.erase
(remove(restaurants.begin(), restaurants.end(), remove_restaurant));

First of all, I think you'd much rather use a vector or list for this, that's what it has been designed for. But if you want to go this way, you could for example write a moveUp method:
void moveUp(int startIndex, int endIndex, string* array) {
for (int ii = startIndex; ii < endIndex; ++ii) {
array[ii] = array[ii + 1];
}
array[endIndex] = 0;
}

Related

Heap corruption detected in C++ after removing strings

When running this code I get an error as shown in the image below.
I've tried running it on GCC compiler and it worked fine. But when running it on Visual Studio on Windows this error appeared:
Debug Error!
Program: C:\Users\yudab\source\repos\Project2\Debug\Project2.exe
HEAP CORRUPTION DETECTED: after Normal block (#153) at 0x014FD2E0.
CRT detected that the application wrote to memory after end of heap buffer.
After some testing it seems as the error only appears after trying to delete the second word.
#include <cstring>
#include <string>
#pragma warning(disable : 4996)
#include <iostream>
using namespace std;
void delStr(char**& lexicon, int& lexSize, char word[]);
void printAll(char** lexicon, int lexSize);
void retract2dArr(char**& arr, int& size);
int main() {
char** lexicon = new char* [3];
lexicon[0] = new char[6]{ "hello" };
lexicon[1] = new char[5]{ "test" };
lexicon[2] = new char[6]{ "world" };
int size = 3;
char removeTest[5] = { "test" }; //The first word I want to remove from the list
char removeWorld[6] = { "world" }; //The second word I want to remove from the list
printAll(lexicon, size); //First prints the entire list
delStr(lexicon, size, removeTest); //Removes the first word
delStr(lexicon, size, removeWorld); //Removes the second word
printAll(lexicon, size); //Prints the list after deleting the words
return 0;
}
void delStr(char**& lexicon, int& lexSize, char word[]) {
bool toDelete = false;
for (int i = 0; i < lexSize; i++) {
if (strcmp(lexicon[i], word) == 0) {
toDelete = true;
for (; i < lexSize - 1; i++) {
strcpy(lexicon[i], lexicon[i + 1]);
}
}
}
if (toDelete == true) {
delete[] lexicon[lexSize - 1];
retract2dArr(lexicon, lexSize);
}
return;
}
void printAll(char** lexicon, int lexSize) {
for (int i = 0; i < lexSize; i++) {
cout << lexicon[i];
if (i != lexSize - 1) {
cout << " ";
}
}
cout << endl;
return;
}
void retract2dArr(char**& arr, int& size) {
size--;
char** newArr = new char* [size];
for (int i = 0; i < size; i++) {
*(newArr + i) = *(arr + i);
}
printAll(newArr, size);
delete[] arr;
arr = newArr;
return;
}
You can't strcpy one string to another
if (strcmp(lexicon[i], word) == 0) {
toDelete = true;
for (; i < lexSize - 1; i++) {
strcpy(lexicon[i], lexicon[i + 1]);
}
}
As length will be different for each strings.
Example:
lexicon[0] = new char[6]{ "hello" };
lexicon[1] = new char[5]{ "test" }; // length is 4
lexicon[2] = new char[6]{ "world" }; // length is 5
3rd string won't fit in 2nd string, it causes out of bound access.
As kiran Biradar pointed out, the strcpy is to blame here. Although instead of copying each word in the lexicon to the memory allocated for the previous word, it would probably be better to simply move the pointers back withing the lexicon array.
Try something like this for your delStr function:
void delStr(char**& lexicon, int& lexSize, char word[]) {
for (int i = 0; i < lexSize; i++) {
if (strcmp(lexicon[i], word) == 0) {
delete[] lexicon[i];
for (; i < lexSize - 1; i++) {
lexicon[i] = lexicon[i + 1];
}
retract2dArr(lexicon, lexSize);
}
}
}
P.S. You didnt need to use a toDelete flag, you could call teh retract2dArr function within the first if.

Unable to delete contents of dynamic array in C++

I've been beating my head against this one for awhile. In the deconstructor of my class, I have a for loop that is supposed to iterate through an array of objects and delete them. When I try though, I get a read access violation. The attached code is supposed to read info from two documents and use that to create Country objects.
#include "pch.h"
#include "CountryCatalogue.h"
#include "Country.h"
#include <iterator>
#include <map>
//imports for reading the files
#include <iostream>
#include <fstream>
CountryCatalogue::CountryCatalogue()
{
_maxSize = 10;
_curSize = 0;
_catalogue = new Country*[_maxSize];
}
CountryCatalogue::CountryCatalogue(std::string continentFileName, std::string countryFileName)
{
//block that opens the files and checks to make sure they can be read
//open up the files
std::ifstream inFile1;
std::ifstream inFile2;
//opening both text files and ensuring that the file is readable to the program
inFile1.open(continentFileName);
if (!inFile1) {
std::cout << "Unable to open file";
exit(1); // terminate with error
}
inFile2.open(countryFileName);
if (!inFile2) {
std::cout << "Unable to open file";
exit(1); // terminate with error
}
// read the continet file
// while there is still stuff to read in the file
std::string str;
while (!inFile1.eof())
{
std::string Country, Cont;
//reading lines from file and assigning to variables
std::getline(inFile1, Country);
std::getline(inFile1, Cont);
//mapping to variables read from file
_countryContinent.insert(std::pair<std::string, std::string>(Country, Cont));
_curSize++;
}
//closing file after use
inFile1.close();
//creating array
_catalogue = new Country*[_curSize+2];
//resetting size to zero for later itteration
_curSize = 0;
// read the country file
// while there is still stuff to read in the file
while (!inFile2.eof())
{
std::string name, POP, AREA;
int pop;
double area = 0.0;
std::getline(inFile2, name);
std::getline(inFile2, POP);
std::getline(inFile2, AREA);
if (!POP.empty() && POP[POP.length() - 1] == '\n') {
POP.erase(POP.length() - 1);
}
if (!AREA.empty() && AREA[AREA.length() - 1] == '\n') {
AREA.erase(AREA.length() - 1);
}
pop = std::stoi(POP);
area = std::stod(AREA);
//creating iterator to search through mapped values
std::map<std::string, std::string>::iterator it;
it = _countryContinent.find(name);
//creating empty string variable to store continent
std::string cont;
//using value found by iterator to make continent string
//ensuring value isn't the end valueof the map
if (it != _countryContinent.end()){
cont = it->second;
}
//std::cout << name << pop << area << cont << std::endl;
// add the country to the catalogue
addCountry(name, pop, area, cont);
}
}
CountryCatalogue::~CountryCatalogue() {
/*for (int i = 0; i < _curSize; i++){
delete _catalogue[i];
std::cout << "deleted" << i << std::endl;
}*/
delete[] _catalogue;
}
void CountryCatalogue::addCountry(std::string name, int pop, double area, std::string cont) {
//std::cout << name << pop << area << cont << std::endl;
//std::cout << _curSize << std::endl;
Country* toAdd = new Country(name, pop, area, cont);
if (_curSize == _maxSize) {
expandCapacity();
}
//adding country object to array
_catalogue[_curSize] = toAdd;
//adding to _curSize for next iteration
_curSize++;
}
void CountryCatalogue::printCountryCatalogue() {
std::string s;
/*for (int i = 0; i < _curSize; i++) {
s += _catalogue[i]->to_string() + "\n";
}*/
std::cout << _curSize << std::endl;
}
void CountryCatalogue::expandCapacity() {
//doubling array size
_maxSize = _maxSize * 2;
//creating pointer to new array of new size
Country** newCatalogue = new Country*[_maxSize];
//copying old array into new
for (int i = 0; i < _curSize; i++) {
newCatalogue[i] = _catalogue[i];
}
//deleting old array
delete[] _catalogue;
//making _catalogue point to newCatalogue
_catalogue = newCatalogue;
}
UPDATE:
What my code is supposed to do is get information from text files and create objects using that data. I am required to use an array instead of a vector. The code runs fine and I can create the country object. The issue is that I cannot add the created object to the _catalogue array, as I cannot delete it afterwards. When I attempt to iterate through the array, I receive a message saying Heap Corruption was detected.
Your problem is due to this line
_catalogue = new Country*[_curSize+2];
in the second constructor. You have forgotten to update _maxSize so you have a mismatch between _maxSize and the real allocated amount of memory.
Try:
_maxSize = _curSize+2;
_catalogue = new Country*[_maxSize];
You created _catalogue as a dynamic array.
To release the memory allocated for arrays of elements using new TYPE[SIZE] the syntax is:
delete[] _catalogue;
Loop is Needed for deleting memory allocated for Matrix elements. For example
int matrix = new int[rows][cols];
for (int i = 0; i < rows; ++i)
delete [] matrix[i];
The array is deleted row by row.

Return struct element from vector c++

I'm new to C++ and I'm trying to return a struct from a vector of structs by using 2 search criteria.
The function find_city is returning me everything from the defined range, regardless of whether it exists inside the vector of struct.
Here's my code:
struct cityLoc
{
int hRange;
int vRange;
int cityCode;
string cityName;
};
vector<cityLoc> cl1;
// the vector has already been preloaded with data
// function to return my struct from the vector
cityLoc find_city(int hRange, int vRange)
{
for (size_t i = 0; i < cl1.size(); i++)
{
if ((cl1[i].hRange = hRange) && (cl1[i].vRange = vRange))
{
return cl1[i];
}
}
}
int main()
{
for (int i = 0; i < 8; i++)
{
for (int j = 0; j <= 8; j++)
{
cityLoc this_city;
this_city = find_city(i, j);
cout << this_city.hRange << ", " << this_city.vRange << endl;
}
}
return 0;
}
Also, aside from this question, I was previously looking into std::find_if and didn't understand it. If I have the following code, what is the output? How do I modify it such that it returns a struct?
auto it = find_if(cl1.begin(), cl1.end(), [](cityLoc& cl) { return cl.hRange == 1; } );
You have a bug here:
if ((cl1[i].hRange = hRange) && (cl1[i].vRange = vRange))
Those = are assignments, not comparisons! Please enable compiler warnings and you won't be hurt by such obvious typos in future.
std::find_if will return the iterator to the found struct entry if it is successful, std::vector::end() otherwise. So, you should first validate the returning iterator if it is valid or not.
For example:
auto it = std::find_if( cl1.begin(), cl1.end(),
[](const cityLoc& cl) { return cl.hRange == 1; } );
if ( it == cl1.end() )
{
// ERROR: Not found! Return error code etc.
return -1;
}
// And, if found, process it here...
std::cout << it->hRange << '\n';
std::cout << it->vRange << '\n';
The criteria (predicate) part in std::find_if is a lambda expression.

Counting number of occurrences of a string in a Hash Table

I am writing my own HashTable class in C++ and need to output to the user the number of occurrences of each string in the table. For example, if this is the input: testing, 1, 2, testing, and this is the hash table (done with chaining, and node pointers):
[0]->testing, testing
[1]->2
[2]->1
this would be the output to the user (the count, followed by the word):
2 testing
1 2
1 1
The problem I'm having is how to keep track of how many of each word is in the Hash Table, or how to find it. I started with this question but was unable to implement another array in my code.
I also tried the solution in this question, but it didn't work because of my use of pointers/chained hashing.
My question is, do I need to use a separate array of strings to keep track of what's already been used, or is there an easy way to recursively go through each index of the Hash Table and print out the number of occurrences of each string? I think I need to accomplish this in either my insert function or my printData function.
For reference, here is my code:
HashTable.h:
#include <string>
#include <iostream>
using namespace std;
struct Entry {
string word;
Entry* next;
};
class HashTable {
public:
HashTable();
HashTable(int);
int hash(string);
void insert(string);
void printData();
int getCapacity() const;
private:
//Member variables
int CAPACITY; // The initial capacity of the HashTable
Entry **data; // The array to store the data of strings (Entries)
};
HashTable.cpp:
#include "HashTable.h"
HashTable::HashTable()
{
CAPACITY = 0;
data = new Entry*[0];
}
HashTable::HashTable(int _cap)
{
CAPACITY = _cap;
data = new Entry*[_cap];
for (int i = 0; i < CAPACITY; i++) {
data[i] = new Entry;
data[i]->word = "empty";
data[i]->next = nullptr;
}
}
int HashTable::hash(string key)
{
int hash = 0;
for (unsigned int i = 0; i < key.length(); i++) {
hash = hash + (int)key[i];
}
return hash % CAPACITY;
}
void HashTable::insert(string entry)
{
int index = hash(entry);
if (data[index]->word == "empty") {
data[index]->word = entry;
} else {
Entry* temp = data[index];
Entry* e = new Entry;
e->word = entry;
e->next = nullptr;
while (temp->next != nullptr) {
temp = temp->next;
}
temp->next = e;
}
}
void HashTable::printData()
{
for (int i = 0; i < CAPACITY; i++) {
if (data[i]->next != nullptr) {
while(data[i]->next != nullptr) {
cout << data[i]->word << " -> ";
data[i] = data[i]->next;
}
cout << data[i]->word << endl;
} else {
cout << data[i]->word << endl;
}
}
}
int HashTable::getCapacity() const
{
return CAPACITY;
}
NOTE: I can't use any function/data structure from the standard C++ Library.
I only see two options here
Traverse entire linked list to count occurances. Use a map< string, int > to count occurances for each string.
You should make your linked list sorted. So when you insert a new node, you will insert it in its exact place. You can use strcmp for comparison. This way you can count every word exactly in one traverse and using just one integer variable, but your insert time and complexity will increase.

Find char* element in array of char* in C++

I'm trying to write function that search for char * element in array of char* and the function start check this element, if the element exist in the array I will have "found", if not it should be "inserted" and the element added to the array.
I wrote this code but I cannot know how to try it, the program always gives me exception, what can I do to check the element in my pointer array?
void checkFunction(char*myArray[], char *element,bool flag)
{
for (int i = 0; i < strlen(*myArray) ; ++i)
{
if (myArray[i] == element)
{
flag = true;
}
}
*myArray = element;
flag = false;
if (flag)
{
cout << "Found" << endl;
}
else
{
cout << "Inserted" << endl;
}
}
C++ Way
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(int argc, const char * argv[]) {
vector<string> myStrings { "One", "Two", "Three" };
// std::find() finds the first element that matches a value
auto it = find(begin(myStrings), end(myStrings), "Twooo");
if (it != end(myStrings)) {
cout << "We found this string; do something..." << endl;
}
}
Few remarks regarding your function:
1.Why do you need the third parameter bool flag, instead of having it as local variable?
2.If you want to expand an array you should copy the old to a newly allocated and then add the new element, you can not just do: *myArray = element;
3.If you want to iterate through the array length/ size, instead of:
for (int i = 0; i < strlen(*myArray) ; ++i)
pass an additional parameter to your function, that indicates the number of elements in the array.
With std::string and std::vector you could do something like:
void check_insert (std::vector<std::string>& v, std::string& c) {
for (auto i = 0; i < v.size(); ++i) {
if (v[i] == c) {
std::cout << "Found!\n";
return;
}
}
v.push_back(c);
std::cout << "Inserted!\n";
}