Decoder implementing a stack as a linked structure - c++

This program I am writing will use a special implementation of a stack as a linked structure. An encoded message input my the user will be parsed and decoded using the stack. What I have written compiles find and runs without crashing. The program asks the user for the string to be decoded. However, the encoded message is not decoded with result printed on the screen. I can't figure out why my program isn't decoding and printing the user's input. Any help is greatly appreciated. Thanks.
My header file :
#ifndef DECODER_H
#define DECODER_H
#include <iostream>
#include <stdlib.h>
using namespace std;
// ---------------------------
// Structure which will serve
// as the link on the stack.
// ---------------------------
struct StackNode {
char ch;
StackNode* next;
};
// -------------------------------
// Class which will contains the
// functions for appropriate use
// of the stack.
// -------------------------------
class Decoder
{
private:
StackNode* top;
public:
Decoder();
~Decoder();
int EmptyStack();
int FullStack();
void Push(char ch);
char Pop();
void Decode(char *encMsg, char *decMsg);
};
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
#endif // End of stack header.
My .cpp file:
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "Decoder.h"
// ------------------------------
// Function: Decoder()
//
// Purpose: Class constructor.
// ------------------------------
Decoder::Decoder()
{
top = NULL;
}
// ------------------------------
// Function: Decoder()
//
// Purpose: Class destructor.
// ------------------------------
Decoder::~Decoder()
{
// TODO
// Destroy anything remaining in the stack
}
// -----------------------------------
// FullStack()
//
// Return TRUE if the stack is full.
// -----------------------------------
int Decoder::FullStack()
{
return TRUE;
}
// -----------------------------------
// EmptyStack()
//
// Return TRUE if the stack is empty
// -----------------------------------
int Decoder::EmptyStack()
{
return (top == NULL);
}
// ------------------------------------------------
// Function: void Push(char ch)
//
// Purpose: Dynamically creates a structure of type
// StackNode (see Decoder.h), stores the character
// in the structure and pushes the structure onto
// the stack.
// ------------------------------------------------
void Decoder::Push(char ch)
{
// Make a new node whose reference is
// the existing list
StackNode* newNode = new (StackNode);
newNode->ch = ch;
// newNode->next = NULL;
if (top == NULL)
top = newNode; // top points to new node
else
{
newNode->next = top;
top = newNode;
}
}
// --------------------------------------------------
// Function: char Pop()
//
// Purpose: Remove (pop) the top node from the stack,
// copy the character, from this node, delete and
// return the character.
// --------------------------------------------------
char Decoder::Pop()
{
StackNode* temp;
char ch;
if (!EmptyStack())
{
ch = top->ch;
temp = top;
top = top->next;
delete(temp);
return ch;
}
else {
cout << "Warning: Overuse of Pop()" << endl;
return '\0';
}
}
// ----------------------------------------------------
// Function: void Decode(char* encMsg, char* decMsg)
//
// Purpose: Parse and decode the message stored in the
// character array encMsg using the stack functions
// and return the decoded message in the char array
// decMsg.
// ----------------------------------------------------
void Decoder::Decode(char* encMsg, char* decMsg)
{
int StackCount = 0;
char num[2] = " ";
for (int i = 0; i < strlen(encMsg); i++)
{
// check whether 1 is an even number of input
if ((encMsg[i] == '1') && (encMsg[i-1] != '2')) // every other index will be a command number
{
Push(encMsg[i+1]);
StackCount++;
}
if (encMsg[i] == '2' && ((encMsg[i+1] >= '0') && (encMsg[i+1 ] <= '9'))) // every other index will be a command number
{
num[0] = encMsg[i+1];
// pop as many as the argument states to pop
for (int j = 0; j < atoi(num); j++)
{
Pop();
StackCount--;
}
}
}
//cout << StackCount << endl;
// Place the remaining characters from the stack into decMsg
int i;
for (i = 0; i < StackCount; i++)
{
decMsg[i] = Pop();
}
decMsg[i] = '\0';
return;
}
My Main .cpp:
#include <iostream>
#include <string>
#include "Decoder.h"
using namespace std;
int main (void)
{
char quit[] = "QUIT";
char en[2048];
char dec[512];
Decoder d;
do {
cout << "\nEnter a message to be decoded" << endl;
cin.getline(en, 1024);
d.Decode(en, dec);
cout << dec << endl;
} while (strcmp(en,quit) != 0);
return 0;
}

This line of code
if ((encMsg[i] == '1') && (encMsg[i-1] != '2'))
Maybe a problem there when i is zero.

It is guaranteed to try endMsg[-1] every time since i=0 is followed immediately by encMsg[i-1] which is always checked since && is present.
for (int i = 0; i < strlen(encMsg); i++)
{
// check whether 1 is an even number of input
if ((encMsg[i] == '1') && (encMsg[i-1] != '2')) // every other index will be a command number
{

Related

Cursor not moving in tree insert function, found in provided header file that has constructor and class definition. How can I move the cursor forward?

The assignment requires that I write the code for an Insert, Print and Find functions in the already provided tree header file. It's a very simple search tree for ints. Here is the header file:
#include <map>
#include <iostream>
class Tree {
Tree *left;
Tree *right;
int node;
static std::map<int, Tree*> allNodes;
public:
Tree(int n, Tree *l=0, Tree *r=0) : left(l), right(r), node(n) {
allNodes[n] = this;
}
int GetNode() { return node; }
void Insert(Tree *newnode) {
// insert code to Insert newnode into tree pointed to by this... return the tree
// My own code // cout<<this->node;
if( newnode->node == this->node ){}
// skip dup
//Everything after is also my code
else if (newnode->node < this->node){
left = newnode;
cout<<"left"<<left->node<<endl;
}
else if (newnode->node > this->node){
right = newnode;
cout<<"right"<<right->node<<endl;
}
}
Here is the code that implements it(I wrote the code at the very bottom):
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#include "trav.h"
std::map<int, Tree*> Tree::allNodes;
// trav print
// trav find X
int
main(int argc, char *argv[])
{
if( argc < 2 )
return 0;
string cmd(argv[1]);
// READ IN THE INTEGERS
vector<int> ids;
int input;
while( cin >> input ) {
ids.push_back( input );
}
// MAKE NODES FROM THE INTEGERS
vector<Tree*> nodes;
for( int id: ids ) {
nodes.push_back( new Tree(id) );
}
if( ids.size() == 0 )
return -1;
// PUT NODES INTO A TREE USING Insert
Tree *theTree = nodes[0];
if( theTree == nullptr )
return -1;
for( auto n : nodes ) {
//My code// theTree->Insert(n);
}
// PRINT TREE
if( cmd == "print" ) {
theTree->Print();
}
/*if (cmd == "find") {
string no = argv[2];
int num = atoi(no);
int result = theTree-> find(num);
if(result!=0)
cout<<num<<endl;
else
cout<<"-1"<<endl;
}*/
return 0;
}
Here is my output:
3232left8
32left3
32left5
32left9
32right40
32right100
32right632
32left1
32left9
32left9
32left3
32left2
32right64
32right43
2
43
32
Those last 3 numbers are from my print function.
The cursor doesn't appear to be moving forward. I've tried setting this=left, which returns an error. What can I do? And I'm not sure how to use the allNodes. Do I implement it in the insert function?

Assigning pointer

I have been working on this for a while and cannot seem to understand what is happening. I am trying to take the values in istr, put them in a linked list and sort them alphabetically. Eventually I will print them out. I am not sure where my problem is but I thought it was in the function InsertAfter. Is this not my problem and if so do you know what may be causing my linked list to not link? The last bit of code only outputs the headObj and not all of them, so I assumed that my list wasn't linking properly in nextNodePtr in each object but I am not sure. Thank you for your help!
void WordNode::InsertAfter(WordNode* nodeLoc) {
WordNode* tmpNext = 0;
tmpNext = this->nextNodePtr; // Remember next
this->nextNodePtr = nodeLoc; // this -- node -- ?
nodeLoc->nextNodePtr = tmpNext; // this -- node -- next
return;
}
wordNode.hpp
#ifndef wordNode_hpp
#define wordNode_hpp
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
class WordNode {
public:
WordNode(string wordval = "", int count = 0, WordNode* nextLoc = 0);
void InsertAfter(WordNode* nodePtr);
WordNode* GetNext();
void PrWordNodeData();
string GetWord();
private:
string word;
WordNode* nextNodePtr;
int wordCount;
};
wordNode.cpp
#include "wordNode.hpp"
// Constructor
WordNode::WordNode(string wordval,int count, WordNode* nextLoc) {
this->word = wordval;
this->wordCount = count;
this->nextNodePtr = nextLoc;
return;
}
/* Insert node after this node.
* Before: this -- next
* After: this -- node -- next
*/
void WordNode::InsertAfter(WordNode* nodeLoc) {
WordNode* tmpNext = 0;
tmpNext = this->nextNodePtr; // Remember next
this->nextNodePtr = nodeLoc; // this -- node -- ?
nodeLoc->nextNodePtr = tmpNext; // this -- node -- next
return;
}
// Print dataVal
void WordNode::PrWordNodeData() {
cout << this->word <<": count=" <<this->wordCount << endl;
return;
}
// Grab location pointed by nextNodePtr
WordNode* WordNode::GetNext() {
return this->nextNodePtr;
}
//Returns word
string WordNode::GetWord()
{
return word;
}
main.cpp
#include <iostream>
#include <sstream>
#include <string>
#include "wordNode.hpp"
int main() {
WordNode* headObj = 0; // Create WordNode objects
WordNode* currObj = 0;
WordNode* nextObj = 0;
string istr ="555 999 777 333 111";
istringstream instring(istr);
string temp;
//Assigns first word to the head object
if (!instring.eof()){
instring >> temp;
headObj=new WordNode(temp,1);
}
currObj=headObj;
while (!instring.eof()){
instring >> temp;
nextObj=new WordNode(temp,1);
//swaps values if currObj is greater than the next word
if(currObj > nextObj) {
currObj->InsertAfter(nextObj);
}
currObj=nextObj;
}
// Print linked list
currObj = headObj;
while (currObj != 0) {
currObj->PrWordNodeData();
currObj = currObj->GetNext();
}
string i;
cin >> i;
return 0;
}
In the very first iteration of the loop (using the string you gave as example) you loose the reference to the head object and hence subsequent iterations will add nodes to a "headless list".
currObj=headObj;
while (!instring.eof()){
instring >> temp;
nextObj = new WordNode(temp,1);
//swaps values if currObj is greater than the next word
if(currObj->GetWord() > nextObj->GetWord()) {
currObj->InsertAfter(nextObj);
}
// And what happens if it is not greater?
currObj = nextObj; // Loose reference to head here if not greater
}
To fix your code you will either just have to add all nodes to the list and then sort it with a sorting algorithm or insert them on the fly as you intend to do now. However, to do the latter you will have to modify your insertion logic, i.e. insert node at the beginning (if new node is alphabetically lower than the first element) or at the end. I recommend reading this nice article about singly linked lists. It has examples and code for the insertions mentioned.

C functions in c++ [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
#include <iostream>
#include <sstream>
#include "blocknode.h"
using namespace std;
class MemoryManager
{
public:
MemoryManager(unsigned int memsize);
unsigned char * malloc(unsigned int request);
void free(unsigned char * blockptr);
blocknode *getFirstPtr();
friend ostream & operator<<(ostream & out,const MemoryManager &M);
private:
unsigned int memsize;
unsigned char *baseptr;
blocknode * firstBlock;
void mergeForward(blocknode *p);
void splitBlock(blocknode *p,unsigned int chunksize);
};
Here is the BLOCKNODE.h file
#include <iostream>
using namespace std;
struct blocknode
{
unsigned int bsize;
bool free;
unsigned char *bptr;
blocknode *next;
blocknode *prev;
blocknode(unsigned int sz,unsigned char *b,bool f=true,blocknode
*p=0,blocknode *n=0):
bsize(sz),free(f),bptr(b),prev(p),next(n) {}
};
CPP FILE
#include <cassert>
#include <iostream>
#include <sstream>
#include <string>
#include "MemoryManager.h"
using namespace std;
ostream & operator<<(ostream & out,const MemoryManager &M)
{
blocknode *tmp = M.firstBlock;
assert(tmp);
while(tmp)
{
out << "[" << tmp->bsize << ",";
if (tmp->free)
out << "free] ";
else
out << "allocated] ";
if (tmp->next)
out << " -> ";
tmp = tmp->next;
}
return out;
}
MemoryManager::MemoryManager(unsigned int memtotal): memsize(memtotal)
{
baseptr = new unsigned char[memsize];
firstBlock = new blocknode(memsize,baseptr);
}
blocknode *MemoryManager::getFirstPtr()
{
return firstBlock;
}
unsigned char * MemoryManager::malloc(unsigned int request)
// Finds the first block in the list whose size is >= request
// If the block's size is strictly greater than request
// the block is split, with the newly create block being free.
// It then changes the original block's free status to false
{
blocknode * tmp = this->firstBlock;
assert(tmp);
while (tmp){
if (tmp->bsize >= request){
if (tmp->bsize > request){
splitBlock(tmp, request);
return tmp->bptr;
}
tmp->free = false;
return tmp->bptr;
}
tmp = tmp->next;
}
}
void MemoryManager::splitBlock(blocknode *p, unsigned int chunksize)
// Utility function. Inserts a block after that represented by p
// changing p's blocksize to chunksize; the new successor node
// will have blocksize the original blocksize of p minus chunksize and
// will represent a free block.
// Preconditions: p represents a free block with block size > chunksize
// and the modified target of p will still be free.
{
if (p->free == false || p->bsize <= chunksize) {
cout << "Error splitting memory....exiting with error code 1" << endl;
exit(1);
}
blocknode * heap = new blocknode(p->bsize,p->bptr + chunksize,true,0,0);
heap->bsize = p->bsize - chunksize;
heap->prev = p;
p->bsize = chunksize;
p->next = heap;
}
void MemoryManager::mergeForward(blocknode *p)
// merges two consecutive free blocks
// using a pointer to the first blocknode;
// following blocknode is deleted
{
blocknode * tmp = p->next;
p->bsize += p->next->bsize;
p->next = tmp->next;
tmp->next->prev = p;
delete tmp;
}
void MemoryManager::free(unsigned char *blockptr)
// makes the block represented by the blocknode free
// and merges with successor, if it is free; also
// merges with the predecessor, it it is free
{
blocknode * tmp = this->firstBlock->next;
assert(tmp);
while (tmp) {
if (tmp->bptr == blockptr) {
tmp->free = true;
if (tmp->free == true && tmp->next->free == true) {
mergeForward(tmp);
}
if (tmp->free == true && tmp->prev->free == true) {
mergeForward(tmp->prev);
}
}
}
}
The goal of this program is to pretty much simulate the C heap manager which deals with malloc() and free(). I am having trouble with the last four functions of the memory manager cpp file. (refer to the comments) The code compiles however my program crashes during runtime, it says that there is an unhanded exception at memory location XxXXXXXXX does anyone know what is causing this? Line 110 ("if(tmp->next->free == true)") is where the program breaks
When MemoryManager::free() calls mergeForward() (the first call to mergeForward()) as a result of what happens in mergeForward(), it looks like the tmp pointer used by free() will no longer be valid, because mergeForward() deleted it.
The derefence of tmp, immediately afterwards, will result in undefined behavior.
This is in addition to the other bug in free() that I noted in the comments.

C Simple RingBuffer - Multithreading - Finding Critical Sections [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
so I wrote a simple C Ring Buffer that I'm now testing using multiple threads and I'm having a hard time trying to get the code to fail so that I can identify critical sections.
Note: The code is in C, but i'm testing it in C++ files because its easier to create threads mutexes etc.
Header File:
#ifndef _C_TEST_H_
#define _C_TEST_H_
#include <stdio.h>
#include <mutex>
///////////////////////////////////////////////////////////////////////////////
// Defines and macros
///////////////////////////////////////////////////////////////////////////////
#ifndef __cplusplus
typedef enum { false, true } bool;
#endif
#define RING_BUFFER_SIZE 2000
///////////////////////////////////////////////////////////////////////////////
// Structures, Enumerations, Typedefs
///////////////////////////////////////////////////////////////////////////////
typedef struct Node
{
int val;
struct Node *next;
struct Node *previous;
} Node_T;
typedef enum RB_ERC
{
RB_ERC_NO_ERROR,
RB_ERC_NULL_PTR,
RB_ERC_UNDERFLOW,
RB_ERC_OVERFLOW
} RB_ERC_T;
typedef enum RB_HANDLE_OVERFLOW
{
RB_DECIMATE,
RB_IGNORE_AND_RETURN_ERROR
} RB_HANDLE_OVERFLOW_T;
typedef enum RB_READ_MODE
{
RB_FIFO,
RB_LIFO
} RB_READ_MODE_T;
typedef struct RingBuffer
{
int curSize;
RB_HANDLE_OVERFLOW_T handleOverflow;
struct Node *Write;
struct Node *Read;
Node_T buffer[RING_BUFFER_SIZE];
} RING_BUFFER_T;
///////////////////////////////////////////////////////////////////////////////
// Prototypes
///////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
extern "C" {
#endif
RB_ERC_T RB_InitRingBuffer(RING_BUFFER_T *rb_, RB_HANDLE_OVERFLOW_T ifOverflow_);
//Return true if the queue has no elements; false if there are elements on the queue
bool RB_IsEmpty(RING_BUFFER_T *rb_);
//Return true if the queue is full; false if there are seats available
bool RB_IsFull(RING_BUFFER_T *rb_);
//Write N elements (length of the array) to the queue
//Note: array values will be read from element 0 to array length
RB_ERC_T RB_WriteArray(RING_BUFFER_T *rb_, int values_[], int length_);
//Write 1 element
RB_ERC_T RB_Write(RING_BUFFER_T *rb_, int val_);
//Dequeue and read N elements (length of the array) into an array
RB_ERC_T RB_ReadArray(RING_BUFFER_T *rb_, int values_[], int length_, RB_READ_MODE_T readMode_);
//Dequeue and read 1 element
RB_ERC_T RB_Read(RING_BUFFER_T *rb_, int *readVal_, RB_READ_MODE_T readMode_);
#ifdef __cplusplus
}
#endif
#endif //_C_TEST_H_
Source:
#include "CTest.h"
static std::mutex m;
RB_ERC_T RB_InitRingBuffer(RING_BUFFER_T *rb_, RB_HANDLE_OVERFLOW_T handleOverflow_)
{
//m.lock();
RB_ERC_T erc = RB_ERC_NO_ERROR;
int i;
if(rb_ == 0)
{
return RB_ERC_NULL_PTR;
}
//Initialize this instance of the ring buffer
//Both the read/write pointers should start at the same location
rb_->curSize = 0;
rb_->Read = &rb_->buffer[0];
rb_->Write = &rb_->buffer[0];
rb_->handleOverflow = handleOverflow_;
//Build the circular doubly-linked list
for(i = 0; i < RING_BUFFER_SIZE; i++)
{
rb_->buffer[i].val = 0;
if(i == 0)
{
//Sentinal Node found. Point the first node to the last element of the array
rb_->buffer[i].previous = &rb_->buffer[(RING_BUFFER_SIZE - 1)];
rb_->buffer[i].next = &rb_->buffer[i + 1];
}
else if(i < (RING_BUFFER_SIZE - 1) )
{
rb_->buffer[i].next = &rb_->buffer[i + 1];
rb_->buffer[i].previous = &rb_->buffer[i - 1];
}
else
{
//Sentinal node found. Reached the last element in the array; Point the sentinal
//node to the first element in the array to create a circular linked list.
rb_->buffer[i].next = &rb_->buffer[0];
rb_->buffer[i].previous = &rb_->buffer[i - 1];
}
}
//m.unlock();
return erc;
}
bool RB_IsEmpty(RING_BUFFER_T *rb_)
{
//m.lock();
//Note: assume rb is valid.
if(rb_->curSize == 0)
{
return true;
}
else
{
return false;
}
//m.unlock();
}
bool RB_IsFull(RING_BUFFER_T *rb_)
{
//m.lock();
//Note: assume rb is valid.
if(rb_->curSize == RING_BUFFER_SIZE)
{
return true;
}
else
{
return false;
}
//m.unlock();
}
RB_ERC_T RB_WriteArray(RING_BUFFER_T *rb_, int values_[], int length_)
{
//m.lock();
RB_ERC_T erc = RB_ERC_NO_ERROR;
int i;
if(rb_ == 0 || values_ == 0 || length_ == 0)
{
return RB_ERC_NULL_PTR;
}
switch(rb_->handleOverflow)
{
//Increment through the array and enqueue
//If attempting to write more elements than are available on the queue
//Decimate - overwrite old data
//Ignore and return error - Don't write any data and throw an error
case RB_DECIMATE:
for(i = 0; i < length_; i++)
{
RB_Write(rb_, values_[i] );
}
break;
default:
case RB_IGNORE_AND_RETURN_ERROR:
{
int numSeatsAvailable = (RING_BUFFER_SIZE - rb_->curSize);
if( length_ <= numSeatsAvailable )
{
//Increment through the array and enqueue
for(i = 0; i < length_; i++)
{
RB_Write(rb_, values_[i] );
}
}
else
{
//Attempted to write more elements than are avaialable on the queue
erc = RB_ERC_OVERFLOW;
}
}
break;
}
//m.unlock();
return erc;
}
RB_ERC_T RB_Write(RING_BUFFER_T *rb_, int val_)
{
//m.lock();
RB_ERC_T erc = RB_ERC_NO_ERROR;
if(rb_ == 0)
{
return RB_ERC_NULL_PTR;
}
if( !RB_IsFull(rb_) )
{
//Write the value to the current location, then increment the write pointer
//so that the write pointer is always pointing 1 element ahead of the queue
rb_->Write->val = val_;
rb_->Write = rb_->Write->next;
rb_->curSize++;
}
else
{
//Overflow
switch(rb_->handleOverflow)
{
case RB_DECIMATE:
//Set the value and increment both the read/write pointers
rb_->Write->val = val_;
rb_->Write = rb_->Write->next;
rb_->Read = rb_->Read->next;
break;
default:
case RB_IGNORE_AND_RETURN_ERROR:
erc = RB_ERC_OVERFLOW;
break;
}
}
//m.unlock();
return erc;
}
RB_ERC_T RB_ReadArray(RING_BUFFER_T *rb_, int values_[], int length_, RB_READ_MODE_T readMode_)
{
//m.lock();
RB_ERC_T erc = RB_ERC_NO_ERROR;
if(values_ == 0)
{
return RB_ERC_NULL_PTR;
}
//Verify that the amount of data to be read is actually available on the queue
if( length_ <= rb_->curSize )
{
//Increment through the array and dequeue
int i;
for(i = 0; i < length_; i++)
{
//Note: Error conditions have already been checked. Skip the ERC check
(void) RB_Read(rb_, &values_[i], readMode_);
}
}
else
{
//Attempted to read more data than is available on the queue
erc = RB_ERC_UNDERFLOW;
}
//m.unlock();
return erc;
}
RB_ERC_T RB_Read(RING_BUFFER_T *rb_, int *readVal_, RB_READ_MODE_T readMode_)
{
//m.lock();
RB_ERC_T erc = RB_ERC_NO_ERROR;
if(rb_ == 0 || readVal_ == 0)
{
return RB_ERC_NULL_PTR;
}
if( !RB_IsEmpty(rb_) )
{
switch(readMode_)
{
case RB_LIFO:
//Use the head (Write) to read the most recently written value (newest data)
//Note: The write pointer is always pointing 1 position ahead of the current queue.
rb_->Write = rb_->Write->previous; //Decrement write pointer
//Read the data
*readVal_ = rb_->Write->val;
rb_->Write->val = 0; //Reset read values to 0
break;
default:
case RB_FIFO:
*readVal_ = rb_->Read->val;
rb_->Read->val = 0; //Reset read values to 0
rb_->Read = rb_->Read->next; //Increment read pointer
break;
}
rb_->curSize--;
}
else
{
//Attempted to read more data but there is no data available on the queue
erc = RB_ERC_UNDERFLOW;
}
//m.unlock();
return erc;
}
Main CPP using for tests:
#include "CTest.h"
#include <iostream>
#include "windows.h"
#include <thread>
using namespace std;
static RING_BUFFER_T test1;
const int dataSize = 300;
const int dataSizeout = 1000;
int sharedValue = 0;
static std::mutex m;
void function1()
{
int data[dataSize];
RB_ERC_T erc = RB_ERC_NO_ERROR;
for (int i = 0; i < dataSizeout; i++)
{
erc = RB_Write(&test1, i);
if (erc != RB_ERC_NO_ERROR)
{
printf("Count down errrror %d\n", erc);
}
}
//RB_WriteArray(&test1, data, dataSize);
}
void function2()
{
RB_ERC_T erc = RB_ERC_NO_ERROR;
for (int i = 0; i > -dataSizeout; i--)
{
erc = RB_Write(&test1, i);
if (erc != RB_ERC_NO_ERROR)
{
printf("Count down errrror %d\n", erc);
}
}
}
int main()
{
RB_InitRingBuffer(&test1, RB_DECIMATE);
thread p1(function1);
//Sleep(1000);
thread p2(function2);
p1.join();
p2.join();
//Read out 5 at a time
int out;
int cnt = 0;
while(cnt < (2 * dataSizeout) )
{
if (RB_Read(&test1, &out, RB_LIFO) == RB_ERC_NO_ERROR)
{
printf("out[%d] = %d\n", cnt, out);
cnt += 1;
}
}
system("Pause");
return 0;
}
I'm thinking that everything in the main RING_BUFFER_T instance would be shared variables, so everywhere they are used, which is pretty much everywhere, they would have to be enclosed in mutexes.
typedef struct RingBuffer
{
int curSize;
RB_HANDLE_OVERFLOW_T handleOverflow;
struct Node *Write;
struct Node *Read;
Node_T buffer[RING_BUFFER_SIZE];
} RING_BUFFER_T;
I suppose NODE_T would be as well, but only for initialization. Am I wrong or shouldn't the elements being stuffed in the ring buffer be placed out of order, since there is no mutex being used right now?
For a state-of-the-art C implementation of a lock-free ring buffer, look in the Linux kernel source code. That should give you some idea of how the experts do it, and it is battle-proven code. See linux/kfifo.h and corresponding C file(s).
design description of Linux ring buffer, dunno how up-to-date it is
For ideas of how to do it in C++, you can look at
Linux Journal article about C++ lock-free queue
or maybe look at boost::lockfree::queue. Using C++ of course enables you to use generic types (templates) and e.g. replace function pointers with compile-time bound calls, thus enabling even better performance than C. And you can avoid those pesky void* pointers.
Thou Shalt Not expose the functions RB_IsEmpty and RB_IsFull as the return values may be invalid immediately. If you only call them from within read/write there is no need to do protection within that functions.
Typically you must protect your struct within the externally exposed read and write functions from the first access to the last access. There is no need to protect parameter checking.
You shall not double lock. Do not call RB_Read from RB_ReadArray. Provide an internal read function used by both. Same for the write functions.

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.