VC++: Pass multiple arrays between functions - c++

I'm quite new to VC++, and I need to pass 4 arrays between functions, so I'm using another array to store their pointers. Have I done it correctly?
unsigned int* step1(...) {
...
// save data arrays
unsigned int* savedData = new unsigned int[4];
savedData[0] = *data0;
savedData[1] = *data1;
savedData[2] = *data2;
savedData[3] = *data3;
return savedData;
}
unsigned char* step2(unsigned int* savedData, ...) {
// read data arrays
unsigned int* data0 = &savedData[0];
unsigned int* data1 = &savedData[1];
unsigned int* data2 = &savedData[2];
unsigned int* data3 = &savedData[3];
...
}

In order to complete the previous valid answers, I will try to expand the answer:
Have I done it correctly?
Well, in order to pass data between functions: yes, doing it with pointers is an option. But it is commonly discouraged by the community because it makes troublesome the memory management.
When you work with pointers pointing dynamic memory, you must have a clear image of WHERE the memory is created and WHERE the memory will be deleted, in other words: the cycle of life of the memory must be clear and straightforward and for this reason, pass pointers between functions is commonly discouraged.
For example, in your case: the unsigned int* step1(...) function returns a pointer but looking at it, a new programmer or someone that works with you wouldn't tell if the pointer returned is dynamic memory and if calling step1 must delete or delete [] the memory after the call, same goes for unsigned char* step2(unsigned int* savedData, ...) and would be more confusing and troublesome because someone would ask: step2 would alter the savedData passed?
In order to fix the step2 issue, you can change the function to:
unsigned char* step2(const unsigned int* const savedData, ...)
By adding the const you're telling: "Hey! step2 isn't going to alter the contents of savedData nor changing the address it is pointing to".
But all the previous text is useless because doesn't fix the most important problem: Where the memory is freed?
In the step1 you're creating memory dynamically, in the step2 this memory is readed but... the delete is hidden somewhere in the code that you don't paste? or there is a step3 waiting for take care of the memory?
To avoid all this memory headaches, is commonly advised the use of STL containers, like std::vector, the container will take care of the memory management for you, in your case:
typedef std::vector<int> intvector;
typedef std::vector<intvector> intintvector;
void step1(intintvector &Data, ...) {
...
// create data arrays
intvector data0, data1, data2, data3;
// fill data0, data1, data2, data3
// ...
// save data arrays.
Data.push_back(data0);
Data.push_back(data1);
Data.push_back(data2);
Data.push_back(data3);
}
void step2(const intintvector &savedData, ...) {
// read data arrays
intvector data0 = savedData[0];
intvector data1 = savedData[1];
intvector data2 = savedData[2];
intvector data3 = savedData[3];
// ...
}
In brief summary: You aren't using correctly the pointer part if you don't take care of the dynamic memory, so, you must fix this issue or delegate into STL containers.
Hope it helps! :D

Use std::vector.
std::vector<int> data;
data.push_back(data0);
data.push_back(data1);
data.push_back(data2);
data.push_back(data3);
And
int data0 = data[0];
int data1 = data[1];
int data2 = data[2];
int data3 = data[3];
And add some code, where these functions will be used.

You will need an array of pointers, for example:
//The function that takes the array
void foo( char ** data )
{
std::cout << data[0];
std::cout << data[1];
std::cout << data[2];
}
main()
{
char * str = "aaa";
char * str1 = "sss";
char * str2 = "ddd";
char ** res = new char *[3];//here's your array that has 3 elements each of which is a pointer.
res[0]=str;
res[1]=str1;
res[2]=str2;
foo( res );
return 0;
}
The output will be
aaasssddd
A slightly better way:
It would be better to use stl containers instead of raw pointers since they are easier and safer to use. With pointers, it will work the same way:
void foo( std::vector< char * >vec )
{
std::cout << vec[0];
std::cout << vec[1];
std::cout << vec[2];
}
main()
{
char * str = "aaa";
char * str1 = "sss";
char * str2 = "ddd";
std::vector< char * >vec;
vec.push_back(str);
vec.push_back(str1);
vec.push_back(str2);
foo( vec );
return 0;
}
A further improved way:
And finally, the best way is to use strings:
void foo( std::vector< std::string >vec )
{
std::cout << vec[0];
std::cout << vec[1];
std::cout << vec[2];
}
main()
{
std::string str = "aaa";
std::string str1 = "sss";
std::string str2 = "ddd";
std::vector< std::string >vec;
vec.push_back(str);
vec.push_back(str1);
vec.push_back(str2);
foo( vec );
return 0;
}

Assuming you really want what you've written in question (4 arrays grouped into one), first of all you need 4 arrays, for example int:
int data1[] = {1,2,3,4};
int data2[] = {5,6,7,8,9,10};
int *data3; // Let's say those two were allocated by malloc/new
int *data4;
// Now array that will contain those values
int **data = new (int*)[4]; // int * = your datatype (array of ints)
// (int*)[] = array of arrays of ints
data[0] = data1;
data[1] = data2;
data[2] = data3;
data[3] = data4;
// And reverse function
data1 = data[0];
data2 = data[1];
data3 = data[2];
data4 = data[3];
Few notes:
if you want to have those "arrays" resizeable use (or use more than 4 items after time) use std::vector or another STL Container
if those data chucks have any special meaning (like data1 = user ids, data2 = visitor ids, ...) build class or structure that will name them:
// In C:
struct user_data{
int *user_ids;
int *visitor_ids;
char **unregistered_user_names; // Feel free to use another types
}
// In C++
class UserData {
std::vector<int> userIds;
std::vector<int> visitorIds;
std::vector<std::string> unregisteredUserNames;
}
Once allocated data with new unsigned int [4] don't forget free memory with delete [] array

I tried Vyktor's solution but it didn't work. I finally got it working using plain ol' arrays (no STL/vectors) and using the following code to save/load arrays from another parent array.
Note that this approach is considered "legacy" since you have to unallocate the arrays manually using the delete [] myArray syntax.
unsigned int** step1(...) {
...
// save data arrays
unsigned int** savedData = new unsigned int*[4]; // ** means pointer to a pointer
savedData[0] = data0; // transfer the pointer value straight
savedData[1] = data1;
savedData[2] = data2;
savedData[3] = data3;
return savedData;
}
unsigned char* step2(unsigned int** savedData, ...) { /// input is pointer to pointer
// read data arrays
unsigned int* data0 = savedData[0]; // read pointer straight
unsigned int* data1 = savedData[1];
unsigned int* data2 = savedData[2];
unsigned int* data3 = savedData[3];
...
}

Related

Is there a way in C++ to use a key word to determine array length?

I'm trying to make a function in C++ that will take a string input and use it to populate an array. The values that the array will be populated with are fixed, but it depends on the word passed in. Some of the elements stay the same, and some of them change. The array size is also dependent on the string that is passed in. I know I can do this by making two longer 'if' statements, but this method seems more efficent... if I can get it working. The code below is non-functioning, but it just to give a general idea of my headspace. Any help is appreciated. Thanks!
myString = "long";
if (myString == "short") {
int numArr* = new int[3];
numArr[2] = 0x02;
}
if (myString == "long") {
int numArr* = new int[5];
numArr[2] = 0x04;
numArr[4] = 0xA1;
numArr[5] = 0x32;
}
numArr[0] = 0x00;
numArr[1] = 0xFF;
numArr[3] = 0x50;
cout << numArr;
delete[] numArr;
First, to answer your question: Given a pointer-to-int (like numArr in your posted code), there is no portable way to query the size of the array that it points to (or even to verify that it actually points to an array at all!)
If you have a proper array, like this (not just a pointer), OTOH:
int properArray[6];
... a function like this will return the number of items in the array:
template<typename T, int size> constexpr unsigned int GetArraySize(T(&)[size])
{
return size;
}
unsigned int arraySize = GetArraySize(properArray); // sets arraySize to 6
That said, it seems to me the best way to make your code simpler and more efficient is to allocate a fixed-size array on the stack (large enough to handle your worst-case-scenario) and keep track of how many items in the array are actually being used, like this:
#include <string>
#include <iostream>
int main(int, char **)
{
int numArr[6] = {0x00, 0xFF, 0x00, 0x50, 0x00, 0x00};
int numValidArrayItems = 3;
std::string myString = "long";
if (myString == "short") {
numArr[2] = 0x02;
}
else if (myString == "long") {
numArr[2] = 0x04;
numArr[4] = 0xA1;
numArr[5] = 0x32;
numValidArrayItems = 6;
}
for (int i=0; i<numValidArrayItems; i++) std::cout << numArr[i] << "\n";
return 0;
}
That avoids the new and delete[] calls, which are likely to be the most expensive (and error-prone) parts of the posted code, and also avoids the need to query the numArr pointer to determine the size of the array it is pointing to.
int r[10];
int count = sizeof(r)/sizeof(r[0]);
cout<<count;
I saw only this type of solution, sorry. You can look at this thread and get better insight(if you wan to use function, for example)
Link for mentioned thread:
Element count of an array in C++

Corrupted struct char arrays - sqlite C++

I am a bit puzzled by this one. Everything has been fine so far with using SQLite but now I am trying to store my query results in a simple struct. When I do this in my callback, all my data looks great in my SQLItems vector but as soon as the callback exits, my SQLItems vector holding my rows of data is suddenly corrupted. Any ideas what could be causing this?
// Simple struct to hold column name and row data
struct SQLrow {
char * Column;
char * Data;
};
// static Vector to hold SQL rows
static std::vector<SQLrow> SQLItems;
...
// static callback that handles placing query results into structs and into SQLItems vector
// SQLItems column/row data gets corrupted after this function exits
static int countTablesCallback(void *data, int count, char **rows, char **azColName) {
int i;
for (i = 0; i < count; i++) {
SQLrow newItem = { azColName[i] ,rows[i] };
SQLItems.push_back(newItem);
}
*static_cast<std::vector<SQLrow>*>(data) = SQLItems; // Tried this too but throws an exception
return 0;
}
I also thought maybe it is only possible to statically cast from the callback to save the vector but that is throwing an exception as well. Stumped here. Thanks for any advice!
Your vector is fine, the static_cast makes no sense there, unless data is actually used as an out parameter. Your problem is, most likely, that SQLrow holds char pointer and SQLite deletes the pointed-to strings after the callback returns. Changing your class to
struct SQLrow {
std::string Column;
std::string Data;
};
should solve the problem.
Just looking at the code, it appears that the data pointed to by rows will be invalidated/destroyed/changed once the callback returns. So you can't retain those pointers for later use, and will have to make a copy of the data.
One easy way is to change Column and Data from char * to std::string. Failing that, you'll have to do some sort of manual memory management (allocate space with new, then delete it later) which is error prone and not really advisable these days.
In my opinion, there are very few case in which you want/need to use raw string in c++ and yours isn't one of those. By the way I hope this will help you or someone else in some way:
#include <vector>
#include <stdio.h>
#include <string.h>
#include <iostream>
struct SQLrow {
char* Column;
char* Data;
};
void your_callback(int count, char **rows, char **azColName) {
std::vector<SQLrow> rows_list;
for (int i = 0; i < count; i++) {
/* Uncomment this if you want
your copy of the strings. If you
use this, don't forget to free the
memory yourself with delete[] s1 and
s2.
size_t s1_len = strlen(rows[i]);
size_t s2_len = strlen(azColName[i]);
char* s1 = new char [sizeof(char) * (s1_len + 1)];
char* s2 = new char [sizeof(char) * (s2_len + 1)];
memcpy(s1, rows[i], s1_len);
s1[s1_len] = '\0';
memcpy(s2, azColName[i], s2_len);
s2[s2_len] = '\0';
SQLrow r = { s1, s2 }; */
SQLrow r = { rows[i], azColName[i] };
rows_list.push_back(r);
}
// test the result
for (int i = 0; i < count; i++) {
SQLrow r = rows_list.at(i);
std::cout << "rows:" << r.Column << " azColName:" << r.Data << std::endl;
}
}
// this 2 lines are just for simulating the data
// you will get this 'warning: ISO C++ forbids converting a string constant to char*''
char* rows[] = {"row1", "row2" , "row3" };
char* colName[] = {"name1", "name2", "name3" };
int main()
{
your_callback(3, rows, colName);
return 0;
}

Clear out the STL list of pointers in C++

I have defined a list of pointers. How should I free all these pointers before clearing the list? What is the best approach to erase all list members? In below program, is it required to free memory allocated for struct?? See my inline comments.
struct MyStruct {
char *data;
int len;
};
typedef std::list<struct MyStruct *> myStruct_list;
myStruct_list l_list;
/* Prepare a list */
for( int i = 0; i < 10; i++) {
struct MyStruct *s = (MyStruct *)malloc(sizeof(struct MyStruct));
s->data = (char*)malloc(MAX_LEN);
get_random_data(s->data,size);
s->len = strlen(s->data);
l_list.push_back(s);
}
/* Delete all members from a list */
myStruct_list::iterator it;
for (it = l_list.begin(); it != l_list.end(); ++it) {
if (*it) {
free(*it); // --->> do I need to free (*it)->data ?????
}
}
l_list.clear();
I want to understand is there any memory leak in below program?
Yes you have it right here:
p = (char*)malloc(MAX_LEN);
p = (char *)buf;
you allocate memory and assign it to p and next line you loose it. So:
You should not use malloc() in C++ programs unless you need to pass data that would be managed by C code
You should use special data structure like std::string etc to manage your data.
If you still need to allocate dynamic memory use smart pointers.
How should I debug if there is any memory leak?
You would not create them in the first place. For example, how could you write get_random_str (assuming you really have to allocate it using malloc):
using spchar = std::unique_ptr<char[], decltype(std::free) *>;
spchar get_random_str( int len )
{
spchar s( static_cast<char *>( malloc( len + 1 ) ), std::free );
static const char alphanum[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
for (int i = 0; i < len; ++i) {
s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
}
s[len] = '\0';
return s;
}
Note, I did not compile this code, it's to show you the idea.
Update: looks like you think that this code:
p = (char *)buf;
would copy string from buf to p, which is not the case. Instead you make p point to memory of buf loosing old value that malloc() returned before (hence creating memory leak) and you assign that adress of buf to data which leads to UB when you call free() on it, so what you need instead:
strncpy( p, buf, MAX_LEN );
but even that is not necessary as you do not really need buf at all:
void myClass::fillData(void)
{
s = (MyStruct *)malloc(sizeof(struct MyStruct));
s->data = (char*)malloc(MAX_LEN);
get_random_str(s->data,950);
s->len = strlen(s->data);
l_list.push_back(s);
}
but this is more C code, using some C++ syntax. You should get newer compiler and textbook if you really want to learn C++.
Delete elements using lambda function in for_each:
std::for_each(l_list.begin(), l_list.end(), [](const MyStruct* elem){if(elem) free(elem)});
And clear pointers:
l_list.clear();

How to dynamically allocate an 2d array to a struct

I'm trying to dynamically allocate an array on the heap using a structure that has a pointer to an array and a string. Here's my code.
struct StudentRecords
{
string names;
int* examsptr;
};
void main()
{
const int NG = 5;
string names[] = { "Amy Adams", "Bob Barr", "Carla Carr",
"Dan Dobbs", "Elena Evans"
};
int exams[][NG] =
{
{ 98,87,93,88 },
{ 78,86,82,91 },
{ 66,71,85,94 },
{ 72,63,77,69 },
{ 91,83,76,60 }
};
StudentRecords *data = nullptr;
(*data).examsptr = new int[][NG];
int *data = new int[NG*NG];
There's a number of problems with your current code.
StudentRecords *data = nullptr; //here you set data to nullptr
(*data).examsptr = new int[][NG]; //then you dereference nullptr, BAD
int *data = new int[NG*NG]; //then you declare another variable with the same name, BAD
You should rename one of your variables and set student records to an actual instance of StudentRecords.
You can't dynamically allocate a 2D array in one step like 'new int[rows][cols]'. Instead you either need to allocate a 1D array with rows*cols elements and do maths to convert a row and col into an index of the 1D array or you need to allocate an array of pointers, where each pointer points to an array holding the data. To hold the array of pointers you need a pointer to a pointer, so you need to make examsptr an int**.
You then need to allocate the arrays that are pointed at by the array of pointers in a loop.
EG:
//cant be nullptr if you want to dereference it
StudentRecords *data = new StudentRecords();
//data-> is shorthand for (*data).
//allocates array of pointers, length NG
data->examsptr = new int*[NG]
//now make the 2nd dimension of arrays
for(int i = 0; i < NG; ++i){
data->examsptr[i] = new int[NG];
}

How to cast from char pointer to custom object pointer

I'm using leveldb to store key-value pairs of integer and MyClass objects. Actually, a key can contain more then one of theses objects.
The problem I have appears when retrieving the data from the database. It compiles, however the values of the MyClass members are not the one I put into the database.
std::string value;
leveldb::Slice keySlice = ANYKEY;
levelDBObj->Get(leveldb::ReadOptions(), keySlice, &value);
The std::string value1 can now contain only one MyClass object or more. So how do I get them?
I already tried the following which didn't work;
1.) directly typecasting and memcpy
std::vector<MyClass> vObjects;
MyClass* obj = (MyClass*)malloc( value.size());
memcpy((void*)obj, (void*) (value.c_str()), value.size());
MyClass dummyObj;
int numValues = value.size()/sizeof(MyClass);
for( int i=0; i<numValues; ++i) {
dummyObj = *(obj+i);
vObjects.push_back(dummyObj);
}
2.) reinterpret_cast to void pointer
MyClass* obj = (MyClass*)malloc( value.size());
const void* vobj = reinterpret_cast<const void*>( value.c_str() );
int numValues = value.size()/sizeof(MyClass);
for( int i=0; i<numValues; ++i) {
const MyClass dummyObj = *(reinterpret_cast<const MyClass*>(vobj)+i);
vObjects.push_back(dummyObj);
}
MyClass is a collection of several public members, e.g. unsigned int and unsigned char and it has a stable size.
I know that there are similar problems with only one object. But in my case the vector can contain more then one and it comes from the leveldb database.
EDIT: SOLUTION
I wrote (de)serialization method for MyClass which then made it working. Thanks for the hint!
void MyClass::serialize( char* outBuff ) {
memcpy(outBuff, (const void*) &aVar, sizeof(aVar));
unsigned int c = sizeof(aVar);
memcpy(outBuff+c, (const void*) &bVar, sizeof(bVar));
c += sizeof(bVAr);
/* and so on */
}
void MyClass::deserialize( const char* inBuff ) {
memcpy((void*) &aVar, inBuff, sizeof(aVar));
unsigned int c = sizeof(aVar);
memcpy((void*) &aVar, inBuff+c, sizeof(aVar));
c += sizeof(aVar);
/* and so on */
}
The get method is as follows (put analogously):
int getValues(leveldb::Slice keySlice, std::vector<MyObj>& values) const {
std::string value;
leveldb::Status status = levelDBObj->Get(leveldb::ReadOptions(), keySlice, &value);
if (!status.ok()) {
values.clear();
return -1;
}
int nValues = value1.size()/sizeof(CHit);
MyObj dummyObj;
for( int i=0; i<nValues; ++i) {
dummyObj.deserialize(value.c_str()+i*sizeof(MyObj));
values.push_back(dummyObj);
}
return 0;
}
You have to serialize your class... otherwise, you're just taking some memory and writing it in leveldb. Whatever you get back is not only going to be different, but it will probably be completely useless too. Check out this question for more info on serialization: How do you serialize an object in C++?
LevelDB does support multiple objects under one key, however, try to avoid doing that unless you have a really good reason. I would recommend that you hash each object with a unique hash (see Google's CityHash if you want a hashing function) and store the serialized objects with their corresponding hash. If your objects is a collection in itself, then you have to serialize all of your objects to an array of bytes and have some method that allows you to determine where each object begins/ends.
Update
A serializable class would look something like this:
class MyClass
{
private:
int _numeric;
string _text;
public:
// constructors
// mutators
void SetNumeric(int num);
void SetText(string text);
static unsigned int SerializableSize()
{
// returns the serializable size of the class with the schema:
// 4 bytes for the numeric (integer)
// 4 bytes for the unsigned int (the size of the text)
// n bytes for the text (it has a variable size)
return sizeof(int) + sizeof(unsigned int) + _text.size();
}
// serialization
int Serialize(const char* buffer, const unsigned int bufferLen, const unsigned int position)
{
// check if the object can be serialized in the available buffer space
if(position+SerializableSize()>bufferLen)
{
// don't write anything and return -1 signaling that there was an error
return -1;
}
unsigned int finalPosition = position;
// write the numeric value
*(int*)(buffer + finalPosition) = _numeric;
// move the final position past the numeric value
finalPosition += sizeof(int);
// write the size of the text
*(unsigned int*)(buffer + finalPosition) = (unsigned int)_text.size();
// move the final position past the size of the string
finalPosition += sizeof(unsigned int);
// write the string
memcpy((void*)(buffer+finalPosition), _text.c_str(), (unsigned int)_text.size());
// move the final position past the end of the string
finalPosition += (unsigned int)_text.size();
// return the number of bytes written to the buffer
return finalPosition-position;
}
// deserialization
static int Deserialize(MyClass& myObject,
const char* buffer,
const unsigned int buffSize,
const unsigned int position)
{
insigned int currPosition = position;
// copy the numeric value
int numeric = *(int*)(buffer + currentPosition);
// increment the current position past the numeric value
currentPosition += sizeof(int);
// copy the size of the text
unsigned int textSize = *(unsigned int*)(buffer + currentPosition);
// increment the current position past the size of the text
currentPosition += sizeof(unsigned int);
// copy the text
string text((buffer+currentPosition), textSize);
if(currentPosition > buffSize)
{
// you decide what to do here
}
// Set your object's values
myObject.SetNumeric(numeric);
myObject.SetText(text);
// return the number of bytes deserialized
return currentPosition - position;
}
};