C++: Issues with Circular Buffer - c++

I'm having some trouble writing a circular buffer in C++. Here is my code base at the moment:
circ_buf.h:
#ifndef __CIRC_BUF_H__
#define __CIRC_BUF_H__
#define MAX_DATA (25) // Arbitrary size limit
// The Circular Buffer itself
struct circ_buf {
int s; // Index of oldest reading
int e; // Index of most recent reading
int data[MAX_DATA]; // The data
};
/*** Function Declarations ***/
void empty(circ_buf*);
bool is_empty(circ_buf*);
bool is_full(circ_buf*);
void read(circ_buf*, int);
int overwrite(circ_buf*);
#endif // __CIRC_BUF_H__
circ_buf.cpp:
#include "circ_buf.h"
/*** Function Definitions ***/
// Empty the buffer
void empty(circ_buf* cb) {
cb->s = 0; cb->e = 0;
}
// Is the buffer empty?
bool is_empty(circ_buf* cb) {
// By common convention, if the start index is equal to the end
// index, our buffer is considered empty.
return cb->s == cb->e;
}
// Is the buffer full?
bool is_full(circ_buf* cb) {
// By common convention, if the start index is one greater than
// the end index, our buffer is considered full.
// REMEMBER: we still need to account for wrapping around!
return cb->s == ((cb->e + 1) % MAX_DATA);
}
// Read data into the buffer
void read(circ_buf* cb, int k) {
int i = cb->e;
cb->data[i] = k;
cb->e = (i + 1) % MAX_DATA;
}
// Overwrite data in the buffer
int overwrite(circ_buf* cb) {
int i = cb->s;
int k = cb->data[i];
cb->s = (i + 1) % MAX_DATA;
}
circ_buf_test.cpp:
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include "circ_buf.h"
int main(int argc, char** argv) {
// Our data source
std::string file = "million_numbers.txt";
std::fstream in(file, std::ios_base::in);
// The buffer
circ_buf buffer = { .s = 0, .e = 0, .data = {} };
for (int i = 0; i < MAX_DATA; ++i) {
int k = 0; in >> k; // Get next int from in
read(&buffer, k);
}
for (int i = 0; i < MAX_DATA; ++i)
std::cout << overwrite(&buffer) << std::endl;
}
The main issue I'm having is getting the buffer to write integers to its array. When I compile and run the main program (circ_buf_test), it just prints the same number 25 times, instead of what I expect it to print (the numbers 1 through 25 - "million_numbers.txt" is literally just the numbers 1 through 1000000). The number is 2292656, in case this may be important.
Does anyone have an idea about what might be going wrong here?

Your function overwrite(circ_buf* cb) returns nothing (there are no return in it's body). So the code for printing of values can print anything (see "undefined behavior"):
for (int i = 0; i < MAX_DATA; ++i)
std::cout << overwrite(&buffer) << std::endl;
I expect you can find the reason of this "main issue" in the compilation log (see lines started with "Warning"). You can fix it this way:
int overwrite(circ_buf* cb) {
int i = cb->s;
int k = cb->data[i];
cb->s = (i + 1) % MAX_DATA;
return k;
}

Related

Heap corruption detected in C++ after removing strings

When running this code I get an error as shown in the image below.
I've tried running it on GCC compiler and it worked fine. But when running it on Visual Studio on Windows this error appeared:
Debug Error!
Program: C:\Users\yudab\source\repos\Project2\Debug\Project2.exe
HEAP CORRUPTION DETECTED: after Normal block (#153) at 0x014FD2E0.
CRT detected that the application wrote to memory after end of heap buffer.
After some testing it seems as the error only appears after trying to delete the second word.
#include <cstring>
#include <string>
#pragma warning(disable : 4996)
#include <iostream>
using namespace std;
void delStr(char**& lexicon, int& lexSize, char word[]);
void printAll(char** lexicon, int lexSize);
void retract2dArr(char**& arr, int& size);
int main() {
char** lexicon = new char* [3];
lexicon[0] = new char[6]{ "hello" };
lexicon[1] = new char[5]{ "test" };
lexicon[2] = new char[6]{ "world" };
int size = 3;
char removeTest[5] = { "test" }; //The first word I want to remove from the list
char removeWorld[6] = { "world" }; //The second word I want to remove from the list
printAll(lexicon, size); //First prints the entire list
delStr(lexicon, size, removeTest); //Removes the first word
delStr(lexicon, size, removeWorld); //Removes the second word
printAll(lexicon, size); //Prints the list after deleting the words
return 0;
}
void delStr(char**& lexicon, int& lexSize, char word[]) {
bool toDelete = false;
for (int i = 0; i < lexSize; i++) {
if (strcmp(lexicon[i], word) == 0) {
toDelete = true;
for (; i < lexSize - 1; i++) {
strcpy(lexicon[i], lexicon[i + 1]);
}
}
}
if (toDelete == true) {
delete[] lexicon[lexSize - 1];
retract2dArr(lexicon, lexSize);
}
return;
}
void printAll(char** lexicon, int lexSize) {
for (int i = 0; i < lexSize; i++) {
cout << lexicon[i];
if (i != lexSize - 1) {
cout << " ";
}
}
cout << endl;
return;
}
void retract2dArr(char**& arr, int& size) {
size--;
char** newArr = new char* [size];
for (int i = 0; i < size; i++) {
*(newArr + i) = *(arr + i);
}
printAll(newArr, size);
delete[] arr;
arr = newArr;
return;
}
You can't strcpy one string to another
if (strcmp(lexicon[i], word) == 0) {
toDelete = true;
for (; i < lexSize - 1; i++) {
strcpy(lexicon[i], lexicon[i + 1]);
}
}
As length will be different for each strings.
Example:
lexicon[0] = new char[6]{ "hello" };
lexicon[1] = new char[5]{ "test" }; // length is 4
lexicon[2] = new char[6]{ "world" }; // length is 5
3rd string won't fit in 2nd string, it causes out of bound access.
As kiran Biradar pointed out, the strcpy is to blame here. Although instead of copying each word in the lexicon to the memory allocated for the previous word, it would probably be better to simply move the pointers back withing the lexicon array.
Try something like this for your delStr function:
void delStr(char**& lexicon, int& lexSize, char word[]) {
for (int i = 0; i < lexSize; i++) {
if (strcmp(lexicon[i], word) == 0) {
delete[] lexicon[i];
for (; i < lexSize - 1; i++) {
lexicon[i] = lexicon[i + 1];
}
retract2dArr(lexicon, lexSize);
}
}
}
P.S. You didnt need to use a toDelete flag, you could call teh retract2dArr function within the first if.

Run-Time Check Failure #2 - Stack around the variable 'IDNumber' was corrupted

#include <iostream>
#include <string.h>
#include <time.h>
using namespace std;
struct MyID
{
char FirstName[10]; // array for lenight of the word.
char LastName[10]; // array for lenight of the word.
int IdNumber;
};
void InitializeArray(MyID IDNumber[], int Size);
//void SortTheArray(MyID IDNumber[], int Size);
int main(){
const int Size = 100;
MyID IDNumber[Size];
strcpy_s(IDNumber[Size].FirstName, "Aziz");
strcpy_s(IDNumber[Size].LastName, "LEGEND");
// I believe the error is around here.
InitializeArray(IDNumber, Size);
//SortTheArray(IDNumber, Size);
}
void InitializeArray(MyID IDNumber[], int Size){
//srand(time(0));
for (int i = 0; i < Size; i++){
//IDNumber[i].IdNumber = rand() %100 ;
cout<<IDNumber[i].FirstName<<endl;
IDNumber[i].LastName;
}
}
I have this problem, every time I want to test my function and struct, this error will prompt. Also, I want to see if my name will print correctly before continue to write rest program. The idea is I want to print same name every time without ask user to print name every time.
Also, I have upload the picture of result if you want to see it.
Because you are using arrays, you are experiencing buffer overrun error:
const int Size = 100;
MyID IDNumber[Size];
strcpy_s(IDNumber[Size].FirstName, "Aziz");
strcpy_s(IDNumber[Size].LastName, "LEGEND");
The expression IDNumber[Size] is equivalent to IDNumber[100].
In C++, array slot indices go from 0 to Size - 1. You are accessing one past the end of the array.
Edit 1: Initializing an array
Based on your comment, you can use a loop to initialize the slots in an array (vector):
struct Person
{
std::string first_name;
std::string last_name;
};
const unsigned int CAPACITY = 100;
int main()
{
std::vector<Person> database(CAPACITY);
Person p;
std::ostringstream name_stream;
for (unsigned int i = 0; i < CAPACITY; ++i)
{
name_stream << "Aziz" << i;
database[i].first_name = name_stream.str();
database[i].last_name = "LEGEND";
}
return 0;
}

Double free or corruption (fasttop) while executing Parallel version

I am trying to implement a serial algorithm in parallel manner using pthread.
Following is the code that i wrote -
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cmath>
#include <sys/time.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <ctime>
#include <vector>
#include <map>
#include <sstream>
using namespace std;
double similarity_score(char a,char b);
double find_array_max(double array[],int length);
void insert_at(char arr[], int n, int idx, char val);
void checkfile(int open, char filename[]);
void *main_algo(void* rank);
double valueChanger(int p1 , int p2);
string read_sequence(ifstream& f);
int ind;
double mu,delta;
double H_max = 0.;
int N_a; // get the actual lengths of the sequences
int N_b;
int** H;
int count_gap = 6;
int matrix_i = 1;
double temp[4];
char *nameof_seq_a;
char *nameof_seq_b;
string seq_a,seq_b;
int bigCount;
int start_i;
int stop_i;
int start_j;
int stop_j;
int stopSituation;
int k;
map<int,int> mymap;
std::string strValue;
std::stringstream out;
std::stringstream out2;
double value;
int main(int argc, char** argv){
// read info from arguments
if(argc!=5){
cout<<"Give me the propen number of input arguments:"<<endl<<"1 : mu"<<endl;
cout<<"2 : delta"<<endl<<"3 : filename sequence A"<<endl<<"4 : filename sequence B"<<endl;
cout<<"5 : maximal length N of sequences"<<endl;exit(1);
}
mu = atof(argv[1]);
delta = atof(argv[2]);
/////////////////////////////////
// give it the filenames
nameof_seq_a = argv[3];
nameof_seq_b = argv[4];
//int N_max = atoi(argv[5]);
// read the sequences into two vectors:
ifstream stream_seq_b; // first define the input-streams for seq_a and seq_b
stream_seq_b.open(nameof_seq_b); // the same for seq_b
checkfile(! stream_seq_b,nameof_seq_b);
seq_b = read_sequence(stream_seq_b);
ifstream stream_seq_a;
stream_seq_a.open(nameof_seq_a); // open the file for input
checkfile(! stream_seq_a,nameof_seq_a); // check, whether the file was opened successfully
seq_a = read_sequence(stream_seq_a);
// string s_a=seq_a,s_b=seq_b;
N_a = seq_a.length(); // get the actual lengths of the sequences
N_b = seq_b.length();
cout<<"N_a length "<<N_a<<endl;
cout<<"N_b length "<<N_b<<endl;
////////////////////////////////////////////////
// initialize H
int temp1 = N_a+1;
int temp2 = N_b+1;
// call to main algorithm
bigCount = N_a;
stopSituation = (N_a + N_b -1) / count_gap;
cout<<"--------Big Count----"<<bigCount<<endl;
cout<<"--------stopSituation----"<<stopSituation<<endl;
//cout<<"--------Matrix_i-------"<<matrix_i<<endl;
while(matrix_i <= stopSituation+1){
//cout<<"--------MATRIX_I----"<<matrix_i<<endl;
pthread_t myThreads[matrix_i];
for(k = 1; k < matrix_i +1 ; k++){
if(k == 1){
start_i = 1;
stop_j = (count_gap * (matrix_i))+1;
}
else if(k == matrix_i){
start_i = (count_gap * (k-1)) + 1;
stop_j = count_gap +1;
}
else{
start_i = (count_gap * (k-1)) + 1;
stop_j = (count_gap * ((matrix_i - k)+1))+1;
}
start_j = (count_gap * (matrix_i - k))+1;
stop_i = (count_gap * k)+1;
//main_algo();
pthread_create(&myThreads[k], NULL,main_algo, (void*)k);
}
//wait until all threads finish
for(k = 1; k<matrix_i+1; k++){
pthread_join(myThreads[k],NULL);
}
//sleep(1);
if(matrix_i > 1)
{
}
matrix_i++;
}
// Print the matrix H to the console
cout<<"**************** Max is = "<<H_max<<endl;
mymap.clear();
} // END of main
/////////////////////////////////////////////////////////////////////////////
// auxiliary functions used by main:
/////////////////////////////////////////////////////////////////////////////
void checkfile(int open, char filename[]){
if (open){cout << "Error: Can't open the file "<<filename<<endl;exit(1);}
else cout<<"Opened file "<<filename<<endl;
}
/////////////////////////////////////////////////////////////////////////////
double valueChanger(int p1 , int p2){
out.str(std::string());
out2.str(std::string());
out << p1;
out2 << p2;
strValue = out.str()+out2.str();
double value_new = atoi(strValue.c_str());
return value_new;
}
void *main_algo(void* rank){
//void main_algo(){
// algorithm
for(int i=start_i;i<stop_i;i++){
if(i > N_a) {
break;
}
for(int j=start_j;j<stop_j;j++){
if(j > N_b){
break;
}
int iCheck = i-1;
int jCheck = j-1;
value = valueChanger(iCheck , jCheck);
//double myVal = H[iCheck][jCheck];
double myVal;
if ( mymap.find(value) == mymap.end() ) {
// not found
myVal = 0;
} else {
// found
myVal = mymap.find(value)->second;
}
if(seq_a[i-1]==seq_b[j-1]){
temp[0]= myVal+1.0;
}
else{
temp[0]= myVal-mu;
}
value = valueChanger(i-1 , j-1);
if ( mymap.find(value) == mymap.end() ) {
// not found
temp[1] = 0;
} else {
// found
temp[1] = mymap.find(value)->second-delta;
}
value = valueChanger(i , j-1);
if ( mymap.find(value) == mymap.end() ) {
// not found
temp[2] = 0;
} else {
// found
temp[2] = mymap.find(value)->second-delta;
}
temp[3] = 0.;
value = valueChanger(i , j);
mymap[value] = find_array_max(temp,4);
if( H_max < mymap[value] ){
H_max = mymap[value];
}
}
}
cout<<"Done"<< my_rank<<endl;
}
double similarity_score(char a,char b){
double result;
if(a==b){
result=1.;
}
else{
result=-mu;
}
return result;
}
/////////////////////////////////////////////////////////////////////////////
double find_array_max(double array[],int length){
double max = array[0]; // start with max = first element
for(int i = 1; i<length; i++){
if(array[i] > max){
max = array[i];
}
}
return max; // return highest value in array
}
/////////////////////////////////////////////////////////////////////////////
string read_sequence(ifstream& f)
{
// overflows.
string seq;
char line[5000];
while( f.good() )
{
f.getline(line,5000);
// cout << "Line:" << line << endl;
if( line[0] == 0 || line[0]=='#' )
continue;
for(int i = 0; line[i] != 0; ++i)
{
int c = toupper(line[i]);
// cout << char(c);
if( c != 'A' && c != 'G' && c != 'C' && c != 'T' )
continue;
seq.push_back(char(c));
}
}
return seq;
}
Here , when i execute this program , i get following error
*** Error in `./myProg': double free or corruption (fasttop): 0xb5300480 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x767e2)[0xb74e67e2]
/lib/i386-linux-gnu/libc.so.6(+0x77530)[0xb74e7530]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZdlPv+0x1f)[0xb7689aaf]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZNSs4_Rep10_M_destroyERKSaIcE+0x1b)[0xb76ee5ab]
/usr/lib/i386-linux-gnu/libstdc++.so.6(+0xad5f0)[0xb76ee5f0]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZNSs6assignERKSs+0x82)[0xb76efde2]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZNSsaSERKSs+0x23)[0xb76efe33]
./myProg[0x80499dc]
./myProg[0x8049c2f]
/lib/i386-linux-gnu/libpthread.so.0(+0x6d78)[0xb7730d78]
/lib/i386-linux-gnu/libc.so.6(clone+0x5e)[0xb75613de]
======= Memory map: ========
*** Error in `./myProg': double free or corruption (fasttop): 0x0829c8f8 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x767e2)[0xb74e67e2]
/lib/i386-linux-gnu/libc.so.6(+0x77530)[0xb74e7530]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZdlPv+0x1f)[0xb7689aaf]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZNSs4_Rep10_M_destroyERKSaIcE+0x1b)[0xb76ee5ab]
/usr/lib/i386-linux-gnu/libstdc++.so.6(+0xad5f0)[0xb76ee5f0]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZNSsaSERKSs+0x23)[0xb76efe33]
./myProg[0x80499dc]
./myProg[0x8049aee]
/lib/i386-linux-gnu/libpthread.so.0(+0x6d78)[0xb7730d78]
Aborted (core dumped)
Please feel free to copy and execute with following two statements -
1) g++ [name].cpp -o [name] -lpthread
2) ./[name] 1 1 filetoread.txt filetoread2.txt
Please update for any kind of mistake i am doing in writing my code.
Thank you !!!!
You need to protect any non-thread-safe variables (such as std::map) with a mutex (or other locking mechanism). Since you're using pthread, take a look at pthread_mutex_lock, pthread_mutex_unlock, and pthread_mutex_destroy.
Here are some notes if you want to go multithreading:
don't (unless you really need to) ... (multithreading brings a new world of complexity and problems)
.... If you really need to, don't use more threads than processors (this is becoming muddled in recent years with CPUs/cores/hyperthreads... but what I mean by processor is what the hardware or virtualization allows you to run in parallel) (otherwise you will have scheduling contention at the OS/hardware level)
lock (mutexes) all common data access.... (otherwise you will corrupt your common data)
.... but try to lock the least possible time. (because every time you lock it means that all your threads need to wait and they will be doing nothing).
and don't use locks unless you need to (because locking/unlocking is expensive)
Avoid locking by using processing queues (e.g. to deliver commands or deliver results across threads). Instead of locking while processing the command/result, you can lock only while inserting/removing from the queue.
Avoid locking by subdividing map-like single structure (with a single mutex) into an array of map-like structure (with an array of mutexes) indexed with a hash of the key of the original map. Instead of locking all threads, you will be locking only some of them.
If there's an unbalance between readers/writers, try a read/write mutex to minimize contention. Ths will allow multiple simultaneous readers or one writer.

c++ Floodfill algorithm final errors

My floodfilling algorithm is nearly finished, but there is a small error somewhere, I've spent about 3 hours debugging, but i can't seem to find it!
note:
When reading in I use numbers from 0 to 15 to define the walls
1 = top
2 = right
4 = bottom
8 = left
(so 13 would mean that the top/bottom/left walls are there)
My Program:
It reads in number of fields to calculate the biggest room from (so everything below here is a cycle that gets repeated for the number of fields).
Then it gets the room's dimensions
Now in the class field, it creates an array of objects (Cell) which store the walls around (left right down up), and a value below 16
Now here is where I think the problem comes, reading in values through std::cin
and then when everything is read in, it scans for empty (0), and then creates a room, and checks for availeble spaces around it (using the wall-check)
and at the end it returns the max value, and we are done.
The input I use:
1
2 2
13 3
15 14
so what happens is is that somewhere, in or the wall-check, or the creation of a object Cell something goes wrong (I think)
Here is my script, and sorry to have to ask something silly like this!
Thanks in advance
// een simpele floodfill
#include <stdlib.h>
#include <iostream>
#include <bitset>
class Cell {
private:
int kamer, value;
bool left, right, up, down;
public:
// constructor
Cell::Cell() {};
// functions
bool CanLeft() { return left ; }
bool CanRight() { return right; }
bool CanDown() { return down ; }
bool CanUp() { return up ; }
int GetRoom() { return kamer; }
void SetRoom(int x) { kamer = x ; }
void SetValue(int x, int room=0) { value = x;
kamer = room;
std::bitset<sizeof(int)> bits(value);
if (bits[3]) left = true;
else left = false;
if (bits[2]) down = true;
else down = false;
if (bits[1]) right = true;
else right = false;
if (bits[0]) up = true;
else up = false;
}
};
class Field {
private:
int Biggest_Chamber;
int Y;
int X;
int temp;
Cell playfield[][1];
public:
// constructor
Field::Field(int SizeY, int SizeX) {
Y = SizeY;
X = SizeX;
Cell playfield[SizeY-1][SizeX-1];
}
// Create a 2d array and fill it
void Get_input() {
for (int Yas = 0; Yas < Y; Yas++){
for (int Xas = 0; Xas < X; Xas++){
std::cin >> temp;
playfield[Yas][Xas].SetValue(temp);
}
}
};
void Start() { Mark(0,0,1); }
void Mark(int y, int x, int nr) {
std::cout << nr;
temp = nr;
playfield[y][x].SetRoom(nr);
if (playfield[y][x].CanLeft()) {
if (playfield[y][x-1].GetRoom() != 0) {
Mark(y, x-1, nr);
std::cout << nr;
system("pause");}}
if (playfield[y][x].CanDown()) {
if (playfield[y+1][x].GetRoom() != 0) {
Mark(y+1, x, nr);
std::cout << nr;
system("pause");}}
if (playfield[y][x].CanRight()) {
if (playfield[y][x+1].GetRoom() != 0) {
Mark(y, x+1, nr);
std::cout << nr;
system("pause");}}
if (playfield[y][x].CanUp()) {
if (playfield[y-1][x].GetRoom() != 0) {
Mark(y-1, x, nr);
std::cout << nr;
system("pause");}}
for (int vertical = 0; vertical < Y; vertical++) {
for (int horizontal = 0; horizontal < X; horizontal++) {
if (playfield[vertical][horizontal].GetRoom() == 0) Mark(vertical, horizontal, nr+1);
}
}
}
int MaxValue() {
int counter[temp];
int max = 0;
for (int y = 0; y < Y; y++) {
for (int x = 0; x < X; x++) {
counter[playfield[y][x].GetRoom()]++;
}
}
for (int i = 0; i < temp; i++)
{
if (counter[i] > max)
max = counter[i];
}
return max;
}
};
int main() {
using namespace std;
int NrKamers;
int sizeY;
int sizeX;
std::cin >> NrKamers;
for (int i = 0; i < NrKamers; i++){
std::cin >> sizeY >> sizeX;
Field floodfield(sizeY, sizeX);
floodfield.Get_input();
floodfield.Start();
std::cout << floodfield.MaxValue() << std::endl;
}
return 0;
}
I have not had much time to deal with the code, but my first impression is that you are not marking (or rather not using the mark) each visited position in the array, so that you move in one direction, and while processing that other position you return back to the original square. Consider that the sequence of tests where: left, right, up, down; and that you start in the top-left corner:
You cannot move left, but you can move right. At that second recursion level you can move left and go back to square one. Then you cannot move left, but you can move right, so you go back to square two, from which you move to square one... infinitedly.
Before you move to the next square you have to mark your square as visited, and also check that the square you intend to move to has not been visited in the current run.
The segmentation fault is the result of infinite recursion, after you exhaust the stack.
1-11-2017: NEW-VERSION; SUCCESFULLY TESTED WITH TWO BITMAPS.
I propose my C version of the Flood-Fill algorithm, which doesn't uses recursive calls, but only a queue of the offsets of the new points, it works on the window: WinnOffs-(WinDimX,WinDimY) of the double-buffer: *VBuffer (copy of the screen or image) and, optionally, it write a mask of the flood-fill's result (*ExtraVBuff).
ExtraVBuff must be filled it with 0 before the call (if you don't need a mask you may set ExtraVBuff= NULL); using it after call you can do gradient floodfill or other painting effects. NewFloodFill works with 32 Bit per Pixel and it is a C function. I've reinvented this algorithm in 1991 (I wrote his in Pascal), but now it works in C with 32 Bit per Pixel; also not uses any functions calls, does only a division after each "pop" from queue, and never overflows the queue, that, if it is sized in the right way (about 1/4 of the pixels of the image), it allows always to fill correctly any area; I show before the c-function (FFILL.C), after the test program (TEST.C):
#define IMAGE_WIDTH 1024
#define IMAGE_HEIGHT 768
#define IMAGE_SIZE IMAGE_WIDTH*IMAGE_HEIGHT
#define QUEUE_MAX IMAGE_SIZE/4
typedef int T_Queue[QUEUE_MAX];
typedef int T_Image[IMAGE_SIZE];
void NewFloodFill(int X,
int Y,
int Color,
int BuffDimX,
int WinOffS,
int WinDimX,
int WinDimY,
T_Image VBuffer,
T_Image ExtraVBuff,
T_Queue MyQueue)
/* Replaces all pixels adjacent to the first pixel and equal to this; */
/* if ExtraVBuff == NULL writes to *VBuffer (eg BUFFER of 786432 Pixel),*/
/* otherwise prepare a mask by writing on *ExtraVBuff (such BUFFER must */
/* always have the same size as *VBuffer (it must be initialized to 0)).*/
/* X,Y: Point coordinates' of origin of the flood-fill. */
/* WinOffS: Writing start offset on *VBuffer and *ExtraVBuff. */
/* BuffDimX: Width, in number of Pixel (int), of each buffer. */
/* WinDimX: Width, in number of Pixel (int), of the window. */
/* Color: New color that replace all_Pixel == origin's_point. */
/* WinDimY: Height, in number of Pixel (int), of the window. */
/* VBuffer: Pointer to the primary buffer. */
/* ExtraVBuff: Pointer to the mask buffer (can be = NULL). */
/* MyQueue: Pointer to the queue, containing the new-points' offsets*/
{
int VBuffCurrOffs=WinOffS+X+Y*BuffDimX;
int PixelIn=VBuffer[VBuffCurrOffs];
int QueuePnt=0;
int *TempAddr=((ExtraVBuff) ? ExtraVBuff : VBuffer);
int TempOffs1;
int TempX1;
int TempX2;
char FLAG;
if (0<=X && X<WinDimX && 0<=Y && Y<WinDimY) do
{
/* Fill to left the current line */
TempX2=X;
while (X>=0 && PixelIn==VBuffer[VBuffCurrOffs])
{
TempAddr[VBuffCurrOffs--]=Color;
--X;
}
TempOffs1=VBuffCurrOffs+1;
TempX1=X+1;
/* Fill to right the current line */
VBuffCurrOffs+=TempX2-X;
X=TempX2;
while (X+1<WinDimX && PixelIn==VBuffer[VBuffCurrOffs+1])
{
++X;
TempAddr[++VBuffCurrOffs]=Color;
}
TempX2=X;
/* Backward scan of the previous line; puts new points offset in Queue[] */
if (Y>0)
{
FLAG=1;
VBuffCurrOffs-=BuffDimX;
while (X-->=TempX1)
{
if (PixelIn!=VBuffer[VBuffCurrOffs] ||
ExtraVBuff && Color==ExtraVBuff[VBuffCurrOffs])
FLAG=1;
else
if (FLAG)
{
FLAG=0;
if (QueuePnt<QUEUE_MAX)
MyQueue[QueuePnt++]=VBuffCurrOffs;
}
--VBuffCurrOffs;
}
}
/* Forward scan of the next line; puts new points offset in Queue[] */
if (Y<WinDimY-1)
{
FLAG=1;
VBuffCurrOffs=TempOffs1+BuffDimX;
X=TempX1;
while (X++<=TempX2)
{
if (PixelIn!=VBuffer[VBuffCurrOffs] ||
ExtraVBuff && Color==ExtraVBuff[VBuffCurrOffs])
FLAG=1;
else
if (FLAG)
{
FLAG=0;
if (QueuePnt<QUEUE_MAX)
MyQueue[QueuePnt++]=VBuffCurrOffs;
}
++VBuffCurrOffs;
}
}
/* Gets a new point offset from Queue[] */
if (--QueuePnt>=0)
{
VBuffCurrOffs=MyQueue[QueuePnt];
TempOffs1=VBuffCurrOffs-WinOffS;
X=TempOffs1%BuffDimX;
Y=TempOffs1/BuffDimX;
}
/* Repeat the main cycle until the Queue[] is not empty */
} while (QueuePnt>=0);
}
Here there is the test program:
#include <stdio.h>
#include <malloc.h>
#include "ffill.c"
#define RED_COL 0xFFFF0000
#define WIN_LEFT 52
#define WIN_TOP 48
#define WIN_WIDTH 920
#define WIN_HEIGHT 672
#define START_LEFT 0
#define START_TOP 671
#define BMP_HEADER_SIZE 54
typedef char T_Image_Header[BMP_HEADER_SIZE];
void main(void)
{
T_Image_Header bmpheader;
T_Image *image;
T_Image *mask;
T_Queue *MyQueue;
FILE *stream;
char *filename1="ffill1.bmp";
char *filename2="ffill2.bmp";
char *filename3="ffill3.bmp";
int bwritten;
int bread;
image=malloc(sizeof(*image));
mask=malloc(sizeof(*mask));
MyQueue=malloc(sizeof(*MyQueue));
stream=fopen(filename1,"rb");
bread=fread(&bmpheader, 1, BMP_HEADER_SIZE, stream);
bread=fread((char *)image, 1, IMAGE_SIZE<<2, stream);
fclose(stream);
memset(mask,0,IMAGE_SIZE<<2);
NewFloodFill(START_LEFT,
START_TOP,
RED_COL,
IMAGE_WIDTH,
IMAGE_WIDTH*WIN_TOP+WIN_LEFT,
WIN_WIDTH,
WIN_HEIGHT,
*image,
NULL,
*MyQueue);
stream=fopen(filename2,"wb+");
bwritten=fwrite(&bmpheader, 1, BMP_HEADER_SIZE, stream);
bwritten=fwrite((char *)image, 1, IMAGE_SIZE<<2, stream);
fclose(stream);
stream=fopen(filename3,"wb+");
bwritten=fwrite(&bmpheader, 1, BMP_HEADER_SIZE, stream);
bwritten=fwrite((char *)mask, 1, IMAGE_SIZE<<2, stream);
fclose(stream);
free(MyQueue);
free(mask);
free(image);
}
I've used, for the input of the test program shown, the follow Windows uncompressed .BMP image (ffill1.bmp):
Filled, by the test program shown, as follows (ffill2.bmp):
Using "mask" instead of NULL, the output bitmap is (ffill3.bmp):

Adding a string or char array to a byte vector

I'm currently working on a class to create and read out packets send through the network, so far I have it working with 16bit and 8bit integers (Well unsigned but still).
Now the problem is I've tried numerous ways of copying it over but somehow the _buffer got mangled, it segfaulted, or the result was wrong.
I'd appreciate if someone could show me a working example.
My current code can be seen below.
Thanks, Xeross
Main
#include <iostream>
#include <stdio.h>
#include "Packet.h"
using namespace std;
int main(int argc, char** argv)
{
cout << "#################################" << endl;
cout << "# Internal Use Only #" << endl;
cout << "# Codename PACKETSTORM #" << endl;
cout << "#################################" << endl;
cout << endl;
Packet packet = Packet();
packet.SetOpcode(0x1f4d);
cout << "Current opcode is: " << packet.GetOpcode() << endl << endl;
packet.add(uint8_t(5))
.add(uint16_t(4000))
.add(uint8_t(5));
for(uint8_t i=0; i<10;i++)
printf("Byte %u = %x\n", i, packet._buffer[i]);
printf("\nReading them out: \n1 = %u\n2 = %u\n3 = %u\n4 = %s",
packet.readUint8(),
packet.readUint16(),
packet.readUint8());
return 0;
}
Packet.h
#ifndef _PACKET_H_
#define _PACKET_H_
#include <iostream>
#include <vector>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
using namespace std;
class Packet
{
public:
Packet() : m_opcode(0), _buffer(0), _wpos(0), _rpos(0) {}
Packet(uint16_t opcode) : m_opcode(opcode), _buffer(0), _wpos(0), _rpos(0) {}
uint16_t GetOpcode() { return m_opcode; }
void SetOpcode(uint16_t opcode) { m_opcode = opcode; }
Packet& add(uint8_t value)
{
if(_buffer.size() < _wpos + 1)
_buffer.resize(_wpos + 1);
memcpy(&_buffer[_wpos], &value, 1);
_wpos += 1;
return *this;
}
Packet& add(uint16_t value)
{
if(_buffer.size() < _wpos + 2)
_buffer.resize(_wpos + 2);
memcpy(&_buffer[_wpos], &value, 2);
_wpos += 2;
return *this;
}
uint8_t readUint8()
{
uint8_t result = _buffer[_rpos];
_rpos += sizeof(uint8_t);
return result;
}
uint16_t readUint16()
{
uint16_t result;
memcpy(&result, &_buffer[_rpos], sizeof(uint16_t));
_rpos += sizeof(uint16_t);
return result;
}
uint16_t m_opcode;
std::vector<uint8_t> _buffer;
protected:
size_t _wpos; // Write position
size_t _rpos; // Read position
};
#endif // _PACKET_H_
Since you're using an std::vector for your buffer, you may as well let it keep track of the write position itself and avoid having to keep manually resizing it. You can also avoid writing multiple overloads of the add function by using a function template:
template <class T>
Packet& add(T value) {
std::copy((uint8_t*) &value, ((uint8_t*) &value) + sizeof(T), std::back_inserter(_buffer));
return *this;
}
Now you can write any POD type to your buffer.
implicitly:
int i = 5;
o.write(i);
or explictly:
o.write<int>(5);
To read from the buffer, you will need to keep track of a read position:
template <class T>
T read() {
T result;
uint8_t *p = &_buffer[_rpos];
std::copy(p, p + sizeof(T), (uint8_t*) &result);
_rpos += sizeof(T);
return result;
}
You will need to explicitly pass a type parameter to read. i.e.
int i = o.read<int>();
Caveat: I have used this pattern often, but since I am typing this off the top of my head, there may be a few errors in the code.
Edit: I just noticed that you want to be able to add strings or other non-POD types to your buffer. You can do that via template specialization:
template <>
Packet& add(std::string s) {
add(string.length());
for (size_t i = 0; i < string.length(); ++i)
add(string[i]);
return *this;
}
This tells the compiler: if add is called with a string type, use this function instead of the generic add() function.
and to read a string:
template <>
std::string read<>() {
size_t len = read<size_t>();
std::string s;
while (len--)
s += read<char>();
return s;
}
You could use std::string as internal buffer and use append() when adding new elements.
Thus adding strings or const char* would be trivial.
Adding/writing uint8 can be done with casting it to char, writing uint16 - to char* with length sizeof(uint16_t).
void write_uint16( uint16_t val )
{
m_strBuffer.append( (char*)(&var), sizeof(val) );
}
Reading uint16:
uint16_t read_int16()
{
return ( *(uint16_t*)(m_strBuffer.c_str() + m_nOffset) );
}
You appear to be attempting to print ten bytes out of the buffer when you've only added four, and thus you're running off the end of the vector. This could be causing your seg fault.
Also your printf is trying to print a character as an unsigned int with %x. You need to use static_cast<unsigned>(packet._buffer[i]) as the parameter.
Stylistically:
Packet packet = Packet(); could potentially result in two objects being constructed. Just use Packet packet;
Generally try to avoid protected attributes (protected methods are fine) as they reduce encapsulation of your class.