C++ reading some bytes at a memory address, output as string - c++

A function returns a pointer and a length (via the arguments) from an unknown DLL.
Result = SpamnEggs( &pBytes, &nBytes )
The pointer points to a valid memory address at which are nBytes sequential bytes.
These bytes contain valid ascci values for text. There is no null termination!
I am tasked with "ovelaying" a string type of some sort in as few simple operations in generic C++ code (without complex libraries or using byte) before output:
cout << sresult
Added:
without copying the bytes as this is a large buffer that must be traversed.
Prototype:
int SpamnEggs( void* pBytes, void* nBytes );
becomes
int SpamnEggs( char** pBytes, int* nBytes );
Many thanks all. Great answers and all very valid.

You can copy the raw memory and add the string terminating character yourself:
char* newStr = new char[size + 1];
memcpy ( newStr, source, size );
newStr[size] = "\0";
cout << newStr;
Without copying memory, you can create a class that holds the pointer and length as members and overload the stream operator to print only length characters:
class MyString
{
void* _pBuf;
int _length;
public:
MyString(void* pBuf, int length)
{
_pBuf = pBuf;
_length = length;
}
friend ostream& operator <<(ostream &os,const MyString& obj);
};
ostream& operator <<(ostream &os,const MyString& obj)
{
const char* pChar = (const char*)obj._pBuf;
for ( int i = 0 ; i < obj._length ; i++ )
{
os << pChar[i];
}
return os;
}
Example usage:
char* x = "blablabla";
int length = 3;
MyString str(x,length);
cout << str;

You can just construct a std::string from the pointer and a length.
std::string sResult(pBytes, nBytes);
std::cout << sResult;
(assuming pBytes is a char* pointer, otherwise you need a small cast).

How about something like this (untested) code:
class my_pointer_string
{
friend std::ostream &operator<<(std::ostream &, const my_pointer_string &);
public:
my_pointer_string(void *ptr, size_t len)
: m_pointer(ptr), m_length(len)
{ }
private:
void *m_pointer;
size_t m_length;
};
std::ostream &operator<<(std::ostream &os, const my_pointer_string &str)
{
char *string = reinterpret_cast<char *>(str.m_pointer);
for (size_t i = 0; i < str.m_length; i++)
os << *string++;
return os;
}

What you would have to do is
a) Create some class that encapsulates the char pointer and the size.
b) Write a << operator for that class to output its content to a stream.
EDIT: In contrast to the response by Bo Persson this would not imply copying the source data.

Related

How do I deserialise a const byte * to a structure in cpp?

I have a structure like this
struct foo {
string str1;
uint16_t int1
string str2;
uint32_t int2;
string str3;
};
strings str1, str2 , str3 are of fixed length of 12 bytes, 3 bytes,etc. left padded with spaces.
I have a function
void func(const byte* data, const size_t len) which is supposed to convert the byte * data to structure foo. len is length of data.What are the ways in which I can do this?
Again the data is const pointer of byte type and will not have null characters in between to distinguish different members.
Should I use character array instead of string for str1, str2, str3?
Easiest (but most errorprone) way is to just reinterpret_cast / std::memcpy if the strings have fixed length:
// no padding
#pragma pack(push, 1)
struct foo {
char str1[12];
uint16_t int1;
char str2[3];
uint32_t int2;
char str3[4];
};
#pragma pack(pop)
void func(const byte* data, const size_t len) {
assert(len == sizeof(foo));
// non owning
const foo* reinterpreted = reinterpret_cast<const foo*>(data);
// owning
foo reinterpreted_val = *reinterpret_cast<const foo*>(data);
foo copied;
memcpy(&copied, data, len);
}
Notes:
Make sure that you're allowed to use reinterpret_cast
https://en.cppreference.com/w/cpp/language/reinterpret_cast#Type_aliasing
if you'd try to use strlen or another string operation on any of the strings you most likely will get UB, since the strings are not null terminated.
Slightly better approach:
struct foo {
char str1[13];
uint16_t int1;
char str2[4];
uint32_t int2;
char str3[5];
};
void func(const char* data, const size_t len) {
foo f;
memcpy(f.str1, data, 12);
f.str1[12] = '\0';
data+=12;
memcpy(&f.int1, data, sizeof(uint16_t));
data+=sizeof(uint16_t);
memcpy(f.str2, data, 3);
f.str2[3] = '\0';
data+=3;
memcpy(&f.int2, data, sizeof(uint32_t));
data+=sizeof(uint32_t);
memcpy(f.str3, data, 4);
f.str3[4] = '\0';
data+=4;
}
Notes:
You could combine both approaches to get rid of the pointer arithmetic. That would also account for any padding in your struct you might have.
I think the easiest way to do this is to change the string inside the structure
to the type of char. Then you can easily copy the objects of this
structure according to its size.
you will have to somehow deal with the byte order on machines with different byte
order
struct foo {
char str1[12];
uint16_t int1;
char str2[3];
uint32_t int2;
char str3[5];
};
byte* Encode(foo* p, int Size) {
int FullSize = Size * sizeof(foo);
byte* Returner = new byte[FullSize];
memcpy_s(Returner, FullSize, p, FullSize);
return Returner;
}
foo * func(const byte* data, const size_t len) {
int ArrSize = len/sizeof(foo);
if (!ArrSize || (ArrSize* sizeof(foo)!= len))
return nullptr;
foo* Returner = new foo[ArrSize];
memcpy_s(Returner, len, data, len);
return Returner;
}
int main()
{
const size_t ArrSize = 3;
foo Test[ArrSize] = { {"Test1",1000,"TT",2000,"cccc"},{"Test2",1001,"YY",2001,"vvvv"},{"Test1",1002,"UU",2002,"bbbb"}};
foo* Test1 = nullptr;
byte* Data = Encode(Test, ArrSize);
Test1 = func(Data, ArrSize * sizeof(foo));
if (Test1 == nullptr) {
std::cout << "Error extracting data!" << std::endl;
delete [] Data;
return -1;
}
std::cout << Test1[0].str1 << " " << Test1[1].str1 << " " << Test1[2].str3 << std::endl;
delete [] Data;
delete[] Test1;
return 0;
}
output
Test1 Test2 bbbb

No suitable constructor exists to convert from const char to "custom string", though I have created one

I am doing a custom string class in C++. However, when I debugged my code, the system said that:
Error E0415:no suitable constructor exists to convert from "const char" to "string"
Here is my header file where my custom string class is defined:
#ifndef _STRING
#define _STRING
#include <iostream>
class string {
private:
char* s = nullptr;
unsigned int size = 0;
public:
string();
~string() { delete s; };
void operator=(const char*);
friend std::ostream& operator<<(std::ostream&, string&);
};
#endif
string::string()
: s{ nullptr }
{
s = new char[1];
s[0] = '\0';
}
void string::operator=(const char* source)
{
if (source == nullptr) {
s = new char[1];
s[0] = '\0';
}
else {
size = strlen(source) + 1;
s = new char[size];
for (int k = 1; k < (strlen(source) + 1); k++) {
s[k] = source[k];
}
}
}
std::ostream& operator<<(std::ostream& output, string& result)
{
output << result.s;
return output;
}
And here is my main file which I tried to comply:
#include "custom_string.h"
int main()
{
string a;
a = "testfile";
std::cout << a;
system("pause");
return 1;
}
As you can see, I have declared a constructor to convert const char to my custom string by overloading assignment operator. However, there should be something wrong in my code and I could not find out it. Please help me and thank you
Thanks everyone, I have done to fix it. As it turned out, I have to declare one more constructor to covert between my custom string and const char. That is something like this:
string::string(const string& t){}
string& string::operator=(const char&source){}

Segmentation fault: 11 and malloc errors in C++ code

Ok, so I know there are probably a lot of errors in this code. I'm pretty new to dynamic memory allocation, pointers, etc.
The header file, account.h, is given to us by our professor. We were told not to make any changes to the .h file.
The implementation file is written by me. The main function is included just for basic initial testing. We were given another file to actually test the implementation of the account class.
If I don't comment out the cout name line, I get a seg fault 11 error.
If I do, it'll print the account number, but throw this error:
Test(29976) malloc: * error for object 0x62c1aa18c9d8374: pointer being freed was not allocated* set a breakpoint in malloc_error_break to debug
Abort trap: 6
Any help at all would be greatly appreciated!
Here's the header file:
class account
{
public:
typedef char* string;
static const size_t MAX_NAME_SIZE = 15;
// CONSTRUCTOR
account (char* i_name, size_t i_acnum, size_t i_hsize);
account (const account& ac);
// DESTRUCTOR
~account ( );
// MODIFICATION MEMBER FUNCTIONS
void set_name(char* new_name);
void set_account_number(size_t new_acnum);
void set_balance(double new_balance);
void add_history(char* new_history);
// CONSTANT MEMBER FUNCTIONS
char* get_name ( ) const;
size_t get_account_number ( ) const;
double get_balance( ) const;
size_t get_max_history_size( ) const;
size_t get_current_history_size ( ) const;
string* get_history( ) const;
friend ostream& operator <<(ostream& outs, const account& target);
private:
char name[MAX_NAME_SIZE+1]; //name of the account holder
size_t ac_number; //account number
double balance; //current account balance
string *history; //Array to store history of transactions
size_t history_size; //Maximum size of transaction history
size_t history_count; //Current size of transaction history
};
Here is the implementation file:
// File: account.cxx
// Author: Mike Travis
// Last Modified: Mar 3, 2012
// Description: implementation of Account class as prescribed by the file account.h
#include <cstdlib>
#include <stdio.h>
#include <iostream>
#include "account.h"
using namespace std;
//Constructor
account::account(char* i_name, size_t i_acnum, size_t i_hsize){
string *d_history;
d_history = new string[i_hsize];
for(int i = 0; i<i_hsize; i++){
name[i] = i_name[i];
}
ac_number = i_acnum;
history_size = i_hsize;
history_count = 0;
}
account::account(const account& ac){
string *d_history;
d_history = new string[ac.history_size];
for( int i=0; i<ac.get_current_history_size(); i++){
strcpy(d_history[i], history[i]);
}
strcpy(name,ac.get_name());
ac_number = ac.get_account_number();
history_size = ac.get_max_history_size();
history_count = ac.get_current_history_size();
}
account::~account(){ delete [] history; }
void account::set_name(char* new_name){ strcpy(name, new_name); }
void account::set_account_number(size_t new_acnum){ ac_number = new_acnum; }
void account::set_balance(double new_balance){ balance = new_balance; }
void account::add_history(char* new_history){
strcpy(history[history_count], new_history);
history_count++;
}
char* account::get_name() const {
char* name_cpy;
strcpy(name_cpy, name);
return name_cpy;
}
size_t account::get_account_number() const{ return ac_number; }
double account::get_balance() const{ return balance; }
size_t account::get_max_history_size() const{ return history_size; }
size_t account::get_current_history_size() const{ return history_count; }
//string* account::get_history() const{ return *history; }
int main(){
account test1("mike travis", 12345, 20);
//cout<<"\nname: "<< test1.get_name();
cout<<"\n\nacnum: "<<test1.get_account_number()<<"\n\n";
return 0;
}
In the destructor of account, you delete the history array. However, in the constructor, you allocate (and leak) an array which is stored in the local variable d_history. You presumably wanted to assign that to the member variable history instead - since you haven't, if you get to the destructor it gives you an error saying that you're freeing history but have never allocated it.
There's a similar error in the copy constructor as well.
There are also other errors in your code as well, which I assume you'll find as you go - get_name(), for example, is not going to work. I suspect the header file is not helping here, but there's not much to be done if you're not supposed to change that.
I've written a little bit code for you and corrected the epic mistakes (even in the header file, sorry ;)). It is still extremely ugly and c-ish, but maybe you can learn something reading it:
#include <cstddef>
#include <ostream>
class account
{
// The whole class makes no sense, since it has no useful
// member function or anything like this.
// Furthermore, the class provides almost full access to all its member variables.
// At this point one could just make everything public.
// This is not even exception safe when the constructor throws.
// A good implementation would use history_entry and history classes,
// together with std::string and std::vector/std::deque
// And it would provide some sort of functionality. ;)
public:
account(const char* name, unsigned number, std::size_t history_max_size);
account(const account& other);
~account();
const char* name() const;
unsigned number() const;
double balance() const;
const char* const* history() const;
std::size_t history_size() const;
unsigned history_max_size() const;
void set_name(const char* new_name);
void set_number(unsigned new_number);
void set_balance(double new_balance);
void add_history(const char* new_history);
private:
char* name_;
unsigned number_;
double balance_;
char** history_;
std::size_t history_size_;
const std::size_t history_max_size_;
};
std::ostream& operator << (std::ostream& stream, const account& a);
#include <cassert>
#include <cstring>
account::account(const char* name, unsigned number, std::size_t history_max_size)
: name_(0)
, number_(number)
, balance_(0.0)
, history_(new char*[history_max_size])
, history_size_(0)
, history_max_size_(history_max_size)
{
assert(name != 0);
assert(history_max_size != 0);
set_name(name);
}
account::account(const account& other)
: name_(0)
, number_(other.number_)
, balance_(other.balance_)
, history_(new char*[other.history_max_size_])
, history_size_(other.history_size_)
, history_max_size_(other.history_max_size_)
{
set_name(other.name_);
for (std::size_t i = 0; i != other.history_size_; ++i)
{
history_[i] = new char[std::strlen(other.history_[i]) + 1];
strcpy(history_[i], other.history_[i]);
}
}
account::~account()
{
delete[] name_;
for (std::size_t i = 0; i != history_size_; ++i)
delete[] history_[i];
delete[] history_;
}
const char* account::name() const
{
return name_;
}
unsigned account::number() const
{
return number_;
}
double account::balance() const
{
return balance_;
}
const char* const* account::history() const
{
return history_;
}
std::size_t account::history_size() const
{
return history_size_;
}
unsigned account::history_max_size() const
{
return history_max_size_;
}
void account::set_name(const char* new_name)
{
if (name_)
delete[] name_;
name_ = new char[std::strlen(new_name) + 1];
std::strcpy(name_, new_name);
}
void account::set_number(unsigned new_number)
{
number_ = new_number;
}
void account::set_balance(double new_balance)
{
balance_ = new_balance;
}
void account::add_history(const char* new_history)
{
if (history_size_ == history_max_size_)
{
delete[] history_[0]; // delete oldest entry
for (std::size_t i = 0; i != history_size_ - 1; ++i)
history_[i] = history_[i + 1];
--history_size_;
}
history_[history_size_] = new char[strlen(new_history) + 1];
std::strcpy(history_[history_size_], new_history);
++history_size_;
}
std::ostream& operator << (std::ostream& stream, const account& a)
{
return stream << "account [name: " << a.name() << ", number: "
<< a.number() << ", balance: " << a.balance() << ']';
}
#include <iostream>
int main()
{
account a("Hello!", 500, 5);
a.set_balance(12.546);
for (int i = 50; i--; )
a.add_history("Yaaay..");
//account b = a;
std::cout << a << '\n';
}

overload operator+ / char* ch1 + char* ch2

I've created simple string class with some extra functions - its mainly for learning purposes.
Now i want to overload operator + to allow me add two or more char* to my string.
this is what i want to make:
tom::string TXT;
TXT="abcde" + "1234";
cout << TXT << endl;
and output have to be:
abcde1234
i want to add more than just const char* later like:
..
int NUM=34;
TXT="abcd"+NUM+"098";
cout << TXT << endl;
and output have to be:
abcd34098
ive already done similar thing with operator <<
TXT << "abcd" << ".......";
but i need it with + operator.
another thing is (probably it will be sorted with + operator)
void testF(tom::string INP) {
cout << INP << endl;
}
int NUM=123;
testF("abcd"+NUM+"efg");
with output:
abcd123efg
if i'm trying anything still ending with error:
error: invalid operands of types
‘const char [4]’ and ‘const char [3]’
to binary ‘operator+’
here is part of the tom::string class:
namespace tom {
class string {
private:
unsigned int _length;
unsigned int _search_pos;
bool _changed;
bool _indexed;
char* _buffer;
unsigned int* _indexes;
unsigned int _indexCount;
char* _emptyChar;
unsigned int _null;
char* _retBuffer[RET_BUFFERS];
short unsigned int _retBufferIndex;
// ADD to string
void _add (const char* txt) {
_buffer=(char*) realloc(_buffer, sizeof(char)*(_length+strlen(txt)+1));
memcpy(&_buffer[_length], txt, strlen(txt));
_length=_length+strlen(txt);
_buffer[_length]=static_cast<char>(0);
_changed=true;
free(_indexes);
_changed=true;
_indexCount=0;
_indexed=false;
_indexes = (unsigned int*) malloc (sizeof(unsigned int)*2);
}
// .......
// REPLACE Whole string
string& _rvs(const char* txt) {
free(_buffer);
free(_indexes);
_changed=true;
_indexCount=0;
_indexed=false;
_indexes = (unsigned int*) malloc (sizeof(unsigned int)*2);
_length=strlen(txt);
_buffer = (char*) malloc (sizeof(char)*(_length+1));
memcpy(_buffer, txt, _length);
_buffer[_length]=static_cast<char>(0);
return (*this);
}
// .......
public:
// ----------------------------------------------
// | CONSTRUCTOR |
// ----------------------------------------------
string(const char* _init="") {
_length=0;
_indexCount=0;
_changed=false;
_indexed=false;
_buffer = (char*) malloc (sizeof(char)*(strlen(_init)+1));
memcpy(_buffer, _init, strlen(_init));
_indexes = (unsigned int*) malloc (sizeof(unsigned int)*2);
_emptyChar = (char*) malloc (sizeof(char));
_buffer[strlen(_init)]=static_cast<char>(0);
_emptyChar[0]=static_cast<char>(0);
_null=(unsigned int)-1;
_retBufferIndex=0;
for (short unsigned int ii=0; ii<RET_BUFFERS; ii++) {
_retBuffer[ii] = (char*) malloc (sizeof(char));
_retBuffer[ii][0]=static_cast<char>(0);
}
}
string(const tom::string& _init) {
string((const char*)_init.c_str());
}
// ----------------------------------------------
// | DESTRUCTOR |
// ----------------------------------------------
~string() {
free(_buffer);
free(_indexes);
free(_emptyChar);
for (short unsigned int ii=0; ii<RET_BUFFERS; ii++) {
free(_retBuffer[ii]);
}
}
// .....
string& operator = (string &ttxt) {
const char* txt=ttxt.c_str();
return (_rvs(txt));
}
string& operator = (const char* txt) {
return (_rvs(txt));
}
string& operator = (int num) {
char bf[32];
sprintf (bf, "%d", num);
const char* txt=bf;
return (_rvs(txt));
}
string& operator << (const char* txt) {
_add(txt);
return(*this);
}
string& operator << (int num) {
char bf[32];
sprintf (bf, "%d", num);
const char* txt=bf;
_add(txt);
return(*this);
}
operator const char*() {
return (const char*)_buffer;
}
// .....
}
}
You can't overload operators for pointer types only. At least one of the involved types needs to be a user-defined type.
tom::string TXT;
TXT="abcde" + "1234";
cout << TXT << endl;
"abcde" + "1234" is evaluated first - you cannot make it work like you want.
You can make e.g. this work though:
tom::string TXT;
TXT=tom::string("abcde") + 987 + "1234";
cout << TXT << endl;
That will require an operator+(int) and an operator+(char const *)
EDIT: Sample operator:
operator+ should return a new object - not modify the object it is called on.
class string {
...
friend string operator+(string const & LHS, char const * RHS) {
string s = LHS;
s._add(RHS);
return s;
}
};
Thanx to Erik! ... sorted (working)
i've added to tom::string class:
friend string operator+(string const & LHS, char const * RHS) {
string s;
s=LHS;
s._add(RHS);
return s;
}
next one throwing malloc error - i have to check it, but the first working perfect!
friend string operator+(string const & LHS, char const * RHS) {
string s=LHS;
s._add(RHS);
return s;
}
and the testing:
void test2 (tom::string ooo) {
cout << ooo << endl;
}
test2(tom::string("abcde")+"AA"+"BB");
showing:
abcdeAABB
Thanx again!

defining output operator << in C++ for user defined type

struct myVals {
int val1;
int val2;
};
I have static functions
static myVals GetMyVals(void)
{
// Do some calcaulation.
myVals val;
val.val1 = < calculatoin done in previous value is assigned here>;
val.val2 = < calculatoin done in previous value is assigned here>;
return val;
}
bool static GetStringFromMyVals( const myVals& val, char* pBuffer, int sizeOfBuffer, int count)
{
// Do some calcuation.
char cVal[25];
// use some calucations and logic to convert val to string and store to cVal;
strncpy(pBuffer, cVal, count);
return true;
}
My requirement here is that i should have above two functions to be called in order and print the string of "myvals" using C++ output operator (<<).
How can we achieve this? Does i require new class to wrap this up. Any inputs are help ful. Thanks
pseudocode:
operator << () { // operator << is not declared completely
char abc[30];
myvals var1 = GetMyVald();
GetStringFromMyVals(var1, abc, 30, 30);
// print the string here.
}
The signature for this operator is as follows:
std::ostream & operator<<(std::ostream & stream, const myVals & item);
An implementation could look like this:
std::ostream & operator<<(std::ostream & stream, const myVals & item) {
stream << item.val1 << " - " << item.val2;
return stream;
}