Reusing a Pointer to a Class in a Loop - c++

In a program there is a pointer to a class object WordList *TheList;. WordList has subclasses WordDataList and WordDataDLinkList, so in a case statement we interpret which subclass to use and how to print out the information in the list. From what I understand in the specs, each case is supposed to declare TheList as a pointer of that type and use that, and then reclaim the memory at the end of the case so that it can be used in the next iteration of the loop. When I try something like:
while (true)
{
displayMenu();
cin>>selection;
switch(selection)
{
case '1':
TheList = new WordDataList;
TheList->parseIntoList(inf);
TheList->printIteratively();
delete TheList;
break;
case '2':
TheList = new WordDataList;
TheList->parseIntoList(inf);
TheList->printRecursively();
delete TheList;
break;
case '3':
TheList = new WordDataList;
TheList->parseIntoList(inf);
TheList->printPtrRecursively();
delete TheList;
break;
case '6':
cout<<"Goodbye"<<endl;
return 0;
default:
cout<<"I cannot understand "<<selection<<". Try again."<<endl;
break;
} // switch
} // while
Deleting the pointer makes it so after the first run through no data appears (Menu still comes up) and option 2 ends up seg faulting. I'm modifying code my professor gave, and when he had no delete call, and new WordDataList and parseIntoList before the loop it ran fine. Any suggestions?
Added:
I'm reinitializing TheList in each case because I'll be adding 4 and 5 that will use WordDataDLinkList. If it's a pointer to WordDataList from outside the case statement, how would I change it to WordDataDLinkList inside when I need to? My professor wrote WordDataList for us:
#include <sstream>
#include <iostream>
#include "WordDataList.h"
using namespace std;
WordDataList::WordDataList()
{ numWords=0; }
bool WordDataList::incMatch(string temp)
{ for(int i=0; i<numWords; i++) {
if (temp==TheWords[i].getWord()) {
TheWords[i].incCount();
return true;
}
}
return false;
}
void WordDataList::parseIntoList(ifstream &inf)
{ string temp;
while (inf >> temp)
if (!incMatch(temp) && numWords < 10) {
TheWords[numWords].setWord(temp);
TheWords[numWords++].setCount(1);
}
}
// Print the data iteratively
void WordDataList::printIteratively()
// void printObjectArrayIterator(WordData TheWords[], int numWords)
{
cout<<"--------------------------"<<endl;
cout<<"|Object Array Iterative|"<<endl;
cout<<"|Word Occurences |"<<endl;
cout<<"--------------------------"<<endl;
for(int i=0; i<numWords; i++)
cout<<" "<<TheWords[i]<<endl;
}
// Print the data recursively
void WordDataList::printRecursivelyWorker(int numWords)
//void printObjectArrayRecursive(WordData TheWords[], int numWords)
{if (numWords==1) {
cout<<"--------------------------"<<endl;
cout<<"|Object Array Recursive|"<<endl;
cout<<"|Word Occurences |"<<endl;
cout<<"--------------------------"<<endl;
cout<<" "<<TheWords[numWords-1]<<endl;
return;
}
printRecursivelyWorker(numWords-1);
cout<<" "<<TheWords[numWords-1]<<endl;
}
// Call worker function to print the data recursively
void WordDataList::printRecursively()
{ printRecursivelyWorker(numWords); }
// Print the data recursively with a pointer
void WordDataList::printPtrRecursivelyWorker(int numWords)
//void printObjectArrayPointerRecursive(WordData* TheWords, int numWords)
{if (!numWords)
{ cout<<"--------------------------"<<endl;
cout<<"|Object Array Pointer |"<<endl;
cout<<"|Word Occurences |"<<endl;
cout<<"--------------------------"<<endl;
return;
}
printPtrRecursivelyWorker(numWords-1);
cout<<" "<<*(TheWords+(numWords-1))<<endl;
}
// Call worker function to print the data recursively
void WordDataList::printPtrRecursively()
{ printPtrRecursivelyWorker(numWords); }

I think you are confused about something else. Why do you need to keep recreating the 'WordDataList' are the parse and print methods modifiying it?
If not, just create it once, and simply use the select to choose which print function to use if any.
I would also suggest putting each of the case execution statement sets into a closure, and adding some print outs or stepping through the debugger to see what is going on. Main guesses are that your 'new' is returning NULL such that you can't call its members properly OR destructor is bad.

Okay, so from what I can kindof tell: Options 1-3 should select a different subclass for your pointer TheList to hold. TheList is a pointer to your base class so that's good. What I think you need to do is new the appropriate subclass in each switch statement. I.E.
case '1': TheList = new WordDataDLinkList();
EDIT: if you intend to call a different version of each member function based off the classtype you are currently using, as in WordDataDLinkList::parseIntoList(inf), instead of WordDataList::parseIntoList(inf), try reading up on polymorphism

Related

Stack using arrays

If suppose i want to implement a stack in c++ using arrrays is it better to do it via making a structure or class for storing the location of head and stuff like that or should you implement in more of a hard code style like this -
#include <iostream>
using namespace std;
int stack[100], n=100, top=-1;
void push(int val) {
if(top>=n-1)
cout<<"Stack Overflow"<<endl;
else {
top++;
stack[top]=val;
}
}
void pop() {
if(top<=-1)
cout<<"Stack Underflow"<<endl;
else {
cout<<"The popped element is "<< stack[top] <<endl;
top--;
}
}
void display() {
if(top>=0) {
cout<<"Stack elements are:";
for(int i=top; i>=0; i--)
cout<<stack[i]<<" ";
cout<<endl;
} else
cout<<"Stack is empty";
}
int main() {
int ch, val;
cout<<"1) Push in stack"<<endl;
cout<<"2) Pop from stack"<<endl;
cout<<"3) Display stack"<<endl;
cout<<"4) Exit"<<endl;
do {
cout<<"Enter choice: "<<endl;
cin>>ch;
switch(ch) {
case 1: {
cout<<"Enter value to be pushed:"<<endl;
cin>>val;
push(val);
break;
}
case 2: {
pop();
break;
}
case 3: {
display();
break;
}
case 4: {
cout<<"Exit"<<endl;
break;
}
default: {
cout<<"Invalid Choice"<<endl;
}
}
}while(ch!=4);
return 0;
}
Im just trying to know what is a more accepted method.
The approach you've taken here using global variables is fine for a simple implementation, but it has a major drawback in most real-world applications: it's not reusable.
What if you need two stacks in your program? That would require creating a second set of global variables and a second set of functions to act on them.
That is the problem that using a class solves. If you wrap all of your stack's state in a class then you can create a single set of functions that can operate on any object of that class. Then creating a second stack is very simple.
Of course, for most real world applications you shouldn't implement your own stack anyway. Just use std::stack unless you have a very compelling reason not to. But that still supports the same conclusion. Because std::stack is a self-contained, reusable class any program can use it without having to re-implement their own stack logic (possibly multiple times).

how to replace a value of a variable inside code from user input?

i am trying to add a developer mode in my program. since duty of car defers every month,i want give my user permission to change every single variables in my program alike duty lccost yen2taka freight
#include <iostream>
using namespace std;
class A
{
public:
int carbid,duty;
void Input()
{
cout<<"please insert the car price you want to bid for(in yen): ";
cin>>carbid;
cout<<"duty of the car: ";
cin>>duty;
}
int Exportcost()
{
int exportcost;
int servicechrg=10;
int freight=20;
exportcost=servicechrg+freight+carbid;
return exportcost;
}
int Yen2taka()
{
int yen2taka;
int taka2dollarrate=10;
int dollar2yen=1;
yen2taka=((Exportcost())/dollar2yen)*taka2dollarrate;
return yen2taka;
}
int Importcost()
{
int importcost;
int lccost=10;
int cnfcost=20;
importcost=lccost+cnfcost;
return importcost;
}
int Totalcosting()
{
int total;
int myprofit=10; //80000
total=myprofit+Importcost()+Yen2taka();
cout<<total;
return total;
}
void summary()
{
cout<<
}
};
int main()
{
x:
A ob;
ob.Input();
ob.Exportcost();
ob.Yen2taka();
ob.Importcost();
ob.Totalcosting();
int ch;
cout<<"press 1 to see the summery of the costing or 2 to restart costing again"<<endl;
cin>>ch;
switch(ch)
{
case 1:
ob.summary();
break;
case 2:
goto x;
}
}
At first, you should collect these parameters in a separate class:
class Configuration // maybe you find a better name...
{
int m_servicechrg = 10; // default
int m_freight = 20;
// ...
public:
int servicechrg() { return m_servicechrg; }
void servicechrg(int value); { /* check some limits? */ m_servicechrg = value; }
int freight() { return m_freight; }
void freight(int value); { /* check some limits? */ m_freight = value; }
// ...
};
// will allow you to do:
// C c; std::cout << c;
ostream& operator<<(ostream& s, Configuration const& c)
{
// which ever formatting is appropriate...
s << c.servicechrg() << ' ' << c.freight();
return s;
}
The setters could alternatively return bool to indicate invalid values.
Now you can use this class within main:
Configuration c;
A a;
int cost = a.exportCost(c); // you'd have to adjust signatures...
int value;
switch(ch)
{
case 4:
if(stc::cin >> freight) // catches invalid user input!
// one ALWAYS should do, otherwise you might end up in
// your program not working any more
{
c.freight(value);
// or, if you have:
if(!c.freight(value))
{
// some appropriate error message
// (it's better not to output in the setter, you are more flexible this
// way – maybe you want different messages at different occasions?)
}
}
else
{
// appropriate error handling
}
break;
default:
// handling invalid user input
// again, you always should; but stream state is not in error state,
// so you just can print appropriate error message
break;
}
See this answer for how to correctly handle stream errors.
If you wonder about the differences in error handling: First case is met if user enters non-numerical input, such as ss, second case, if input is numerical, but out of valid range (77).
Now if you don't want to pass the configuration as parameter all the time, you could make a global variable from (but careful, there are some dangers with global variables, use them as sparely as possible) or implement the singleton pattern.
Side notes: goto can be a fine tool sometimes, but it is a dangerous one (and the label's name x isn't a good one, prefer a name that clearly shows intention, such as REENTRY_POINT, LOOP_START, ...). If you can get along without unreasonable effort, prefer such variants:
bool isRunning = true;
do
{
// ...
case 2:
isRunning = false;
break;
}
while(isRunning);
Sure, an additional variable, an additional check; unfortunately, you cannot use break to exit a (pseudo-) endless loop (for(;;)) (but don't apply this pattern for nested loops, then it gets more and more unreadabla – and ineffcient: bool isExit = false; for(int i = 0; !isExit && i < n; ++i) { for(j = 0; j < n; ++j) { isExit = true; break; } } – see what I mean?). A variant might be:
for(;;)
{
switch(ch)
case 1:
// ...
//break; <- replace
continue;
case 2:
//
break;
} // end of switch
break; // break the surrounding for(;;) loop
}
But that's not really nice either.
A pretty nice variant allowing to exit the loop in the given case, as there isn't anyhting to do afterwards:
for(;;)
{
switch(ch)
{
case 2:
// maybe yet some cleaning up here
return 0;
default:
// ...
break;
}
}
Drawback: The function's exit point possibly is deeply nested inside the code.
There are yet other tricks to allow this pattern, like packing sub-sections of code in a lambda having a return inside and call that one directly. But that now really starts going beyond the scope...
Finally, if you insist on goto, my variant would rather be:
for(;;)
{
switch(ch)
{
case 2:
// ...
goto LOOP_EXIT;
default:
// ...
break;
}
}
LOOP_EXIT:
return 0; // e. g. main
(void)0; // if there isn't anything to do in the function any more
// (labels require an instruction afterwards!)
There won't be a hidden loop now and it is more obvious what you actually are doing. Currently, not really an issue, but if your code grows, the hidden loop gets more and more difficult to spot.
In such cases, I clearly mark the gotos so that another coder can immediately spot the critical code points:
///////////////////////////////////////////////////
// possibly some comment why applying this pattern
goto SOME_LABEL;
///////////////////////////////////////////////////
One could do the same with deeply nested function exit points (return).

how to use gets function in c++ code?

In the main function of this code in the case 2 of switch case after entering the string program terminates! What is the problem with the code?
/*this code is a implementation of bubble sort algorithm*/
#include <iostream>
#include<conio.h>
#include<stdio.h>
#include<string.h>
#include<dos.h>
using namespace std;
int counter;
template <class T>//template created
class program//class which holds all the sorting functions
{
public:
T *v,x;
int j,k,l,siz,flag;
time_t t1,t2;
char c;
public:
void sortlist()//fn to sort characters and numbers
{
cout<<endl<<"------->>INTERMEDIATE STEPS<<-------";
for(k=1;k<=siz-1;k++)//sorting using a bubble sort
{ flag=0;
cout<<endl<<"PASS : "<<k<<endl;
j=0;
while(j<=siz-1-k)
{
if(v[j]>v[j+1])//comparing two consecutive elements
{
x=v[j+1];
v[j+1]=v[j];
v[j]=x;
flag++;
}
for(l=0;l<siz;l++)
{
cout<<v[l]<<" ";
}
cout<<endl;
j++;
}
cout<<"COMPARISONS:"<<(siz-k)<<endl;
if(flag==0)
{
cout<<endl<<"----->NO need to carry out more passes"<<endl<<"List is already sorted"<<endl;
break;
}
}
}
void stringsort()//fn to sort the strings
{
T a[90][20],b[1][20];
cout<<"enter the size of list:";
cin>>siz;
cout<<"enter the list:";
cin.ignore();
for(j=0;j<siz;j++)
{
gets(a[j]);
}
cout<<endl<<"------->>INTERMEDIATE STEPS<<-------";
for(k=1;k<=siz-1;k++)//sorting using bubble sort
{
flag=0;
cout<<endl<<"PASS : "<<k<<endl;
j=0;
while(j<siz-k)
{
x=strcmp(a[j],a[j+1]);//comparing two consecutive string
if(x>0)
{
strcpy(b[1],a[j+1]);
strcpy(a[j+1],a[j]);
strcpy(a[j],b[1]);
flag++;
}
for(l=0;l<siz;l++)
{
cout<<a[l]<<" ";
}
cout<<endl;
j++;
}
cout<<endl<<"COMPARISON:"<<(siz-k)<<endl;
if(flag==0)
{
cout<<endl<<"No need to carry out more passes"<<endl<<"List is already Sorted"<<endl;
break;
}
}
cout<<"SORTED LIST:"<<endl;
for(j=0;j<siz;j++)
{
cout<<endl<<a[j]<<endl;
}
}
};
int main()//main fn
{
int x;
char c;
do
{
program <char> p1;
program <int> p2;
cout<<endl<<"To sort a list of NUMBERS enter -> 1"<<endl<<endl<<"To sort string of CHARACTERS enter -> 2"<<endl<<endl<<"To sort a list OF STRINGS and DOUBLE_STRINGS enter -> 3";
cout<<endl<<endl<<"Enter either 1 OR 2 OR 3:";
cin>>x;
switch(x)
{
case 1://to sort list of numbers
{
cout<<endl<<"enter the size of list: ";
cin>>p2.siz;
cout<<"enter the list: "<<endl;
p2.v=new int[p2.siz];
for(p2.l=0;p2.l<=p2.siz-1;p2.l++)
{
cin>>p2.v[p2.l];
}
p2.sortlist();//sort and search in numbers
cout<<endl<<"SORTED LIST:"<<endl;//sorted list after the bubble sort
for(x=0;x<=(p2.siz)-1;x++)
{
cout<<p2.v[x]<<endl;
}
}
break;
case 2://to sort string of character
{
cout<<"enter the string of characters:";
cin.ignore()
gets(p1.v);
p1.siz=strlen(p1.v);
p1.sortlist();//sort in characters
cout<<endl<<"SORTED STRING:"<<p1.v;
}
break;
case 3://to sort list of strings
{
p1.stringsort();//sort list of string
}
break;
default:
cout<<"INVALID_CHOICE"<<endl<<endl;
}
cout<<endl<<"do u want to enter another list?y/n";
cin>>c;
}
while(c=='y');
return 0;
}
gets requires that you pass a pointer to enough storage space to hold the string that gets read. Your program passes an uninitialized pointer.
You're not really allowed to do anything with uninitialized values, so in theory your program can crash before it even enters the gets function.
Since the user can pass any amount of data to gets and your program would be responsible for storing it, the function is deprecated. It doesn't even exist any more in the C++ standard library as std::gets since 2011, although ::gets will probably always be available in POSIX. The short answer is, "don't."
You might consider std::string and std::getline instead.

linked list not printing correctly?

struct stack_struct
{
int number;
struct stack_struct *next_number;
};
stack_struct *mainStruct;
class stack_class
{
private:
struct stack_struct *head;
public:
stack_class();
//~stack_class();
void pushNumber(int number);
void popANumber();
void findNumber();
void clearStack();
void sizeFinder();
void printStack();
};
stack_struct *pointerFunc,*pointerFunc2,*pointerFunc3,*printPointer;
stack_class::stack_class()
{
head=NULL;
}
void stack_class::pushNumber(int numberFunc)
{
if(head==NULL)
{
head = new stack_struct;
head->number = numberFunc;
head->next_number = NULL;
pointerFunc2=head;
}
else
{
pointerFunc = new stack_struct;
pointerFunc->number=numberFunc;
pointerFunc->next_number=NULL;
head->next_number=pointerFunc;
head=pointerFunc;
}
}
void stack_class::printStack()
{
while(pointerFunc2)
{
cout<<pointerFunc2->number<<endl;
pointerFunc2=pointerFunc2->next_number;
}
}
int optionChosen;
int main()
{
stack_class mainClassStack;
do
{
cin>>optionChosen;
switch(optionChosen)
{
case 1:
{
int pushInt;
cout<<"\n\nEnter Number: ";
cin >> pushInt;
mainClassStack.pushNumber(pushInt);
break;
}
case 2:
{
break;
}
case 3:
{
break;
}
case 4:
{
break;
}
case 5:
{
break;
}
case 6://print
{
mainClassStack.printStack();
break;
}
default:
{
break;
}
}
}while(optionChosen!=7);
return 0;
I am trying to implement a stack type of data list using dynamic memory (linked list). But when I try to prints the list, it only prints the list once, and if I try to reprint again using option 6, its like the list is gone. I went over the code twice but couldnt figure out what the problem was. Any suggestions?
The problem with your code is that after you print the stack, you aren't resetting pointerFunc2 to become head.
Either reset it correctly, or use a local variable inside your print function.
Here's a corrected version of your function:
void stack_class::printStack()
{
while (pointerFunc2)
{
cout << pointerFunc2->number << endl;
pointerFunc2 = pointerFunc2->next_number;
}
// reset pointerFunc2 so the next iteration
// can start at the head and print again.
pointerFunc2 = head;
}
The problem is when you print the stack the first time with this
pointerFunc2=pointerFunc2->next_number;
the pointerFunc2 becomes the last element after the first iteration. So that's why you think its gone. You should reset pointerFunc2 to point to the head node after being printed. So save it first, then after iterating thru the whole list, restore it, so that the next time you print the stack you will start with the head node.
The reason the second print does not work is that you are using a global variable instead of a local one:
stack_struct *pointerFunc2;
When you declare a variable outside a function or a class, it becomes global variable. Global variables survive function invocations, and retain the value that was last set into them. In order to be local, a variable needs to be declared inside printStack, initialized to the stack's head, and then discarded upon exiting the function. The same is true about pointerFunc.
The printPointer and pointerFunc3 variables are unused, and can be removed from the source code.

Error in a Link List

I wrote the following code for a Link list to create a Book its serial no. and search it. I am using linked list in it.
When I add my first entry , it is added successfully, but when I add second entry it shows segmentation fault. I am not able to figure out why. Please help.Thanks in advance.Code:
#include<iostream>
#include<string>
#include<fstream>
#include<cstdlib>
using namespace std;
struct book
{
int accno;
string name;
book* next;
};
int main()
{
bool flag=false;
int x,m;
string s;
book* front=NULL;
book* n;
do
{
cout<<"\nPlease select the following:\n1.Create and append\n2.Search\n3.Exit";
cin>>m;
switch(m)
{
case 1:
n=new book();
cout<<"\nEnter the book name: ";
cin>>s;
cout<<"\nEnter the acc no.: ";
cin>>x;
if(front==NULL)
{
front=n;
}
else
{ n=front;
while(n->next!=NULL)
{
n=n->next;
}
n=n->next;
}
n->accno=x;
n->name=s;
break;
case 2:
cout<<"Enter the roll no.";
int y;
cin>>y;
if(front==NULL){cout<<"Doesnot exist\n"; break;
}
else
{
n=front;
while(n->accno!=y && n->next!=NULL)
{
n->next=n;
}
cout<<"Book name is:"<<n->name;
cout<<"\nAccno is: "<<n->accno;
}
break;
case 3: flag=true;
break;
}
}
while(flag==false);
return 0;
}
Here
while(n->next!=NULL)
{
n=n->next;
}
n=n->next;
you iterate through the linked list to find the last element, then step past it. After this, n will be null.
What you are missing is creating a new element and appending it to the end of the list.
And here
n->accno=x;
n->name=s;
you must also assign n->next = null, otherwise your list won't be properly terminated.
Also, when searching for a book, here
while(n->accno!=y && n->next!=NULL)
{
n->next=n;
}
cout<<"Book name is:"<<n->name;
cout<<"\nAccno is: "<<n->accno;
after exiting the loop, either you found the book or n is null. You must check which is the case before trying to dereference n, otherwise you will again get a segfault if the book you are looking for is not in the list.
Learn to write a linked list (so if this is a homework targeted at learning them, it's valid, but it is not tagged as such), but never ever do it in practice. There is a standard library and there is boost and they have all data structures you'll need unless you do something really special.
You have C++, so don't write C-style code. book should have a constructor that should initialize it's members. The list head should probably be encapsulated in the class too and manipulated using it's methods.
You never set n->next, so don't be surprised it never contains anything meaningful.
You re-use n in the loop forgetting the object you constructed (memory leak).
Than you get the NULL at the end of the list instead of the object you constructed.
here lies your problem:
....
else
{
n=front;
while(n->next!=NULL) //access to next will cause seg fault!!!
{
n=n->next;
}
n=n->next; // step once more, now we have NULL on second add...
}
also, where is n->next being assigned? I don't see it anywhere?
What are you doing here?
case 1:
n=new book();
cout<<"\nEnter the book name: ";
cin>>s;
cout<<"\nEnter the acc no.: ";
cin>>x;
if(front==NULL)
{
front=n;
}
else
{
n=front;
}
while(n->next!=NULL)
{
n=n->next;
}
n=n->next;
}
n->accno=x;
n->name=s;
break;
You have created new book and assigned it to n, in first case its ok becasue your are directly assigning it to front. But in other case you should iterate list using someother variable (temp), when your write n = front, your have already lost your new book object pointer. Hope you got your answer.
This is a buggy code:
You need null the "next" field when you add a new node:
case 1:
new book();
n->next = NULL;
...
You have the memory leakage