Error : Display duplicated results via pointer - c++

Goal state: I'm supposed to display a result where by randomized e.g. Set S = {dog, cow, chicken...} where randomized size can be 1-12 and animals cannot be replicated so once there is cow, there cannot be another cow in Set S anymore.
Error: I've been displaying a correct randomized size of 1-12. However I have duplicated animals even though I tried to check whether the animal exist in set S before I insert it into Set S.
UPDATE: I couldnt get it to run after the various updates by stackoverflow peers.
Constraints: I have to use pointers to compare with pointers - dynamically.
"Important Note
All storages used for the arrays should be dynamically created; and delete them when
they are no longer needed.
When accessing an element of the array, you should access it via a pointer, i.e. by
dereferencing this pointer. Using the notation, for example set [k] or *(set + k)
accessing to the kth element of the set is not allowed."
Do hope to hear your advice, pals!
Best regards,
MM
/*
MarcusMoo_A2.cpp by Marcus Moo
Full Time Student
I did not pass my assignment to anyone in the class or copy anyone’s work;
and I'm willing to accept whatever penalty given to you and
also to all the related parties involved
*/
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <ctime>
using namespace std;
/* Global Declaration */
const int MAX = 12; // 12 animals
const int MAXSTR = 10;
typedef char * Element;
static Element UniversalSet [MAX] = {"Rat", "Ox", "Tiger", "Rabbit", "Dragon",
"Snake", "Horse", "Sheep", "Monkey", "Rooster", "Dog", "Pig"};
/* Functions */
// Construct a set
void option0(int); // Menu Option 0
void constructSet (Element *, int); // Construct a set
bool checkElement (Element *, Element *, int); // Check element for replicates
int main()
{
// Declarations
int mainSelect;
int size=rand()%12+1; // Random construct
srand (time(NULL)); // Even better randomization
cout << "Welcome to MARCUS MOO Learning Center" << endl;
do
{
cout << "0. An example of set" << endl;
cout << "1. Union" << endl;
cout << "2. Intersection" << endl;
cout << "3. Complement" << endl;
cout << "4. Subset of" << endl;
cout << "5. Equality" << endl;
cout << "6. Difference " << endl;
cout << "7. Distributive Law" << endl;
cout << "9. Quit" << endl;
cout << endl;
if (mainSelect==0)
{
option0(size);
}
cout << "Your option: ";
cin >> mainSelect;
cout << endl;
} while(mainSelect!=9);
return 0;
}
/* Functions */
// Option 0 - An example of set
void option0 (int size)
{
// Mini Declaration
int again;
Element *S;
do
{
cout << "Here is an example on set of animals" << endl;
cout << endl;
// Build set S
constructSet (S,size);
// Display set S
Element *S = &S[0];
cout << "Set S = {";
for (int i = 0; i < size; i++)
{
if (i!=size)
{
cout << *S
<< ", ";
}
else
{
cout << *S
<< "}"
<< endl;
}
S++;
}
cout << endl;
cout << "Note that elements in S are distinct are not in order" << endl;
cout << endl;
// Option 0 2nd Part
cout << "Wish to try the following operations?" << endl;
cout << "1. Add an element to the set" << endl;
cout << "2. Check the element in the set" << endl;
cout << "3. Check the cardinality" << endl;
cout << "9. Quit" << endl;
cout << endl;
cout << "Your choice: ";
cin >> again;
} while (again!=9);
}
// Construct a set
void constructSet (Element *set, int size)
{
// Declarations
Element *ptrWalk;
ptrWalk = &set[0];
int randomA=0;
for (int i = 0;i<size;i++)
{
bool found = true;
while (found)
{
randomA = rand()%MAX; // avoid magic numbers in code...
*ptrWalk = UniversalSet [randomA];
// Ensure no replicated animals in set S
found = checkElement (ptrWalk, set, i);
}
set=ptrWalk;
set++;
}
}
bool checkElement (Element *ptrWalk, Element *set, int size)
{
for (int j=0; j<size;j++)
{
if (ptrWalk==&set[j])
{
return true;
}
}
return false;
}

You have 2 different major problems in your code. First has already be given by Federico: checkElement should return true as soon as one element was found. Code should become simply (but please notice the < in j<size):
bool checkElement (char *ptrWalk, int size)
{
for (int j=0; j<size;j++)
{
if (ptrWalk==S[j])
{
return true;
}
}
return false;
}
The second problem is that you should not search the whole array but only the part that has already been populated. That means that in constructSet you should call checkElement(ptrWalk, i) because the index of current element is the number of already populate items. So you have to replace twice the line
found = checkElement (*ptrWalk, size);
with this one
found = checkElement (*ptrWalk, i);
That should be enough for your program to give expected results. But if you want it to be nice, there are still some improvements:
you correctly declared int main() but forgot a return 0; at the end of main
you failed to forward declare the functions while you call them before their definition (should at least cause a warning...)
you make a heavy use of global variables which is not a good practice because it does not allow easy testing
your algorithms should be simplified to follow the Dont Repeat Yourself principle. Code duplication is bad for future maintenance because if forces to apply code changes in different places and omission to do so leads to nasty bugs (looks like this is bad but I've already fixed it - yes but only in one place...)
constructSet could simply be:
// Construct a set
void constructSet (Element *set, int size)
{
// Declarations
//Element *ptrBase;
voidPtr *ptrWalk;
ptrWalk = &set[0];
int randomA=0;
for (int i = 0;i<size;i++)
{
bool found = true;
while (found) {
randomA = rand()%MAX; // avoid magic numbers in code...
*ptrWalk = UniversalSet [randomA];
// Ensure no replicated animals in set S
found = checkElement (*ptrWalk, i);
}
ptrWalk++;
}
}

Main problem is that 'break' is missing in checkElement() once it finds the element. If you do not break the loop, it will compare with other indices and overwrite the 'found' flag.
if (ptrWalk==S[j])
{
found = true;
break;
}
Also, use ptrWalk as temporary variable to hold the string. Add the string to S only after you make sure that it is not present already.
void constructSet (Element *set, int size)
{
// Declarations
//Element *ptrBase;
Element ptrWalk;
//ptrWalk = &set[0];
int randomA=0;
int randomB=0;
bool found = false;
for (int i = 0;i<size;i++)
{
randomA = rand()%12;
ptrWalk = UniversalSet [randomA];
// Ensure no replicated animals in set S
found = checkElement (ptrWalk, i);
if (found==true)
{
do
{
// Define value for S
randomB = rand()%12;
ptrWalk = UniversalSet [randomB];
found = checkElement (ptrWalk, i);
} while(found==true);
S[i] = UniversalSet [randomB];
//ptrWalk++;
}
else
{
// Define value for S
S[i] = UniversalSet [randomA];
//ptrWalk++;
}
}
}
You need to optimize your code by removing unnecessary variables and making it less complex.

I have fixed this with the guidance of my C++ lecturer! You guys may take a reference from this to solve your pointers to pointers dilemma next time! Cheers!
/*
MarcusMoo_A2.cpp by Marcus Moo
Full Time Student
I did not pass my assignment to anyone in the class or copy anyone’s work;
and I'm willing to accept whatever penalty given to you and
also to all the related parties involved
*/
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <ctime>
using namespace std;
/* Global Declaration */
const int MAX = 12; // 12 animals
const int MAXSTR = 10;
typedef char * Element;
static Element UniversalSet [MAX] = {"Rat", "Ox", "Tiger", "Rabbit", "Dragon",
"Snake", "Horse", "Sheep", "Monkey", "Rooster", "Dog", "Pig"};
/* Functions */
// Construct a set
void option0(int); // Menu Option 0
void constructSet (Element *, int); // Construct a set
bool checkElement (Element, Element *, int); // Check element for replicates
// This function is to get a random element
// with storage allocated
Element getAnElement ()
{
Element *p = &UniversalSet [0];
int k = rand () % MAX;
for (int i = 0; i < k; i++)
++p;
Element e = new char [MAXSTR];
strcpy (e, *p);
return e;
}
int main()
{
// Declarations
int mainSelect;
int size=rand()%12; // Random construct
srand (time(NULL)); // Even better randomization
cout << "Welcome to MARCUS MOO Learning Center" << endl;
do
{
cout << "0. An example of set" << endl;
cout << "1. Union" << endl;
cout << "2. Intersection" << endl;
cout << "3. Complement" << endl;
cout << "4. Subset of" << endl;
cout << "5. Equality" << endl;
cout << "6. Difference " << endl;
cout << "7. Distributive Law" << endl;
cout << "9. Quit" << endl;
cout << endl;
if (mainSelect==0)
{
option0(size);
}
cout << "Your option: ";
cin >> mainSelect;
cout << endl;
} while(mainSelect!=9);
return 0;
}
/* Functions */
// Option 0 - An example of set
void option0 (int size)
{
// Mini Declaration
int again;
Element *S;
// You need to assign storage
S = new Element [MAX];
for (int i = 0; i < MAX; i++)
S [i] = new char [MAXSTR];
do
{
cout << "Here is an example on set of animals" << endl;
cout << endl;
// Build set S
constructSet (S,size);
// Display set S
Element *p = &S[0]; // Change to p
cout << "Set S = {";
for (int i = 0; i < size; i++)
{
if (i!=size-1)
{
cout << *p
<< ", ";
}
else
{
cout << *p
<< "}"
<< endl;
}
p++;
}
cout << endl;
cout << "Note that elements in S are distinct are not in order" << endl;
cout << endl;
// Option 0 2nd Part
cout << "Wish to try the following operations?" << endl;
cout << "1. Add an element to the set" << endl;
cout << "2. Check the element in the set" << endl;
cout << "3. Check the cardinality" << endl;
cout << "9. Quit" << endl;
cout << endl;
cout << "Your choice: ";
cin >> again;
} while (again!=9);
}
// Construct a set
void constructSet (Element *set, int size)
{
// Declarations
Element *ptrWalk;
ptrWalk = &set[0];
int randomA=0;
Element temp = new char [MAXSTR];
for (int i = 0;i<size;i++)
{
bool found = true;
while (found)
{
// randomA = rand()%MAX; ..
temp = getAnElement ();
// Ensure no replicated animals in set S
found = checkElement (temp, set, i);
}
// set=ptrWalk;
// set++;
strcpy (*ptrWalk, temp);
++ptrWalk;
}
}
bool checkElement (Element ptrWalk, Element *set, int size)
{
Element *p = &set[0];
for (int j=0; j<size;j++)
{
if (strcmp (ptrWalk, *p) == 0)
{
return true;
}
p++;
}
return false;
}

Related

C++ Array values being altered at element 4 after throwing exception

The requirements for the program state that the try/catch must be placed in the main.cpp as below:
cout << "printing the array element by element using: int getElement(int);" << endl;
cout << "(going one too far to test out of range)" << endl;
for(int i=0; i<=LISTSIZE; i++){
try{
elementResult = mylist.getElement(i);
cout << elementResult << endl;
} catch(int e){
cout << "Error: Index out of range." << endl;
}
}
cout << endl;
When it accesses the method:
int MyList::getElement(int passedIndex){
if((passedIndex < 0) || (passedIndex > length -1)){
throw 0;
}
return array[passedIndex];
}
It doesn't seem to matter which variation of throwing I use, my array gets destroyed afterward. It works fine if it stays within bounds, or I work it to not throw from the method (doing the error checking elsewhere), but the requirements state that it has to be that way, so I must be missing something. Full code below:
main.h:
#ifndef MAIN_H
#define MAIN_H
/***********************************
* DO NOT MODIFY THIS FILE OTHER THAN
* TO ADD YOUR COMMENT HEADER
***********************************/
#include <iostream> /* cout, endl */
#include "mylist.h"
#include <stdexcept>
#define LISTSIZE 10
using std::cout;
using std::endl;
int elementResult;
#endif /* MAIN_H */
main.cpp:
#include "main.h"
int main(int argc, char** argv) {
/***********************************
* DO NOT MODIFY THIS FILE OTHER THAN
* TO ADD YOUR COMMENT HEADER AND
* UNCOMMENT THINGS AS YOU COMPLETE
* THE FUNCTIONALITY OF YOUR LIST OBJECT
***********************************/
/* This will create a "list" of size LISTSIZE
* and initialize it to all zeros */
cout << "create and initialize mylist" << endl;
MyList mylist(LISTSIZE);
mylist.printArray();
cout << endl;
/* This will set the list to all 50 */
cout << "set mylist to all 50" << endl;
mylist.setArray(50);
mylist.printArray();
cout << endl;
/* This will fail and set the array to the
* default random 1-10 values */
cout << "attempt to set to random numbers -2 to 4" << endl;
mylist.setRandom(-2,4);
mylist.printArray();
cout << endl;
/* This will fail and set the array to the
* default random 1-10 values */
cout << "attempt to set to random numbers 4 to 4" << endl;
mylist.setRandom(4,4);
mylist.printArray();
cout << endl;
/* This will succeed and set the array to the
* random 1-100 values */
cout << "attempt to set to random numbers 1 to 100" << endl;
mylist.setRandom(1,100);
mylist.printArray();
cout << endl;
/* This will succeed and set the array to the
* random 500-1000 values */
cout << "attempt to set to random numbers 500 to 1000" << endl;
mylist.setRandom(1000,500);
mylist.printArray();
cout << endl;
/* These next two sets will succeed and set the 1st and last
* elements to 1000 and 2000 respectively */
if(mylist.setElement(1000, 0)){
cout << "Element Set" << endl;
} else {
cout << "Element NOT Set" << endl;
}
if(mylist.setElement(2000, LISTSIZE-1)){
cout << "Element Set" << endl;
} else {
cout << "Element NOT Set" << endl;
}
mylist.printArray();
cout << endl;
/* These next two sets will fail and leave the array unmodified */
if(mylist.setElement(9999, -1)){
cout << "Element Set" << endl;
} else {
cout << "Element NOT Set" << endl;
}
if(mylist.setElement(9999, LISTSIZE)){
cout << "Element Set" << endl;
} else {
cout << "Element NOT Set" << endl;
}
mylist.printArray();
cout << endl;
cout << "Testing new and/or modified code..." << endl << endl;
cout << "printing the array element by element using: int getElement(int);" << endl;
cout << "(going one too far to test out of range)" << endl;
for(int i=0; i<=LISTSIZE; i++){
try{
elementResult = mylist.getElement(i);
cout << elementResult << endl;
} catch(int e){
cout << "Error: Index out of range." << endl;
}
}
cout << endl;
mylist.printArray();
cout << "attempting to get element 4000 using: int getElement(int);" << endl;
try{
cout << mylist.getElement(4000) << endl;
} catch(int e){
cout << "Error: Index out of range." << endl;
}
cout << endl;
cout << "printing the array element by element using: int getElement(int,int*);" << endl;
cout << "(going one too far to test out of range)" << endl;
for(int i=0; i<=LISTSIZE; i++){
if(mylist.getElement(i, &elementResult)){
cout << elementResult << endl;
} else {
cout << "Error: Index out of range." << endl;
}
}
cout << endl;
cout << "attempting to get element 4000 using: int getElement(int,int*);" << endl;
if(mylist.getElement(4000, &elementResult)){
cout << elementResult << endl;
} else {
cout << "Error: Index out of range." << endl;
}
return 0;
}
mylist.h:
#ifndef MYLIST_H
#define MYLIST_H
#include <iostream> /* cout, endl */
#include <stdlib.h> /* srand, rand, atoi */
#include <time.h> /* time */
#include <stdexcept>
// you can add libraries if you need them, but you shouldn't
// DO NOT MODIFY THESE DEFINES
#define RMIN 1
#define RMAX 10
#define DEFAULT_SIZE 10
using std::cout;
using std::endl;
class MyList {
public:
// DO NOT MODIFY THESES NEXT TWO
MyList(int); // constructor
~MyList(); // destructor
int getElement(int);
void setArray(int);
bool setElement(int, int);
void setRandom(int, int);
void printArray();
bool getElement(int, int*);
private:
// these are the only attributes allowed
// DO NOT ADD OR MODIFY THEM
int length;
int *array;
};
#endif //MYLIST_H
mylist.cpp:
#include "mylist.h"
// constructor
MyList::MyList(int size) {
srand(time(NULL)); // call only once!
if(size < 1){
size = DEFAULT_SIZE;
}
MyList::length = size;
MyList::array = new int(size);
setArray(0);
}
// destructor
MyList::~MyList() {
//delete[] MyList::array;
}
void MyList::printArray() {
cout << "[";
for (int i = 0; i < length; i++){
if (i == length - 1){
cout << array[i];
}else{
cout << array[i] << " ";
}
}
cout << "]" << endl;
}
void MyList::setArray(int setArrayTo){
for (int i = 0; i < length; i++){
MyList::array[i] = setArrayTo;
}
}
void MyList::setRandom(int numOne, int numTwo){
bool isValidRandom = true;
int randMin, randMax;
if((numOne < RMIN) || (numTwo < RMIN) || (numOne == numTwo)){ isValidRandom = false; }
if(isValidRandom == true){
if(numTwo < numOne){
randMin = numTwo;
randMax = numOne;
} else {
randMin = numOne;
randMax = numTwo;
}
} else {
randMin = RMIN;
randMax = RMAX;
}
for(int i = 0;i < length; i++){
MyList::array[i] = rand() % randMax + randMin;
}
}
bool MyList::setElement(int passedValue, int arrayIndex){
bool isInRange = true;
if ((arrayIndex < 0)||(arrayIndex > length - 1)){
isInRange = false;
}
if (isInRange == true){
MyList::array[arrayIndex] = passedValue;
}
return isInRange;
}
int MyList::getElement(int passedIndex){
if((passedIndex < 0) || (passedIndex > length -1)){
throw 0;
}
return array[passedIndex];
}
bool MyList::getElement(int passedIndex, int *iPtr){
bool isItValid = true;
if((passedIndex >= 0) && (passedIndex < length)){
*iPtr = MyList::array[passedIndex];
} else {
isItValid = false;
}
return isItValid;
}
Output

Semantic error in the selection condition of the type of LED lamps

I have a class of light bulbs. There are methods and constructors in this class. There is even a destructor) The problem is that I have to determine and display information about class members with type "n" in the TEST() method (LED lamps).
To implement this task, he developed the gettype() method, which returns the type of an object, and, in fact, the TEST() method, which displays information about light bulbs.
The problem is that nothing works for me. I tried a lot of things, but it doesn’t work out for me to implement this task. I'm new to programming (
Code:
#include <iostream>
using namespace std;
class lamp
{
public:
// methods
void TEST(void);
char* gettype (void);
void INIT(void);
void SHOW(void);
// construcrors
lamp();
lamp(const char *t, int powe, const char *c, double cos);
lamp(const lamp & obj);
// destructor
~lamp();
private:
// data
char type[100]; // LED, energy-saving or incandescent lamp
int power; // LED lamp - "n"
char color[100];
double cost;
};
lamp::lamp() {
cout << "This object was created in the default constructor.\n";
strcpy(type, "");
power = 0;
strcpy(color, "");
cost = 0;
}
lamp::lamp(const char *t, int powe, const char *c, double cos) {
cout << "This object was created in the constructor with parameters.\n";
strcpy(type, t); //*t
power = powe;
strcpy(color, c); //*c
cost = cos;
}
lamp::lamp(const lamp & obj) {
cout << "This object was created in the copy constructor.\n";
strcpy(type, obj.type);
power = obj.power;
strcpy(color, obj.color);
cost = obj.cost;
}
lamp::~lamp() {
cout << "Deletion of object by destructor.\n";
}
void lamp::SHOW(void) {
cout << "Lamp Information:\n";
cout << "\nType > " << type;
cout << "\nPower > " << power;
cout << "\nColor > " << color;
cout << "\nCost > " << cost << endl;
}
void lamp::INIT(void) {
cout << "Enter lamp information:\n";
cout << "\nType (if LED, then n) > "; cin >> type;
cout << "\nPower > "; cin >> power;
cout << "\nColor > "; cin >> color;
cout << "\nCost > "; cin >> cost;
}
char* lamp::gettype (void) {
return type;
}
void lamp::TEST(void) {
cout << "\nType > " << type;
cout << "\nPower > " << power;
cout << "\nColor > " << color;
cout << "\nCost > " << cost << endl;
}
void main() {
setlocale(0, "");
// default constructor for 1 class instance
lamp l1;
cout << "Entering data for the first product." << endl;
l1.INIT();
// constructor with parameters for 2 class instances
cout << endl << "Information about the second object: \n";
lamp l2("n", 950, "yellow", 1580);
// copy constructor for the third object
cout << endl << "Information about the third object: \n";
lamp l3(l2);
// Derived information about all the lamps using the method SHOW
l1.SHOW();
l2.SHOW();
l3.SHOW();
// I create an array of two objects using the default constructor
lamp la[2];
I enter data into an array of objects using the method INIT
cout << "Fill an array of objects with 2 elements." << endl;
for(int i = 0; i < 2; i++) {
la[i].INIT();
}
// I output data from an array of objects using the method SHOW
cout << "Showing items." << endl;
for (int i = 0; i < 2; i++) {
la[i].SHOW();
}
// looking for and displaying information about LED lamps
cout << "Search and display information about LED lamps." << endl;
for (int i = 0; i < 3; i++) {
if (la[i].gettype() == "n") {
cout << endl << " lamp number : " << (i + 1) << endl;
la[i].TEST();
cout << endl;
}
}
system("pause");
}
There are several errors in your code:
strcpy is included in <cstring> which is missed. You need to add it in the beginning:
#include <cstring>
main() function should be declared as int main() and you need to add a return statement
int main() {
//YOUR CODE HERE
return 0;
}
You missed a comment sign at line 104
lamp la[2];
//I enter data into an array of objects using the method INIT
cout << "Fill an array of objects with 2 elements." << endl;
After fixed, your code should be able to run.

C++ changing object in vector doesn't work

I want to implement a trie using a vector to store the nodes but somehow my insert method doesn't work. I've managed to build the trie data structure using a different implementation but I would like to understand why my current implementation doesn't work.
Works (not index based storing of childs/references):
struct Trie {
struct Trie *references[26];
bool end; //It is true if node represents end of word.
};
DOESN'T WORK (index based storing of childs/references):
struct node {
int references[26] = {0};
bool end;
};
It doesn't work because of a faulty insert function.
void insert_word(string s){
node *current_node = &trie[0];
// current_node->references[4] = 9999 WORKS! Node in Trie is UPDATED
for(int i=0;i<s.size();i++){
print_trie();
int letter_num = static_cast<int>(tolower(s[i])) - static_cast<int>('a');
int next_index = current_node->references[letter_num];
cout << "letter num: " << letter_num << " next index: " << next_index << endl;
if(next_index == 0){
node new_node;
trie.push_back(new_node);
current_node->references[letter_num] = trie.size()-1; // DOESN'T WORK! Node in Trie is NOT UPDATED
cout << "new value: ";
for(auto c:current_node->references)
cout << c << " ";
cout << endl;
cout << "in for" << endl;
print_trie();
current_node = &trie.back();
} else{
current_node = &trie[next_index];
}
}
current_node->end = true;
}
The problem is that when I access current_node as a reference to an object ob the trie vector and I change its value. The object/node in the trie vector isn't always updated. It works in the second line but further down it somehow stops working. I would like to understand why.
Here is a short debug program I wrote to simplify the problem. Here everything seems to work fine.
n1.references[0] = 1;
n2.references[0] = 2;
n3.references[0] = 3;
trie.push_back(n1);
trie.push_back(n2);
trie.push_back(n3);
node *n = &trie[0];
n->references[0] = 10; // Tree is updated properly
n = &trie[1];
n->references[0] = 11; // Tree is updated properly
Can you help me understand why the insert function doesn't work properly?
EDIT: Minimal working example
#include <vector>
#include <string>
#include <iostream>
using namespace std;
struct node
{
int num_words;
int references [26] = {0};
bool end;
};
vector<node> trie;
int n;
void print_trie(){
cout << "#### NEW PRINT TRIE ##### " << endl;
for(int i=0;i<trie.size();i++){
cout << "node " << i << ": ";
for(int j=0;j<26;j++)
cout << trie[i].references[j] << " ";
cout << endl;
}
}
void insert_word(string s){
node *current_node = &trie[0];
// current_node->references[4] = 9999 WORKS! Node in Trie is UPDATED
for(int i=0;i<s.size();i++){
print_trie();
int letter_num = static_cast<int>(tolower(s[i])) - static_cast<int>('a');
int next_index = current_node->references[letter_num];
cout << "letter num: " << letter_num << " next index: " << next_index << endl;
if(next_index == 0){
node new_node;
trie.push_back(new_node);
current_node->references[letter_num] = trie.size()-1; // DOESN'T WORK! Node in Trie is NOT UPDATED
cout << "new reference value of node: ";
for(auto c:current_node->references)
cout << c << " ";
cout << endl;
current_node = &(trie[trie.size()-1]);
} else{
current_node = &trie[next_index];
}
}
current_node->end = true;
}
int main()
{
node root;
trie.push_back(root);
insert_word("hallohallo");
return 0;
}
Anytime a std::vector<T> undergoes a resizing operation all iterators and pointers to elements are invalidated. Using your mcve as an example of where this goes off the rails, consider the marked lines:
void insert_word(string s){
node *current_node = &trie[0]; // **HERE
for(int i=0;i<s.size();i++){
print_trie();
int letter_num = static_cast<int>(tolower(s[i])) - static_cast<int>('a');
int next_index = current_node->references[letter_num];
cout << "letter num: " << letter_num << " next index: " << next_index << endl;
if(next_index == 0){
node new_node;
trie.push_back(new_node); //** RESIZE
current_node->references[letter_num] = trie.size()-1;
cout << "new reference value of node: ";
for(auto c:current_node->references)
cout << c << " ";
cout << endl;
current_node = &(trie[trie.size()-1]); // **HERE
} else{
current_node = &trie[next_index]; // **HERE
}
}
current_node->end = true;
}
In each location marked with // **HERE, you're storing a pointer to an object hosted in your vector. but the line marked with // **RESIZE can (and will) resize via copy/move/etc the entire vector once the capacity is reached. This means current_node no longer points to a valid object, is a dangling pointer, but your code is none-the-wiser and marches on into undefined behavior.
There are a couple of ways to address this. You could reserve the capacity from inception if you know it ahead of time, but for a more robust solution don't use pointers to begin with. if you enumerate via index instead of pointer your solution becomes the following:
void insert_word(std::string s)
{
size_t idx = 0;
for(int i=0;i<s.size();i++){
print_trie();
int letter_num = static_cast<int>(tolower(s[i])) - static_cast<int>('a');
size_t next_index = trie[idx].references[letter_num];
std::cout << "letter num: " << letter_num << " next index: " << next_index << std::endl;
if(next_index == 0){
trie.emplace_back();
trie[idx].references[letter_num] = trie.size()-1;
std::cout << "new reference value of node: ";
for(auto c : trie[idx].references)
std::cout << c << ' ';
std::cout << std::endl;
idx = trie.size()-1;
} else{
idx = next_index;
}
}
trie[idx].end = true;
}
Notice how all instances of current_node have been replaced with trie[idx]. And changing the "current node" is now just a matter of changing the value of idx, which is relevant even when the underlying vector resizes.
that might be caused by type mismatch int is assigned size_t
try ... = (int)trie.size()-1
#include <vector>
#include <iostream>
using namespace std;
struct node{
int num_words;
int references [26] = {}; //........... int
bool end;
};
vector<node> trie;
int n;
void print_trie(){
cout << "#### NEW PRINT TRIE ##### " << endl;
for(int i=0;i<trie.size();i++){
cout << "node " << i << ": ";
for(int j=0;j<26;j++)
cout << trie[i].references[j] << " ";
cout << endl;
}
}
void insert_word(const string& s){
node *current_node = &trie[0];
// current_node->references[4] = 9999 WORKS! Node in Trie is UPDATED
for(int i=0;i<s.size();i++){
print_trie();
int letter_num = int(tolower(s[i]) - 'a');
int next_index = current_node->references[letter_num];
cout << "letter num: " << letter_num << " next index: " << next_index << endl;
if(next_index == 0){
node new_node;
trie.push_back(new_node);
current_node->references[letter_num] = (int)trie.size()-1; //....size_t DOESN'T WORK! Node in Trie is NOT UPDATED
cout << "new reference value of node: ";
for(auto c:current_node->references)
cout << c << " ";
cout << endl;
current_node = &(trie[trie.size()-1]);
} else{
current_node = &trie[next_index];
}
}
current_node->end = true;
}
int main()
{
node root;
trie.push_back(root);
insert_word("hallohallo");
return 0;
}

c++ vector of structs inside class

hello all i am working on a school prject called inventory inquisitor. the specifications are as follows:
enter image description here
so far i have created a class in which contains a struct and a vector of this struct.
all im trying to do so far is get the class to display the struct just to know it works but when i compile it and run it nothing happens. here is the code. excuse whatever rookie mistakes i have made i am very new with classes, and vectors. thanks you in advance!
//Inventory Inquisitor.cpp
#include <iostream>
#include <string>
#include <cctype> //for toupper
#include <fstream>
#include <vector>
using namespace std;
class Inventory
{
private:
struct item
{
string Description = " ";
double Quantity = 0;
double Wholesalescost = 0;
double Retailcost = 0;
string Dateadded = " ";
};
vector<item> Inv;
public:
void Display();
};
void Inventory::Display()
{
Inv[0].Description = "english";
Inv[0].Quantity = 1;
Inv[0].Wholesalescost = 100;
Inv[0].Retailcost = 200;
Inv[0].Dateadded = "3/8/2018";
cout << Inv[0].Description << endl;
cout << Inv[0].Quantity << endl;
cout << Inv[0].Wholesalescost << endl;
cout << Inv[0].Retailcost << endl;
cout << Inv[0].Dateadded << endl;
}
int main()
{
Inventory inst1;
inst1.Display();
}
You have to put something into the vector before accessing it:
// Create an item
item i;
i.Description = "english";
i.Quantity = 1;
i.Wholesalescost = 100;
i.Retailcost = 200;
i.Dateadded = 3/8/2018;
// The vector is empty, size() == 0
// Add it to the vector
Inv.push_back(i);
// Now the vector has 1 item, size() == 1
// Now you can print it
cout << Inv.at(0).Description << endl;
cout << Inv.at(0).Quantity << endl;
cout << Inv.at(0).Wholesalescost << endl;
cout << Inv.at(0).Retailcost << endl;
cout << Inv.at(0).Dateadded << endl;
According to your assignment, you will most likely change to function to print an existing item. You will have another function to add items to the vector.
void Inventory::Display(int index)
{
// Print an item already in the vector
if (index >= 0 && index < Inv.size()) {
cout << Inv.at(index).Description << endl;
cout << Inv.at(index).Quantity << endl;
cout << Inv.at(index).Wholesalescost << endl;
cout << Inv.at(index).Retailcost << endl;
cout << Inv.at(index).Dateadded << endl;
}
}

List-Search with recursion by using list library

int listRecSearch(list<int>list, const int data)
{
if (list.empty())
{
cout << "The number is not in the list, try again..." << endl;
return -1;
}
else if (list.back() == data)
{
// cout << "list.size(): " << list.size() << endl;
list.pop_back();//I needed the index begins from 0 instead of 1
return list.size();
}
else
{
// cout << "list.back(): " << list.back() << endl;
list.pop_back();
listRecSearch(list, data);
}
}
//funtion used
int main()
{
list<int>list = listGenerator(size);//generate a list with 20 random numbers.
cout << "Specify the element to be searched for: ";
cin >> data;
int position = listRecSearch(list, data);
if (position > -1)
cout << "\nFind the element at position: " << position << endl;
}
The function listRecSearch was able to display correct list.size() value and correct pop_back values. But once it returned, it always return a garbage value. I figured there were steps were still went through after return, but I can't see where and how.
There exists a code path which does not return a value. listRecSearch(list, data); should become return listRecSearch(list, data);.