Member variable resetting back to 0 - c++

When running through the test the count variable from the class stack1 gets reset back to 0 when using its pop function. Strangely however, during the push loop, the count increases as intended but when pop occurs, the count gets reset back to 0 and subtracts into the negatives from there. Is there something I'm forgetting?
#include <iostream>
using namespace std;
class TheStack
{
public:
TheStack();
void push(int);
int pop();
bool isEmpty();
private:
const int MaxSize = 10;
int arr[10];
int count;
};
TheStack::TheStack()
{
count = 0;
}
void TheStack::push(int userInput)
{
if (count >= MaxSize)
{
cout << "Stack is full." << endl;
}
else
{
arr[count] = userInput;
count+=1;
}
}
int TheStack::pop()
{
if (isEmpty())
{
cout << "Stack is empty." << endl;
}
else
{
int temp = arr[count];
arr[count] = NULL;
count-=1;
return temp;
}
}
bool TheStack::isEmpty()
{
if (count == 0)
{
return true;
}
else
{
return false;
}
}
int main()
{
TheStack stack1;
if (stack1.isEmpty())
{
cout << "isEmpty() works" << endl;
}
stack1.pop();
for (int i = 0; i < 10; i++)
{
stack1.push(i);
}
stack1.push(0);
stack1.pop();
stack1.pop();
stack1.pop();
stack1.pop();
system("pause");
}

When you do push you first save the data into the array and then increment count. This means that in order to properly do pop you need to work in reverse: first decrement count and only then read data from the array.
But in the code you are doing it backwards. When the stack is full, count is at max value (10 in your case), and your arr[count] = NULL; writes beyond the array boundary. This causes undefined behavior and, in particular, destroys your count value. (This is why it suddenly becomes 0.)
Also:
arr[count] = NULL; makes no sense. NULL is supposed to be used in pointer contexts, not in integer contexts. This is not even guaranteed to compile.
What is the point of that anyway? Initially your array contains garbage above the current top of the stack. Why do you suddenly care to clean it up after doing pop?
Not all control paths of pop() return value. This is undefined behavior in itself.
const int MaxSize = 10; in the class definition is a C++11 feature. Since you are already using C++11, you can do the same for count. Just do int count = 0; right inside the class definition and you will not have to write the constructor explicitly.
Although in your implementation MaxSize would make more sense as a static const class member. In that case you'll also be able to declare your array as int arr[MaxSize];.

You must first decrease count and then access arr[count] in int TheStack::pop(). Now you get access above the last pushed element, event out of bound of array if the stack is full.

Related

Class variable not reachable from class method

I am trying to implement a circular queue.
I have declared size of the queue in the header file and I initiated my queue using size variable via constructor.
Here are queue.h and queue.cpp files.
class Queue
{
public:
int size;
int front, rear;
int A[];
Queue(int size);
bool isEmpty();
void enqueue(int n);
int dequeue();
int Peek();
void Display();
int sizeQ();
};
Here is queue.cpp
Queue::Queue(int size)
{
int A[size];
front = rear = -1;
}
bool Queue::isEmpty(){
if((front == -1) && (rear == -1))
return true;
else
return false;
}
void Queue::Display(){
if(isEmpty()){
cout << "Its empty! Nothing to display"<<endl;
}else{
for(int i=0; i<sizeQ(); i++){
cout << A[i] << endl;
}
}
cout <<endl;
}
Here is my main
int main()
{
Queue q1(10);
q1.enqueue(20);
q1.Display();
return 0;
}
The problem: Loop inside display function does not see the size variable although I created object using size inside main. When I debug the program, I saw that size is 0, thus for loop never starts.
What I tried
int Queue::sizeQ(){
return size;
}
I tried to return size via method; however, no luck. What should I do in order to access size variable?
Currently your constructor creates a local array that gets destroyed after it completes. You don't want to do this.
If you want to set the size of an array at run time it has to be declared on the heap. To do that you should change the declaration of the array A like this in the header:
int *A;
Then in your constructor you can allocate the array on the heap:
Queue::Queue(int iSize):
size(iSize), front(-1), rear(-1)
{
A = new int[size];
}
Note the initialiser list is initialising member variables size, front and rear.
You must also deallocate your array. To do this add a destructor to your class Queue and do this:
Queue::~Queue()
{
delete [] A;
}
This will free up the memory used by A.
Queue::Queue(int size)
{
int A[size];
front = rear = -1;
}
You never initialize this->size here. Hence sizeQ() returns uninitialized value of size member.
Add this->size = size; inside the constructor.
EDIT: the int A[size] does not do what you think it does. It is creating a local array and has nothing to do with the member A. Refer to #jignatius answer to see how to fix it.
Initiate size inside constructor like below:
Queue::Queue(int nSize) //changed name of parameter to nSize to remove confusion
{
int A[size];
front = rear = -1;
size = nSize; // Initialize passed param to member variable of class
}

Error C2228 In a Simple Counter Program C++

First time here, so forgive me if I'm not entirely following protocol. I will adjust as is necessary. I'm trying to make a simple program that increments (or decrements) through a counter. The counter's functions are through a class, and I'm trying to use the main for testing for functionality. I could very easily be missing something super simple, as is always the case with me, but I can't figure it out so I figured I'd ask here, since I've come here very often finding help easily. I've tried sifting through answers and nothing has been helping so far. Here's the code:
#include <iostream>
using namespace std;
class counter
{
public:
counter();
counter(int begin, int maximum);
void increment();
void decrement();
int getter();
private:
int count;
int max;
};
// Default constructor.
counter::counter()
{
count = 0;
max = 17;
}
// Constructor that allows you to put in a starting point for the counter
// and a maximum value for the counter.
counter::counter(int begin, int maximum)
{
max = maximum;
if (begin > maximum)
{
cout << "You input an invalid value to begin. Set to default.";
count = 0;
}
else
{
count = begin;
}
}
// Increments counter by one. If counter would exceed max, then goes to 0.
void counter::increment()
{
if (count == max)
{
count = 0;
}
else
{
count++;
}
}
// Decrements counter by one. If counter we go below 0, then goes to max.
void counter::decrement()
{
if (count == 0)
{
count = max;
}
else
{
count--;
}
}
// Getter for counter value.
int counter::getter()
{
return count;
}
int main()
{
counter test();
for (int i = 0; i < 20; i++)
{
test.increment();
cout << test.getter() << "\n";
}
}
The error that's appearing is:
"dsCh2Exercise.cpp(81): error C2228: left of '.increment' must have
class/struct/union dsCh2Exercise.cpp(82): error C2228: left of
'.getter' must have class/struct/union"
Thanks ahead of time for any and all input! It's greatly appreciated!
counter test(); declares a function named test that takes no arguments and returns a counter, not a variable named test that contains a counter. Change that line to:
counter test;

Seg. fault resizing array C++

I have a priority queue array that is filled with "Jobs" (name + priority). I've been able to get everything queue related working aside from re sizing if it is full. Here is the bits that I think are causing a segmentation fault that I haven't been able to figure out.
EDIT:
Here is a bit more code that will compile, I left in the rest of the functions in case those might help in any way. Right now the initial capacity is set to 5, when you try to add a job to the full list it will double the capacity of the array and allow you to add a couple more jobs before a SEG. fault.
pq.h
#ifndef PQ_H
#define PQ_H
#include "interface.h"
#include <string>
using namespace std;
class Job {
public:
int getPriority();
string getTaskName();
void setPriority(int val);
void setTaskName(string tname);
Job();
private:
int priority;
string taskName;
};
class PriorityQueue {
public:
PriorityQueue();
~PriorityQueue();
int size();
bool isEmpty();
void clear();
void enqueue(string value, int priority);
string dequeue();
string peek();
int peekPriority();
PriorityQueue(const PriorityQueue & src);
PriorityQueue & operator=(const PriorityQueue & src);
private:
static const int INITIAL_CAPACITY = 5;
Job *array;
int count;
int capacity;
void expandCapacity() {
Job *oldArray = array;
capacity *= 2;
array = new Job[capacity];
for (int i = 0; i < count; i++) {
array[i] = oldArray[i];
}
delete[] oldArray;
}
};
#endif
pq.cpp
#include <iostream>
#include <cstring>
using namespace std;
//#include "job.h"
#include "pq.h"
Job::Job() // Constructor
{
priority= 0;
taskName = "There are no items in the list.";
}
int Job::getPriority(){ // returns the prority of the job
return priority;
}
string Job::getTaskName(){ // returns the name of the job
return taskName;
}
void Job::setPriority(int val){ // sets the priority of a newly created job
priority = val;
}
void Job::setTaskName(string tname){ // sets the name of a new job
taskName = tname;
}
PriorityQueue::PriorityQueue() // constructor
{
count = 0;
capacity = INITIAL_CAPACITY - 1;
array = new Job[INITIAL_CAPACITY];
}
PriorityQueue::~PriorityQueue() { // destructor
delete [] array;
}
int PriorityQueue::size() { // returns the number of jobs in the queue
return count;
}
bool PriorityQueue::isEmpty() { // returns true if queue is empty
if (count != 0){
return false;
}else{
return true;
}
}
void PriorityQueue::clear() { // clears queue of all jobs
count = 0;
// need to make it remove and delete the items
}
void PriorityQueue::enqueue(string value, int priority) {
// tests size to see if Queue is a max capacity
if(count == capacity){
expandCapacity();
cout << "\tList was full and has been expanded\n";
}
array[++count].setPriority(priority);
array[count].setTaskName(value);
// upheap operations
Job v = array[count];
int tempcount = count;
while (array[tempcount/2].getPriority() >= v.getPriority()){
array[tempcount] = array[tempcount/2];
tempcount = tempcount/2;
array[tempcount] = v;
}
}
string PriorityQueue::dequeue() {
// removes the job with the highest priority from the queue and returns the name
if(this->isEmpty()){ // make sure the queue isnt empty
string empty = "The queue is empty";
return empty;
}else{
Job remove = array[1];
array[1] = array[count--];
int j;
Job v;
int k = 1;
v = array[k];
while(k <= count/2){
cout << "dequeuewhile"; // test
j = k + k;
if(j < count && array[j].getPriority() > array[j+1].getPriority()){
j++;
cout << "dequeueloop if1"; // test
}
if(v.getPriority() <= array[j].getPriority()){
cout << "dequeueloop if2"; //test
break;
}
array[k] = array[j];
k = j;
}
array[k] = v;
return remove.getTaskName(); // returns the name of the removed job
}
}
string PriorityQueue::peek() { // returns the name of the highest priority job without removing it from the queue
if(count == 0){
return array[0].getTaskName();
}
return array[1].getTaskName();
}
int PriorityQueue::peekPriority() { // returns the priority from the highest priority job without removing it from the queue
if(count == 0){
cout << "\tThere are no items in the list.\n";
return array[0].getPriority();
}
return array[1].getPriority();
}
I think that when you do ++count, the next use of count will be out of bounds for the array.
array[++count].setPriority(priority);
// SEGMENTATION FAULT HERE
array[count].setTaskName(value);
If the capacity of the array is 5, and count was 4, then you just incremented count to 5, and tried to access element 5, which is out-of-bounds.
array = new Job[capacity];
for (int i = 0; i < count; i++) {
array[i] = oldArray[i];
}
Lets assume capacity is 10, so you've got an array of 10 elements, ranging from elements 0 to 9.
counttells us how many elements are being used.
If count happens to be 9, then when you increment count by one, it is now 10. Then, when line come you marked as producing segment fault comes, you're trying to access element 10, in our example. There is no element 10in an array of length 10, so you're out of bounds.
array[++count].setPriority(priority); // array[10], but last element is 9!
// SEGMENTATION FAULT HERE
array[count].setTaskName(value); // array[10], but last element is 9!
And, of course, everything after that part causes the same issue, as you keep using array[count].
Your original code did exactly as the previous answer given by #antiHUMAN.
The problem you're having is mixing or erroneously using 0-based and 1-based concepts.
Your first mistake is to make capacity a 0-based number. The capacity should denote the maximum number of items in an array, thus you should not be subtracting 1 from it. If the array can hold 5 items, then capacity should be 5, not 4.
PriorityQueue::PriorityQueue() // constructor
{
count = 0;
capacity = INITIAL_CAPACITY; // this remains 1-based.
array = new Job[INITIAL_CAPACITY];
}
or using the initializer-list:
PriorityQueue::PriorityQueue() : count(0),
capacity(INITIAL_CAPACITY),
array(new Job[INITIAL_CAPACITY]) {}
The 0-based number in your situation should be count, not capacity. Given that, since count is 0-based, and capacity is 1-based, your test in enqueue needs to be changed:
if(count + 1 == capacity){
expandCapacity();
cout << "\tList was full and has been expanded\n";
}
Note that 1 is added to count to account for the fact that count is 0-based and capacity is 1 based.

Messy and wrong char visualization (after passing actual parameters) C++

this is my first post. Below the code of my implementation of a char Stack. Theoretically It should print f,g,h. But when I execute it, I can just see a long list of strange signs in the console. Is a compiler issue or code issue? Thanks.
#include <iostream>
using namespace std;
const int max_L = 10;
class Stack {
protected:
char array[];
int length;
public:
Stack(){length = 0;}
bool push(char c) {
if(length < max_L){
array[length] = c;
length++;
return(true);
}
else return(false);
}
void pop(){
if(length >= 1){
cout << array[length];
length--;
} else return ;
}
bool is_empty(){
return(length == 0);
}
void print(){
for(int i = 0; i < length; i++){
cout << array[i];
}
}
};
int main() {
Stack p1;
p1.push('f');
p1.push('g');
p1.push('h');`
p1.print();
return 0;
}
There are two problems in the code. As πάντα ῥεῖ said, the array has to be created with a size. The other problem is that push and pop aren't quite complementary. push puts the added value at array[length], then increments length. So after a call to push, length is the index of the next entry, i.e., the one that hasn't been put in yet. pop has to look at the previous entry, i.e., the one that was just put in. So the code for pop should decrement length before looking at array[length]. Change
cout << array[length];
length--;
to
length--;
cout << array[length];

C++ Priority Queue, logical error, can't figure out

I'm implementing a simple priority queue in C++.
However when it runs, it prints out gibberish numbers.
Am I somehow trying to access invalid entries in the array in my code?
Below is the code.
Also, is my "remove" function somehow not doing its job? Conceptually, shall I be putting null into the first entry and return whatever was just erased?
Thanks.
[Priority.h]
#ifndef Priority_h
#define Priority_h
class Priority
{
public:
Priority(void);
Priority(int s);
~Priority(void);
void insert(long value);
long remove();
long peekMin();
bool isEmpty();
bool isFull();
int maxSize;
long queArray [5];
int nItems;
private:
};
#endif
[Priority.cpp]
#include <iostream>
#include <string>
#include <sstream>
#include <stack>
#include "Priority.h"
using namespace std;
Priority::Priority(void)
{
}
Priority::Priority(int s)
{
nItems = 0;
}
Priority::~Priority(void)
{
}
void Priority::insert(long item)
{
int j;
if(nItems==0) // if no items,
{
queArray[0] = item; nItems++;
}// insert at 0
else // if items,
{
for(j=nItems-1; j=0; j--) // start at end,
{
if( item > queArray[j] ) // if new item larger,
queArray[j+1] = queArray[j]; // shift upward
else // if smaller,
break; // done shifting
} // end for
queArray[j+1] = item; // insert it
nItems++;
} // end else (nItems > 0)
}
long Priority::remove()
{
return queArray[0];
}
long Priority::peekMin()
{
return queArray[nItems-1];
}
bool Priority::isEmpty()
{
return (nItems==0);
}
bool Priority::isFull()
{
return (nItems == maxSize);
}
int main ()
{
Priority thePQ;
thePQ.insert(30);
thePQ.insert(50);
thePQ.insert(10);
thePQ.insert(40);
thePQ.insert(20);
while( !thePQ.isEmpty() )
{
long item = thePQ.remove();
cout << item << " "; // 10, 20, 30, 40, 50
} // end while
cout << "" << endl;
system("pause");
}
Here is one error:
for(j=nItems-1; j=0; j--) // start at end,
^ this is assignment, not comparison.
I am also not convinced that there isn't an off-by-one error in
queArray[j+1] = item; // insert it
Finally, your default constructor fails to initialize nItems.
There could be further errors, but I'll stop at this.
I agree with the other answers here, but I would add this:
Your "Remove" method isn't actually removing anything - it is just returning the first element - but it doesn't do anything to the array itself.
Edited to say that your insert method needs some work - it may or may not write over the end of the array, but it is certainly confusing as to what it is doing.
Try initializing your queue array in the constructor.