How to pass a pointer to vector of pointers? - c++

This is a C++ version of a duplicate question. I know the pointers to vectors a bit much in the following, but I did this in order to duplicate a much larger project. The members of info_a are not properly printing from within print_b and I have been unable to properly pass the vector of pointers.
With what I have tried, the members of info_a are not properly printing from within print_b. The first element is fine, but the next two are not.
The structs and print_b are from a third-party api and I am trying to pass in what they are expecting.
Here's the working code ...
http://coliru.stacked-crooked.com/a/c3ad6af6da9409a5
Does anyone see where I am going wrong?
typedef struct {
uint16_t a1;
uint8_t a2;
uint8_t a3;
} info_a;
typedef struct {
uint16_t id;
unsigned int arr_sz;
info_a *arr;
} info_b;
void print_a(const info_a* a)
{
using namespace std;
cout <<
"a->a1 0x" << hex << setfill('0') << setw(4) << a->a1 << std::endl <<
"a->a2 0x" << hex << setfill('0') << setw(2) << a->a2 << std::endl <<
"a->a3 0x" << hex << setfill('0') << setw(2) << a->a3 << std::endl;
}
void print_b(const info_b* b)
{
using namespace std;
cout << "b->id 0x" << hex << setfill('0') << setw(4) << b->id << endl
<< "b->arr_sz " << hex << setfill('0') << setw(2) << b->arr_sz << endl;
for (unsigned int i = 0; i < b->arr_sz; ++i) {
const info_a *elem = &(b->arr[i]);
print_a(elem);
}
}
int main(int argc, char **argv)
{
std::shared_ptr<std::vector<std::shared_ptr<info_a>>> sp_info_a =
std::make_shared<std::vector<std::shared_ptr<info_a>>>();
std::shared_ptr<std::vector<std::shared_ptr<info_b>>> sp_info_b =
std::make_shared<std::vector<std::shared_ptr<info_b>>>();
int offset = 0;
for (uint16_t i = 1; i <= 1; ++i) {
for (uint16_t j = 1; j <= 3; ++j) {
std::shared_ptr<info_a> a_info =
std::make_shared<info_a>(info_a { j, 0x31, 0x32 } );
sp_info_a->push_back(a_info);
}
std::shared_ptr<info_b> b_info = std::make_shared<info_b>(
info_b {
static_cast<uint16_t>(i),
static_cast<unsigned int>(sp_info_a->size()),
(*sp_info_a)[offset].get()
});
sp_info_b->push_back(b_info);
print_b(b_info.get());
}
return 0;
}

It doesn't work because you interpret an array of std::shared_ptr<info_a> as an array of info_a. This will work:
int main(int argc, char **argv)
{
std::shared_ptr<std::vector<info_a>> sp_info_a =
std::make_shared<std::vector<info_a>>();
std::shared_ptr<std::vector<std::shared_ptr<info_b>>> sp_info_b =
std::make_shared<std::vector<std::shared_ptr<info_b>>>();
int offset = 0;
for (uint16_t i = 1; i <= 1; ++i) {
for (uint16_t j = 1; j <= 3; ++j) {
sp_info_a->push_back(info_a { j, 0x31, 0x32 });
}
std::shared_ptr<info_b> b_info = std::make_shared<info_b>(
info_b {
static_cast<uint16_t>(i),
static_cast<unsigned int>(sp_info_a->size()),
sp_info_a->data() + offset
});
sp_info_b->push_back(b_info);
print_b(b_info.get());
}
return 0;
}

I have been unable to properly pass the vector of pointers
This is the core of the problem. The C API you're calling does not expect a vector of pointers, it expects a vector of structs.
In particular, this bit ...
unsigned int arr_sz;
info_a *arr;
... expects to find arr_sz structs in memory, one after the other, starting from arr.
Your code allocates all structs separately, then stores the address of the first one in arr. The printing code then walks off the end of arr[0], expecting to find the next struct, but as you've allocated them separately, they're stored who knows where in memory.
In order to fix this, whatever you do, you must create the equivalent of a std::vector<info_a> (which you can then wrap an info_b around, as a sort of array view). This is what gives you the guarantee that the structs are actually adjacent in memory.

Related

How do I convert long doubles to char arrays?

I am running a C++ program to sort strings as numbers.
I am saving strings in a char array vector but want to sort numbers as numbers so I am converting number strings into long doubles by calling "tonum()" then converting them back to strings when I am done by calling "tostring()". I am calling "numstr()" strictly for readability and debugging. I convert numbers 0 through 7 and the 6th number across for each value changes every time I run it. In my actual program, the first 5 numbers also seem to change. How do I get consistent results for a long double so that I can properly sort long doubles in char arrays?
#include<iostream>
std::string::size_type sz;
//___________________________________________________
std::string tonum(std::string str)
{
const int len = sizeof(long double);
std::string out = "0000000000000000";
union
{
long double dbl;
char array[len];
};
try
{
dbl = stold(str);
}
catch(std::exception &err)
{
dbl = 0;
}
for (int i = 0; i < len; i++)
{
std::cout << (int)array[i] << "\n";
out[len-i-1] = array[i];
}
return(out);
}
//___________________________________________________
std::string fromnum(std::string str)
{
const int len = sizeof(long double);
std::string out = "";
union
{
long double dbl;
char array[len];
};
for (int i = 0; i < len; i++)
{
array[len-i-1] = str[i];
}
out = std::to_string(dbl);
return(out);
}
//_____________________________________________________
std::string numstr(std::string str)
{
std::string out = fromnum(str) + ":";
for (int i = 0; i < str.length(); i++)
{
std::string look = std::to_string(str[i]);
int lookint = stold(look,&sz);
if (lookint < 0) lookint += 256;
std::string look2 = std::to_string(lookint);
out += look2 + " ";
}
return(out);
}
//_____________________________________________________
int main()
{
std::cout << numstr(tonum("0")) << "\n";
std::cout << numstr(tonum("1")) << "\n";
std::cout << numstr(tonum("2")) << "\n";
std::cout << numstr(tonum("3")) << "\n";
std::cout << numstr(tonum("4")) << "\n";
std::cout << numstr(tonum("5")) << "\n";
std::cout << numstr(tonum("6")) << "\n";
std::cout << numstr(tonum("7")) << "\n";
}
//_____________________________________________________

Why is this plain array implementation slower than the std::vector implementation performance?

Why is this plain array implementation slower than the std::vector implementation performance?
Due to some weired results I was seeing on something I'm working on, I decided to write a simplified test to compare std::vector vs plain array efficiency.
I have a struct which I implement in both ways,
1 using plain arrays (of different sizes)
typedef struct {
uint16_t index;
uint16_t nvals;
uint16_t vals[50];
double mean;
} a_segment_t;
2 using STL
typedef struct {
uint16_t index;
uint16_t nvals;
vector<uint16_t> vals;
uint32_t mean;
} b_segment_t;
The creation of this object in memory is not what I'm interested in (so I dont mind the push_back()), once this object is in memory it is used for an operation and that efficiency is what I'm analyzing. The vals are filled with some random data.
The operation goes through the vals stored in each segment, in this case a simple mean calculation. The test is as follows:
using namespace std;
#include <stdint.h>
#include <stdlib.h> // srand, rand
#include <time.h>
#include <iostream>
#include <iomanip>
#include <vector>
#include <array>
#define NSEGMENTS 100
#define MAX_NPXS 50
#define N 10000
// plain array approach
typedef struct {
uint16_t index;
uint16_t nvals;
uint16_t vals[MAX_NPXS];
double mean;
} a_segment_t;
uint16_t operation(uint16_t, a_segment_t*);
uint16_t print(uint16_t nsegments, a_segment_t* p_segments);
// stl vector approach
typedef struct {
uint16_t index;
uint16_t nvals;
vector<uint16_t> vals;
uint32_t mean;
} b_segment_t;
uint16_t operation(uint16_t, vector<b_segment_t>*);
uint16_t print(uint16_t nsegments, vector<b_segment_t>*);
void delta_time(struct timespec*, struct timespec*, struct timespec*);
uint16_t operation(uint16_t nsegments, a_segment_t* p_segments) {
// the operation (plain array approach)
uint64_t sum;
for( uint16_t nsegment = 0; nsegment < nsegments; ++nsegment ) {
sum = 0;
for(uint16_t nval = 0; nval < p_segments[nsegment].nvals; ++nval){
sum = sum + p_segments[nsegment].vals[nval];
}
p_segments[nsegment].mean = sum/p_segments[nsegment].nvals;
}
return nsegments;
}
uint16_t print(uint16_t nsegments, a_segment_t* p_segments) {
// print data (plain array approach)
for( uint16_t nsegment = 0; nsegment < nsegments; ++nsegment ) {
cout << "index : " << setfill('0') << setw(3) << p_segments[nsegment].index;
cout << "\tnval : " << setfill('0') << setw(3) << p_segments[nsegment].nvals;
cout << "\tvals : [";
for(uint16_t nval = 0; nval < p_segments[nsegment].nvals; ++nval){
cout << p_segments[nsegment].vals[nval] << ",";
}
cout << "\b]" << endl;
}
return nsegments;
}
uint16_t operation(uint16_t nsegments, vector<b_segment_t>* p_segments) {
// the operation (stl vector approach)
uint32_t sum;
for (vector<b_segment_t>::iterator p_segment = p_segments->begin(); p_segment<p_segments->end(); ++p_segment) {
sum = 0;
for (vector<uint16_t>::iterator p_val = (p_segment->vals).begin(); p_val<(p_segment->vals).end(); ++p_val) {
sum = sum + (*p_val);
}
p_segment->mean = sum/(p_segment->nvals);
}
return nsegments;
}
uint16_t print(uint16_t nsegments, vector<b_segment_t>* p_segments) {
// print data (stl vector approach)
for (vector<b_segment_t>::iterator p_segment = p_segments->begin(); p_segment<p_segments->end(); ++p_segment) {
cout << "index : " << setfill('0') << setw(3) << p_segment->index;
cout << "\tnval : " << setfill('0') << setw(3) << p_segment->nvals;
cout << "\tvals : [";
for (vector<uint16_t>::iterator p_val = (p_segment->vals).begin(); p_val<(p_segment->vals).end(); ++p_val) {
cout << *p_val << ",";
}
cout << "\b]" << endl;
}
return nsegments;
}
void delta_time(struct timespec* t1, struct timespec* t2, struct timespec* dt) {
if ((t2->tv_nsec - t1->tv_nsec) < 0) {
dt->tv_sec = t2->tv_sec - t1->tv_sec - 1;
dt->tv_nsec = t2->tv_nsec - t1->tv_nsec + 1000000000;
} else {
dt->tv_sec = t2->tv_sec - t1->tv_sec;
dt->tv_nsec = t2->tv_nsec - t1->tv_nsec;
}
return;
}
int main(int argc, char const *argv[]) {
uint16_t nsegments = NSEGMENTS;
uint16_t nsegment = 0;
uint16_t i = 0;
//create an populate the segments with dummy data (plain array approach)
a_segment_t* a_segments = new a_segment_t[nsegments];
for( nsegment = 0; nsegment < nsegments; ++nsegment ) {
a_segments[nsegment].index = nsegment;
srand(nsegment);
a_segments[nsegment].nvals = rand() % MAX_NPXS + 1;
for(uint16_t nval = 0; nval < a_segments[nsegment].nvals; ++nval){
a_segments[nsegment].vals[nval] = nval;
}
}
//create an populate the segments with dummy data (stl vector approach)
nsegment = 0;
vector<b_segment_t> b_segments(nsegments);
for (vector<b_segment_t>::iterator p_segment = b_segments.begin(); p_segment<b_segments.end(); ++p_segment) {
p_segment->index = nsegment;
srand(nsegment);
p_segment->nvals = rand() % MAX_NPXS + 1;
for(uint16_t nval = 0; nval < p_segment->nvals; ++nval){
p_segment->vals.push_back(nval);
}
nsegment++;
}
// print(nsegments, a_segments);
// cout << "===================================" << endl;
// print(nsegments, &b_segments);
// cout << "===================================" << endl;
// ======================= plain array timing measure ========================
struct timespec a_times[N];
for(i = 0; i < N; i++) {
nsegments = operation(nsegments, a_segments);
clock_gettime(CLOCK_REALTIME, &(a_times[i]));
}
// ===========================================================================
// ========================= vector timing measure ===========================
struct timespec b_times[N];
for(i = 0; i < N; i++) {
nsegments = operation(nsegments, &b_segments);
clock_gettime(CLOCK_REALTIME, &(b_times[i]));
}
// ===========================================================================
// =========================== timing console log ============================
struct timespec a_deltatime[N], a_elapsedtime[N], b_deltatime[N], b_elapsedtime[N];
cout << "\t\t plain array\t\t stl vector" << endl;
cout << "frame #\telapsedtime\tdeltatime\telapsedtime\tdeltatime" << endl;
for(i = 0; i < N-1; i=i+1000) {
delta_time(&(a_times[0]), &(a_times[i]), &(a_elapsedtime[i]));
delta_time(&(a_times[i]), &(a_times[i+1]), &(a_deltatime[i]));
delta_time(&(b_times[0]), &(b_times[i]), &(b_elapsedtime[i]));
delta_time(&(b_times[i]), &(b_times[i+1]), &(b_deltatime[i]));
cout << i << ",\t"
<< a_elapsedtime[i].tv_sec << "." << setfill('0') << setw(9) << a_elapsedtime[i].tv_nsec << ",\t"
<< a_deltatime[i].tv_sec << "." << setfill('0') << setw(9) << a_deltatime[i].tv_nsec << ",\t"
<< b_elapsedtime[i].tv_sec << "." << setfill('0') << setw(9) << b_elapsedtime[i].tv_nsec << ",\t"
<< b_deltatime[i].tv_sec << "." << setfill('0') << setw(9) << b_deltatime[i].tv_nsec << endl;
}
// ===========================================================================
}
An online version. Note: All of the tests were compiled with -O3
Can someone please point out why the plain array implementation is slower than the std::vector implementation?
Shouldn't the plain array implementation be faster?
What can I do to improve the speed of the plain array implementation?
The compiler will do a much better job of optimising code if you express algorithms in terms of iterators. One of the reasons is that it can make assumptions about the size and overflow characteristics of array indexes (which translate to indexed addressing with offset in machine code).
Refactoring to express both operation() and print() in terms of iterators (which can be pointers):
#include <stdint.h>
#include <stdlib.h> // srand, rand
#include <time.h>
#include <iostream>
#include <iomanip>
#include <vector>
#include <array>
#include <numeric>
using namespace std;
#define NSEGMENTS 100
#define MAX_NPXS 50
#define N 10000
// plain array approach
typedef struct {
uint16_t index;
uint16_t nvals;
uint16_t vals[MAX_NPXS];
double mean;
} a_segment_t;
// stl vector approach
typedef struct {
uint16_t index;
uint16_t nvals;
vector<uint16_t> vals;
uint32_t mean;
} b_segment_t;
void delta_time(struct timespec*, struct timespec*, struct timespec*);
template<class Iter>
uint16_t operation(Iter first, Iter last) {
auto result = std::uint16_t(std::distance(first, last));
// the operation (plain array approach)
for( ; first != last ; ++first ) {
auto sum = std::accumulate(std::begin(first->vals), std::begin(first->vals) + first->nvals, uint64_t(0), std::plus<>());
first->mean = sum / first->nvals;
}
return result;
}
template<class Iter>
uint16_t print(Iter first, Iter last) {
auto result = std::uint16_t(std::distance(first, last));
// print data (plain array approach)
for( ; first != last ; ++first ) {
cout << "index : " << setfill('0') << setw(3) << first->index;
cout << "\tnval : " << setfill('0') << setw(3) << first->nvals;
cout << "\tvals : [";
for_each(std::begin(first->vals), std::begin(first->vals) + first->nvals, [](const auto& val)
{
cout << val << ",";
});
cout << "\b]" << endl;
}
return result;
}
void delta_time(struct timespec* t1, struct timespec* t2, struct timespec* dt) {
if ((t2->tv_nsec - t1->tv_nsec) < 0) {
dt->tv_sec = t2->tv_sec - t1->tv_sec - 1;
dt->tv_nsec = t2->tv_nsec - t1->tv_nsec + 1000000000;
} else {
dt->tv_sec = t2->tv_sec - t1->tv_sec;
dt->tv_nsec = t2->tv_nsec - t1->tv_nsec;
}
return;
}
int main(int argc, char const *argv[]) {
uint16_t nsegments = NSEGMENTS;
uint16_t nsegment = 0;
uint16_t i = 0;
//create an populate the segments with dummy data (plain array approach)
a_segment_t* a_segments = new a_segment_t[nsegments];
for( nsegment = 0; nsegment < nsegments; ++nsegment ) {
a_segments[nsegment].index = nsegment;
srand(nsegment);
a_segments[nsegment].nvals = rand() % MAX_NPXS + 1;
for(uint16_t nval = 0; nval < a_segments[nsegment].nvals; ++nval){
a_segments[nsegment].vals[nval] = nval;
}
}
//create an populate the segments with dummy data (stl vector approach)
nsegment = 0;
vector<b_segment_t> b_segments(nsegments);
for (vector<b_segment_t>::iterator p_segment = b_segments.begin(); p_segment<b_segments.end(); ++p_segment) {
p_segment->index = nsegment;
srand(nsegment);
p_segment->nvals = rand() % MAX_NPXS + 1;
for(uint16_t nval = 0; nval < p_segment->nvals; ++nval){
p_segment->vals.push_back(nval);
}
nsegment++;
}
// print(a_segments, a_segments + nsegments);
// cout << "===================================" << endl;
// print(b_segments.begin(), b_segments.end());
// cout << "===================================" << endl;
// ======================= plain array timing measure ========================
struct timespec a_times[N];
for(i = 0; i < N; i++) {
nsegments = operation(a_segments, a_segments + nsegments);
clock_gettime(CLOCK_REALTIME, &(a_times[i]));
}
// ===========================================================================
// ========================= vector timing measure ===========================
struct timespec b_times[N];
for(i = 0; i < N; i++) {
nsegments = operation(b_segments.begin(), b_segments.begin() + nsegments);
clock_gettime(CLOCK_REALTIME, &(b_times[i]));
}
// ===========================================================================
// =========================== timing console log ============================
struct timespec a_deltatime[N], a_elapsedtime[N], b_deltatime[N], b_elapsedtime[N];
cout << "\t\t plain array\t\t stl vector" << endl;
cout << "frame #\telapsedtime\tdeltatime\telapsedtime\tdeltatime" << endl;
for(i = 0; i < N-1; i=i+1000) {
delta_time(&(a_times[0]), &(a_times[i]), &(a_elapsedtime[i]));
delta_time(&(a_times[i]), &(a_times[i+1]), &(a_deltatime[i]));
delta_time(&(b_times[0]), &(b_times[i]), &(b_elapsedtime[i]));
delta_time(&(b_times[i]), &(b_times[i+1]), &(b_deltatime[i]));
cout << i << ",\t"
<< a_elapsedtime[i].tv_sec << "." << setfill('0') << setw(9) << a_elapsedtime[i].tv_nsec << ",\t"
<< a_deltatime[i].tv_sec << "." << setfill('0') << setw(9) << a_deltatime[i].tv_nsec << ",\t"
<< b_elapsedtime[i].tv_sec << "." << setfill('0') << setw(9) << b_elapsedtime[i].tv_nsec << ",\t"
<< b_deltatime[i].tv_sec << "." << setfill('0') << setw(9) << b_deltatime[i].tv_nsec << endl;
}
// ===========================================================================
}
Yields expected results:
plain array stl vector
frame # elapsedtime deltatime elapsedtime deltatime
0, 0.000000000, 0.000002000, 0.000000000, 0.000002000
1000, 0.001533000, 0.000001000, 0.001551000, 0.000002000
2000, 0.003061000, 0.000002000, 0.003096000, 0.000002000
3000, 0.004589000, 0.000001000, 0.004771000, 0.000002000
4000, 0.006255000, 0.000001000, 0.006433000, 0.000002000
5000, 0.007785000, 0.000002000, 0.007975000, 0.000001000
6000, 0.009326000, 0.000002000, 0.009494000, 0.000001000
7000, 0.010893000, 0.000002000, 0.011012000, 0.000001000
8000, 0.012435000, 0.000002000, 0.012650000, 0.000002000
9000, 0.014024000, 0.000002000, 0.014273000, 0.000001000
The two versions aren't actually equivalent.
Firstly, your "array version" has mean as a double, and the "STL version" has mean as uint32_t. For the two functions to be remotely equivalent, the calculation of mean needs to be the same.
Second, your "array version" uses array subscripting, whereas the STL version increments and dereferences iterators. Since the compiler/optimiser will need to allow for more concerns (such as pointer aliasing) in the array version, it is probably unable to optimise performance as much.
Try turning your array version into something like;
uint16_t operation(uint16_t nsegments, a_segment_t* p_segments)
{
uint64_t sum;
for(a_segment *pseg = p_segments, *eseg = p_segments + nsegments; pseg < eseg; ++pseg)
{
sum = 0;
for(uint16_t *val = pseg->vals, *eval = pseg->vals + pseg->nvals; val < eval; ++val)
{
sum = sum + (*val);
}
p_seg->mean = sum/(pseg->nvals);
}
return nsegments;
}
This will (barring mistakes I've made in translating to this form - I haven' tested) give the same result, but will at least give the compiler a fighting chance of being able to apply the same type of performance optimisations to your "array version" as to the "STL version".
This sort of thing is one reason (of several) that the C++ standard algorithms work with iterators, rather than array indexing on containers like vector. The compiler has a better chance of optimising performance. Note that a pointer is a type of iterator.

Set array dimension at runtime

I have a struct, which, depending on user inputs at runtime, will either require a 1D array or a 3D array. It will never need both. Right now, I have it set up like in the sample code below, with separate variables that can point to either a 1D array, or a 3D array. I would like to have just one variable in the struct that can point to either a 1D array or a 3D array, where the dimension is set at runtime. I have intermediate knowledge of C, and am a beginner with C++. I'd be willing to accept an answer based on C++ concepts but only if there is no slowdown (or negligible slowdown) compared to using C when iterating over the values. If it's a 3D array, then the for loops that access and change the array's values are the biggest bottleneck in my code. Once the array is set up, I won't need to change the dimension or size of the array.
Is there a way to do this, or should I just settle for always having an extraneous variable in my struct?
#include <iostream>
using namespace std;
typedef struct {
int dim;
int *one_d_arr;
int ***three_d_arr;
} Struct;
int main() {
int count = 0;
int *arr1 = (int*) malloc(2 * sizeof(int));
arr1[0] = 0;
arr1[1] = 1;
int ***arr3 = (int***) malloc(2 * sizeof(int**));
for (int i=0; i<2; i++) {
arr3[i] = (int**) malloc(2 * sizeof(int*));
for (int j=0; j<2; j++) {
arr3[i][j] = (int*) malloc(2 * sizeof(int));
for (int k=0; k<2; k++) {
arr3[i][j][k] = count++;
}
}
}
Struct s;
s.one_d_arr = NULL;
s.three_d_arr = NULL;
cout << "Enter number of dimensions: ";
cin >> s.dim;
if (s.dim==1) {
s.one_d_arr = arr1;
cout << s.one_d_arr[0] << ", " << s.one_d_arr[1] << endl;
}
else if (s.dim==3) {
s.three_d_arr = arr3;
cout << s.three_d_arr[0][0][0] << ", " << s.three_d_arr[0][0][1] << endl;
cout << s.three_d_arr[0][1][0] << ", " << s.three_d_arr[0][1][1] << endl;
cout << s.three_d_arr[1][0][0] << ", " << s.three_d_arr[1][0][1] << endl;
cout << s.three_d_arr[1][1][0] << ", " << s.three_d_arr[1][1][1] << endl;
}
else {
cout << "Must enter 1 or 3" << endl;
}
}
My recommendation is to use two different types here, instead of a single struct. Using an abstract base class, you can make both subclasses conform to a single interface, but they would have different underlying behavior. A very basic example:
class ArrayBase {
int dim;
public:
// This function is pure virtual, which means it's impossible to
// instantiate an instance of ArrayBase. Any class that inherits from
// ArrayBase must implement printArray().
virtual void printArray() = 0;
}
class Array1D : public ArrayBase {
int* array;
void printArray() {
// some code to print this one-dimensional array
}
}
class Array3D : public ArrayBase {
int*** array;
void printArray() {
// some code to print this three-dimensional array
}
}
Later, when you need to use the array, you can dynamically allocate the type you need, like this:
ArrayBase* inputArray;
// if the user wants a 1D array
inputArray = new Array1D();
// if the user wants a 3D array
inputArray = new Array3D();
// this will call the appropriate function to print the array
inputArray->printArray();
If you really want to have a single type, using boost::any is one way to condense your two array pointers into one. I would not recommend this approach, but it would work.
One of the juicy things about the C/C++ pointers is the existence of void pointers. A void pointer can point to anything you want, from int to int ***.
So you can simply use the following code:
#define CAST1(arr) ((int *)arr)
#define CAST3(arr) ((int ***)arr)
#define CAST(arr,i) CAST##i(arr)
typedef struct {
int dim;
void *arr;
} Struct;
int main()
{
Struct s;
cin >> s.dim;
int count = 0;
if (s.dim == 1){
s.arr = malloc(2 * sizeof(int));
CAST(s.arr, 1)[0] = 0;
CAST(s.arr, 1)[1] = 1;
}
else if (s.dim == 3){
s.arr = malloc(2 * sizeof(int ***));
for (int i = 0; i < 2; i++){
CAST(s.arr, 3)[i] = (int **) malloc(2 * sizeof(int **));
for (int j = 0; j < 2; j++){
CAST(s.arr, 3)[i][j] = (int *)malloc(2 * sizeof(int *));
for (int k = 0; k < 2; k++){
CAST(s.arr, 3)[i][j][k] = count++;
}
}
}
}
if (s.dim == 1) {
cout << CAST(s.arr, 1)[0] << ", " << CAST(s.arr, 1)[1] << endl;
}
else if (s.dim == 3) {
cout << CAST(s.arr, 3)[0][0][0] << ", " << CAST(s.arr, 3)[0][0][1] << endl;
cout << CAST(s.arr, 3)[0][1][0] << ", " << CAST(s.arr, 3)[0][1][1] << endl;
cout << CAST(s.arr, 3)[1][0][0] << ", " << CAST(s.arr, 3)[1][0][1] << endl;
cout << CAST(s.arr, 3)[1][1][0] << ", " << CAST(s.arr, 3)[1][1][1] << endl;
}
else {
cout << "Must enter 1 or 3" << endl;
}
system("pause");
return 0;
}

Writing value to c style string in struct

For the life of me I can't figure out why the I can't write to a c style string inside of a struct.
College student - can't use string class, haven't learned pointers.
Help? 2 hours at trying to figure this out.
#include <iostream>
using namespace std;
void strCopy(char from[], char to[])
{
for (int i = 0; i < 255; i++)
{
to[i] = from[i];
}
}
struct card
{
char suit[20];
char rank[20];
int cvalue;
char location[20];
};
void printCard(card card)
{
cout << card.rank << " of " << card.suit << endl;
}
int main()
{
// I don't think strCopy()'s the problem, I've used it with my last project.
cout << "Test strCopy()" << endl;
char str1[14] = "abcdefghijklm";
char str2[14];
strCopy(str1, str2);
cout << " " << str2 << endl << endl;
// Now the negative.
card one;
one.cvalue = 2;
strCopy("Somewhere", one.location);
strCopy("Two", one.rank);
strCopy("Hearts", one.suit);
printCard(one);
}
// I don't think strCopy()'s the problem, I've used it with my last
project.
Wrong
for (int i = 0; i < 255; i++)
{
to[i] = from[i];
}
copies 255 characters, however that's not what you meant.
If here :
strCopy(str1, str2);
cout << " " << str2 << endl << endl;
Your're getting "correct" output, then you're just unlucky, since that invokes an undefined behavior, an you're writing off the end of the array.

How can I view a short's bit representation?

If I have this as pointer to memory as a pointer to shorts:
unsigned short* ms = reinterpret_cast<unsigned short*>(_memory);
and I know the size of ms (number of this shorts), I would like to see running through all these shorts and their binary representation.
How can I access the bits of each short in C++?
To see the binary representation of any variable of type T, you can do something like this:
template <typename T>
void print_raw(const T & x)
{
const unsigned char * const p = reinterpret_cast<const unsigned char *>(&x);
for (std::size_t i = 0; i != sizeof(T); ++i)
{
if (i != 0) std::putchar(' ');
std::printf("%02X", p[i]);
}
}
You can plug this into your list of shorts.
(You could even replace printf by two lookups of index p[i] / 16 and p[i] % 16 in a suitable alphabet:
static const char alphabet = "01234567890ABCDEF";
std::putchar(alphabet[p[i] / 16]);
std::putchar(alphabet[p[i] % 16]);
Or replace it by a genuine binary printer:
void print_byte(unsigned char b)
{
for (std::size_t i = CHAR_BIT; i != 0; --i)
{
std::putchar(b & (1u << (i-1)) ? '1' : '0');
}
}
You can chain that into the previous loop instead of the two printf calls.)
cout << "\t" << dec << x << "\t\t Decimal" << endl;
cout << "\t" << oct << x << "\t\t Octal" << endl;
cout << "\t" << hex << x << "\t\t Hex" << endl;
cout << "\t" << bitset<MAX_BITS>(x) << endl;
try through bitset
EDIT(added code)
#include <iostream>
#include <bitset>
using namespace std;
int main( int argc, char* argv[] )
{
unsigned short _memory[] = {0x1000,0x0010,0x0001};
unsigned short* ms = reinterpret_cast<unsigned short*>(_memory);
for(unsigned short* iter = ms; iter != ms + 3/*number_of_shorts*/; ++iter )
{
bitset<16> bits(*iter);
cout << bits << endl;
for(size_t i = 0; i<16; i++)
{
cout << "Bit[" << i << "]=" << bits[i] << endl;
}
cout << endl;
}
}
or
#include <iostream>
#include <algorithm>
#include <bitset>
#include <iterator>
int main( int argc, char* argv[] )
{
unsigned short _memory[] = {0x1000,0x0010,0x0001};
unsigned short* ms = reinterpret_cast<unsigned short*>(_memory);
unsigned int num_of_ushorts = 3;//
std::copy(ms, ms+num_of_ushorts, ostream_iterator<bitset<16>>(cout, " "));
}
for (size_t i=0; i<N_SHORTS_IN_BUFFER; i++)
// perform bitwise ops
where N_SHORTS_IN_BUFFER is the number of shorts in memory.
The number of bits in a short is CHAR_BIT * sizeof(short).
If you are working under the assumption that an unsigned short has 16 bits, then you can retrieve each of them with bitwise operations:
for( unsigned short* iter = ms; iter != ms + num_of_ushorts; ++iter )
{
int bitN = ( *iter ) & ( 1 << N ); // get the N bit
}
As _memory points to a list of shorts your ms pointer can be used as an array.
unsigned short* ms = reinterpret_cast<unsigned short*>(_memory);
for (int i = 0; i < NUM_SHORTS_IN_MEM; i++)
cout << i << "th element\t" << ms[i] << endl;