Why is a struct member uninitialized after dereferencing the struct - c++

I'm writing an HBridge class to make handling HBridges one arduino much easier. I'm not sure why I call .print() on my HBridge instance, it prints:
---------
BRIDGE ONE
Bridge Use:->pin: 1392293344
Bridge Idle->pin: 1392293408
Freq:0
Dir:0
---------
BRIDGE TWO
Bridge Use:->pin: 8
Bridge Idle->pin: 214125355
Freq:0
Dir:0
Notice how the Bridge Use and Bridge Idle is uninitialized. Am I making a mistake somewhere with my pointers?
Here is my code.
HBridge.h
//-----------------------|
#define true 1 //|
#define false 0 //|
//-----------------------|
#define PIN_OFF 0 //|
#define PIN_ON 1 //|
//-----------------------|
#define PIN_FORWARD 0 //|
#define PIN_BACKWARD 1//|
//-----------------------|
typedef struct{
int pin;
} Pin;
typedef struct {
Pin *inuse;
Pin *idle;
int freq;
int direction;
}Bridge;
typedef enum{ A, B} hbridge_pins;
class HBridge {
private:
Bridge bridge_a, bridge_b;
Bridge *pins[2];
public:
HBridge(int, int, int, int);
void setPinFrequency(hbridge_pins, int);
void setPinDir(hbridge_pins, int);
void turnPinOFF(hbridge_pins);
void update(void);
void print();
};
HBridge.cpp
#import "./HBridge.h"
#import <stdio.h>
Pin pinWith(int num) {
// pinMode(num, OUTPUT);
Pin p;
p.pin = num;
return p;
}
void swap_pins(Pin *a, Pin *b) {
Pin temp = *a;
*a = *b;
*b = temp;
}
void print_pin(const char * name, Pin *p){
printf("%s->pin: %d\n",name,p->pin);
}
void print_bridge(Bridge *b){
print_pin("Bridge Use:", b->inuse);
print_pin("Bridge Idle", b->idle);
printf("Freq:%d\nDir:%d\n",b->freq,b->direction);
}
void HBridge::turnPinOFF(hbridge_pins pin) {
pins[pin]->freq = PIN_OFF;
}
HBridge::HBridge(int pinAA, int pinAB, int pinBA, int pinBB) {
Pin a_use = pinWith(pinAA);
Pin a_idle = pinWith(pinAB);
Pin b_use = pinWith(pinBA);
Pin b_idle = pinWith(pinBB);
bridge_a.inuse = &a_use;
bridge_a.idle = &a_idle;
bridge_b.inuse = &b_use;
bridge_b.idle = &b_idle;
/*---(DEFAULT DIRECTIONS)---*/
bridge_a.direction = PIN_FORWARD;
bridge_b.direction = PIN_FORWARD;
bridge_a.freq = PIN_OFF;
bridge_b.freq = PIN_OFF;
/*---(ARRAY OF POINTERS TO THE TWO PINS FOR EASY ACCESS BY INDEX)---*/
pins[0] =&bridge_a;
pins[1] =&bridge_b;
}
void HBridge::setPinFrequency(hbridge_pins pin, int freq) {
pins[pin]->freq = freq;
}
void HBridge::setPinDir(hbridge_pins pin, int dir) {
if ((pins[pin]->direction == PIN_FORWARD && dir == PIN_FORWARD) || (pins[pin]->direction == PIN_BACKWARD && dir == PIN_BACKWARD)) {
} else if (pins[pin]->direction == PIN_FORWARD && dir == PIN_BACKWARD) {
/*----(SWAP POINTERS)----*/
swap_pins(pins[pin]->inuse, pins[pin]->idle);
pins[pin]->direction = PIN_BACKWARD;
} else if (pins[pin]->direction == PIN_BACKWARD && dir == PIN_FORWARD) {
/*----(SWAP POINTERS)----*/
swap_pins(pins[pin]->inuse, pins[pin]->idle);
pins[pin]->direction = PIN_BACKWARD;
}
}
void HBridge::update(void)/*pointer to an int to save memory*/ {
/*THE FIRST BRIDGE*/
// analogWrite(pins[0]->inuse->pin, pins[0]->freq);
// analogWrite(pins[0]->indle->pin, pins[0]->PIN_OFF);
// THE SECOND BRIDGE
// analogWrite(pins[1]->inuse->pin, pins[1]->freq);
// analogWrite(pins[1]->indle->pin, pins[1]->PIN_OFF);
}
void HBridge::print(void){
printf("---------\nBRIDGE ONE\n");
print_bridge(pins[0]);
printf("---------\nBRIDGE TWO\n");
print_bridge(pins[1]);
}
int main(int argc, const char*argv[]){
HBridge b(31,42,33,4);
b.setPinFrequency(A,200);
b.print();
}

Pin a_use is local to the constructor and you are making a pointer from it, although it will be deallocated when the contsructor returns.
Declare inuse and idle as Pin inuse; and Pin idle; and don't make a pointer, just assign to them what pinWith() returns, the value will be copied and the problem will be gone.
If you need them to be pointers, then first request heap space like this
bridge_a.inuse = new Pin;
and then do this
memcpy(bridge_a.inuse, &a_use, sizeof(Pin));
if the Pin doesn't contain any class but just POD fields, it will work, otherwise a more elaborated copy will be needed.

Echoing #iharob. You have the same problem in the pinWith() function where you return a Pin off the stack for the pinWith() function, a position which becomes "garbage" once you return from the function. You'll need to allocate a Pin from the heap in pinWith() to fix this.
Pin pinWith(int num) {
// pinMode(num, OUTPUT);
Pin p = new Pin;
p.pin = num;
return p;
}

Related

The attributes of my child class are lazily initialized

I have created a parent class in C++ and one child class which I have two attributes: _trigger and _echo. In order to use my child class I declare it and I assign its address to a pointer of the parent class. Hence, I use the methods of my parent class.
My problem: When I use the method cyclePulse without parameters (int trigger, int echo) and the attributes from my class (_trigger and _echo), the method does not work properly. I guess it is because the attributes _trigger and _echo are lazily initialized, or because I am not using new keyword when I am creating my object.
class ISensor {
...
public:
ISensor();
virtual ~ISensor();
...
virtual int connect() = 0;
virtual char * readRequest() = 0;
virtual int disconnect() = 0;
};
class HCSR04: public ISensor {
private:
int _trigger;
int _echo;
public:
HCSR04();
HCSR04(int trigger, int echo);
...
int connect();
char * readRequest();
uint64_t cyclePulse(int trigger, int echo);
float distanceCentimeters();
};
Here is the implementation of HCSR04.cpp. Edited: I forgot the constructors.
HCSR04::HCSR04() {
_echo = RPI_V2_GPIO_P1_13;
_trigger = RPI_V2_GPIO_P1_15;
}
HCSR04::HCSR04(int trigger, int echo) {
_echo = echo;
_trigger = trigger;
}
char * HCSR04::readRequest() {
float preCent = distanceCentimeters();
char* buf = new char[20];
sprintf(buf, "%.10f", preCent);
return buf;
}
float HCSR04::distanceCentimeters() {
return (float) cyclePulse(_trigger, _echo) / 55.5;
}
uint64_t HCSR04::cyclePulse(int trigger, int echo) {
uint64_t width, begin, start, end;
int max = 80, check;
begin = bcm2835_st_read();
// Emit pulse for 10 microseconds
bcm2835_gpio_write(_trigger, HIGH); // Set trigger state HIGH
bcm2835_delayMicroseconds(10); // Wait 10 microseconds
bcm2835_gpio_write(_trigger, LOW); // Set trigger state LOW
while (bcm2835_gpio_lev(_echo) == LOW && check < max) {
start = bcm2835_st_read();
check = (int) begin - start;
}
while (bcm2835_gpio_lev(_echo) == HIGH) {
bcm2835_delayMicroseconds(1);
}
end = bcm2835_st_read();
width = end - start;
return width;
}
I am using the class like this:
HCSR04 deviceUltrasonic;
ISensor * sensorUltrasonic = &deviceUltrasonic;
char* readRequestArray = sensorUltrasonic->readRequest();
Giving my previous comment as a possible answer here, because I assume that the uninitialized variables are causing your fault here:
uint64_t HCSR04::cyclePulse(int trigger, int echo) {
uint64_t width, begin, start, end;
int max = 80, check = 0; // <<< init check to 0.
// Btw: size_t or any other unsigned type matches
// better the purpose of what you want to achieve.
begin = bcm2835_st_read();
// begin is not used afterwards. Did you mean to initialize "start" here?
start = begin;
// Emit pulse for 10 microseconds
bcm2835_gpio_write(_trigger, HIGH); // Set trigger state HIGH
bcm2835_delayMicroseconds(10); // Wait 10 microseconds
bcm2835_gpio_write(_trigger, LOW); // Set trigger state LOW
while (bcm2835_gpio_lev(_echo) == LOW && check < max) {
start = bcm2835_st_read();
check = (int) begin - start;
}
while (bcm2835_gpio_lev(_echo) == HIGH) {
bcm2835_delayMicroseconds(1);
}
end = bcm2835_st_read();
width = end - start;
return width;
}

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.

Decoder implementing a stack as a linked structure

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
{

How do I pass a pointer to an array of pointers as an argument to a function?

I'm trying to code a robot, and I'm having a confusing situation. I need to pass an array of pointers to objects to a constructor of a class. I can't, however, populate the array before I pass it into the constructor. To solve this I want to pass a pointer to said array, and access its elements from the pointer. The problem is that I'm new to C++, and so I'm not sure of the syntax. Could you guys help me out?
Code for the main file
class RobotDemo : public SimpleRobot
{
Joystick stick;
JoystickOne joyOne;
Victor *victors [8];
public:
RobotDemo(void):
stick(1),
joyOne(&stick)// these must be initialized in the same order
// as they are declared above.
/*It doesnt seem like I can do anything but initialize things here*/
{
/*Populate array with pointers to victors. Will need to update channels*/
for (int x = 1; x <= 7; x++) {
victors[x] = new Victor(x);
}
/*And I don't think I can initialize anything here*/
myRobot.SetExpiration(0.1);
}
/**
* Drive left & right motors for 2 seconds then stop
*/
void Autonomous(void)
{
}
/**
* Runs the motors with arcade steering.
*/
void OperatorControl(void)
{
myRobot.SetSafetyEnabled(true);
while (IsOperatorControl())
{
joyOne.testForActions(); /*Check joystick one for actions*/
Wait(0.005); // wait for a motor update time
}
}
/**
* Runs during test mode
*/
void Test() {
}
};
START_ROBOT_CLASS(RobotDemo);
Here's the code for the JoystickInput class, which the JoystickOne class extends
//the .h
#ifndef JOYSTICKINPUT_H
#define JOYSTICKINPUT_H
#include "WPILib.h"
class JoystickInput {
public:
JoystickInput(Joystick*);
JoystickInput(Joystick*, Victor* [8]);
Joystick * joystick;
bool buttons [10];
Victor** victors [8];
bool buttonClicked(int id);
virtual void testForActions();
};
#endif
//and the .cpp
#include "JoystickInput.h"
JoystickInput::JoystickInput(Joystick * joy) {
joystick = joy;
for (int x = 0; x < 10; x++) {
buttons[x] = false;
}
}
JoystickInput::JoystickInput(Joystick * joy, Victor* vicArray [8]) {
joystick = joy;
for (int x = 0; x < 10; x++) {
buttons[x] = false;
}
for (int n = 0; n <=7; n++) {
*victors[n] = vicArray[n];
}
}
bool JoystickInput::buttonClicked(int id) {
if (buttons[id] == false and joystick->GetRawButton(id) == true) {
buttons[id] = true;
return true;
} else if (buttons[id] == true and joystick->GetRawButton(id) == false) {
buttons[id] = false;
return false;
} else {
return false;
}
}
void JoystickInput::testForActions() {
}
What I'm asking you guys to help me do is rework the constructor of JoystickInput() so that it also takes a pointer to an array of pointers (to Victors), and performs methods on elements of the array. Googling it hasnt turned up anything useful. I'd research it more myself, but its been a few days and I'm still hung up on this.
Thanks for the help (and if not that, then at least reading my post)!
You should be able to use:
JoystickInput(Joystick*, Victor**, int);
and just pass vicArray into the constructor. If victors can be anything else than an array of length 8, then you should also pass the length as an argument because c++ cannot find the length of an array from a pointer.
Whenever types get complicated (functions or arrays), use a typedef:
typedef char char_buffer_type[8]; //char_buffer_type is an array
typedef char (*char_buffer_ptr)[8]; //char_buffer_ptr is a pointer to an array
typedef char (&char_buffer_ref)[8]; //char_buffer_ref is a reference to an array
typedef int main_type(int, char**); //main_type is a "int(int, char**)" function
typedef Victor*(array_of_ptr)[8]; //array_of_ptr is an array of 8 Victor*
Also, you should name the values 8 and 10.
class JoystickInput {
public:
static const int victor_count = 8;
static const int button_count = 10;
typedef Victor*(array_of_victor_ptr)[victor_count];
JoystickInput(Joystick*){}
JoystickInput(Joystick*, array_of_victor_ptr& vicArray);
bool buttonClicked(int id){return true;}
virtual void testForActions(){}
Joystick * joystick;
bool buttons [button_count];
array_of_victor_ptr victors; //that's simpler
};
//then pass this one by reference
JoystickInput::JoystickInput(Joystick * joy, array_of_victor_ptr& vicArray) {
joystick = joy;
for (int x = 0; x < button_count; x++) {
buttons[x] = false;
}
for (int n = 0; n < victor_count; n++) {
victors[n] = vicArray[n]; //don't have to dereference here anymore
}
}
Proof of compilation. Typedefs are wonderful. Use them.

Optimal technique to parse a real-time char* data received from a buffer for text content in C++

I have created a live continuous mjpeg stream. A crude illustration is like this
....[image (jpeg)]->[text "content-length"]->[image (jpeg)]->[text "content-length"]->....
As you can see I receive data from gstreamer media pipe line which contains image and my own injected text
(Note: Although I am using Gstreamer, my question is only related to C++ principles.)
In order to parse this real-time data, I am trying to receive and push it into the queue. Subsequently I plan to parse the data for the word "content-length" after queue contains a certain number of packets.
My code looks like the following:
void clear( std::queue<char> &q )
{
std::queue<char> empty;
std::swap( q, empty );
}
static GstFlowReturn new_buffer (GstAppSink *app_sink, gpointer user_data)
{
GstBuffer* buffer = gst_app_sink_pull_buffer(app_sink);
//create queue
std::queue<char> q;
g_print("The input buffer contents are\n");
gint i=0;
for(i=0; buffer->data[i];i++)
{
//g_print("\n%d",i);
q.push(buffer->data[i]);
}
//g_print("\nsize of inbuf is %d\n",GST_BUFFER_SIZE(buffer));
g_print("\n");
gst_buffer_unref(buffer);
//#####################
//parsing method here???
//#####################
clear(q);
return GST_FLOW_OK;
}
I have used circular queues/ ring buffer in C/C++ before. Is that the best option? Or is the C++ STL queues would be more appropriate in this scenario like above?
I ended up using ringbuffer class
In header file declare
//queue size
enum { rb_size = 5 }; // ---->element1 -> element2 -> .... -> elementN -> gap ->
// ^ |
// | |
// <--------------------<------------------<-------------V
typedef struct
{
char * data[rb_size];
int head, tail;
} ring_buffer_struct;
namespace myspace{
class ring_buffer{
private:
protected:
public:
//========= constructor ============
ring_buffer()
{
//If necessary initialization can happen here.
}
//========== destructor =============
virtual ~ring_buffer()
{
}
//===================================
virtual void rb_start(ring_buffer_struct *b);
virtual bool rb_empty(ring_buffer_struct const *b);
virtual char * rb_front(ring_buffer_struct const *b);
virtual char * rb_rear(ring_buffer_struct const *b);
virtual void rb_pop_front(ring_buffer_struct *b);
virtual ring_buffer_struct* rb_push_back(ring_buffer_struct *b);
}; //end of class
}
In cpp file
//start
void myspace::ring_buffer::rb_start(ring_buffer_struct *b)
{
b->head = 0; b->tail = 0;
}
//clear
bool myspace::ring_buffer::rb_empty(ring_buffer_struct const *b)
{
return b->head == b->tail;
}
//front element
char * myspace::ring_buffer::rb_front(ring_buffer_struct const *b)
{
return b->data[b->head]; //data gets popped
}
//rear element
char * myspace::ring_buffer::rb_rear(ring_buffer_struct const *b)
{
return b->data[b->tail]; //data gets pushed
}
//pop out front element
void myspace::ring_buffer::rb_pop_front(ring_buffer_struct *b)
{
if(b->head < b->tail)
{
++b->head;
}
if(b->head > b->tail)
{
b->head = 0;
}
}
//push in rear element
ring_buffer_struct* myspace::ring_buffer::rb_push_back(ring_buffer_struct *b)
{
int new_tail = b->tail;
if (++new_tail >= rb_size)
{ //beginning of the queue
new_tail = 0;
}
if (new_tail != b->head)
{
//middle of the queue
b->tail = new_tail;
}
if (new_tail <= b->head)
{
b->tail = 0;
}
return b;
}
And to use in the main()
...
char element1[10] = "abcdefghi";
char element2[10] = "bcdefghij";
char element3[10] = "cdefghijk";
ring_buffer_struct rb;
myspace::ring_buffer q;
q.rb_empty(&rb); //make sure empty
q.rb_start(&rb); //start - initialize
//initialize
uint16_t i;
for(i=0;i<rb_size;i++)
{
rb.data[rb.tail] = (char *)"000000000";
q.rb_push_back(&rb);
}
rb.data[rb.tail] = element1;
q.rb_push_back(&rb);
q.rb_pop_front(&rb); //now parse
rb.data[rb.tail] = element2;
q.rb_push_back(&rb);
q.rb_pop_front(&rb); //now parse
...
For parsing: I looked at this post
Simple string parsing with C++
Off topic suggestion:
When using the swap trick to clear out an STL container, don't call std::swap explicitly, as you may end up not getting a better-optimized version. The better way is:
void clear( std::queue<char> &q )
{
std::queue<char> empty;
using std::swap;
swap( q, empty );
}
This allows the compiler to choose a specialized version of swap that's optimized for the type of container you're using. You could also try q.swap(empty);, but I'm not sure all STL implementations offer that.