Corrupted struct char arrays - sqlite C++ - 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;
}

Related

Return char[256] from an accessor of a char[256] attribute

class A{
char info[256];
public:
char* getInfo();
A(char i[256]);
//A.cpp
#include "A.h"
char * A::getInfo(){
return(&info[256]);
}
A::A(char i[256]){
info[256]=i[256];
}
I'm struggling with the accessor. When I try to use getInfo(), I get a char*, and thus with
char test[256] = "test";
FractionException d(test);
for (int i = 0; i < 256; i++) {
cout << d.getInfo()[i] ;
}
I get
╠╠╠╠╠╠╠╠test
I guess I'm doing things the wrong way, but I cant figure it out..
By the way, VScode also warn me on
info[256]=i[256]
by telling me that 257 octets bytes might be written (C6386) but I dont get it ...
Could you help me please ? Thanks !
The problem is, your constructor is not initializing the contents of the info array correctly, and your accessor is returning a bad pointer.
In the constructor, info[256]=i[256] does not do what you think it does. You are trying to copy the 257th element of i into the 257th element of info, which is Undefined Behavior since neither array has 257 elements. That is why the compiler is warning you about it.
Try this instead:
A::A(char i[256]){
for(int x = 0; x < 256; ++x){
info[x] = i[x];
}
}
Alternatively:
#include <algorithm>
A::A(char i[256]){
std::copy_n(i, 256, info);
}
As for the accessor, it is returning a pointer to the non-existent 257th element. You need to return a pointer to the 1st element instead:
char * A::getInfo(){
return(&info[0]);
}
Or simply:
char * A::getInfo(){
return info;
}
This declaration of the constructor
A(char i[256]);
does not make a great sense because the compiler will adjust the parameter declaration like
A(char *i);
Taking into account this code snippet
char test[256] = "test";
FractionException d(test);
for (int i = 0; i < 256; i++) {
cout << d.getInfo()[i] ;
}
It seems you want that the constructor would accept a string. If so then it should be declared like
A( const char * );
and it can be defined like
#include <cstring>
//...
A::A( const char *i ){
strncpy( info, i, sizeof( info ) );
info[sizeof( info ) - 1] = '\0';
}
The member function getInfo should return the array instead of the address of the non-existent element info[256]
char * A::getInfo(){
return info;
}
This method should be also overloaded
const char * getInfo() const;
And this loop
for (int i = 0; i < 256; i++) {
cout << d.getInfo()[i] ;
}
should be substituted for this statement
std::cout << d.getInfo();

Using an allocated structure data in an std::thread

I ran into a little problem programming something, I've looked around but I didn't seem to find out the answer.
I'll spare you useless code.
Here are the declarations:
struct one {
std::string string1, string2;
bool boolean;
};
struct two {
std::string string3, string4;
bool boolean;
};
void function(uint first_parameter, one **first, two **second);
And here is what the main looks like:
int main()
{
one *passes;
two *users;
//...
passes = new one[size_one]();
users = new two[size_two]();
//Filling the arrays...
std::thread t[PARTS];
for (int start = 0; start < PARTS; start++)
t[start] = std::thread(function, first_parameter, &passes, &users);
for (int i = 0; i < PARTS; i++)
t[i].join();
}
Whenever I try to access an element of one of my structures (allocated on the free store) in my thread function, (I typically would access it like so: (*first)[0].string1[0]) I do not get the string1 I normally can access in main. Aren't the std::strings located in the free store?
check your function to have valid types of parameters.
this example bellow works nice.
#include <iostream>
typedef struct _one
{
std::string first_str;
std::string second_str;
bool check;
} one;
void do_something(one** passes)
{
one* original = *passes;
one first = original[0];
std::cout << first.first_str; // -> hello
// the same
std::cout << (*passes)[0].first_str;
}
int main()
{
one* passes = nullptr;
passes = new one[10];
passes[0].first_str = "hello";
do_something(&passes);
}

C++ struct values lost

I have a strange issue. I allocate char[] values in struct array, but they get lost:
------- The struct is this one :
typedef struct _Settings
{
const char* str;
uint val;
}Settings;
------- I create it like this :
int nn=10;
settings = new Settings[nn];
for (int i = 0; i < nn; i++) {
string strr = "thisOneIs";
strr.append(std::to_string(i));
settings[i].str = strr.c_str();
string teststr = settings[i].str; //// (1)
settings[i].val = i + 1;
}
..... at (1), I get the correct values.
But if I then call this (same place, right after the code above), the settings[i].str is empty:
for (int i = 0; i < nn; i++) {
string teststr = settings[i].str; ///// (2)
std::cout << settings[i].str << "=" << settings[i].val << "\n";
}
... at (2), I get empty.
Does anyone have a clue why? Thanks!
The line at (1) is a problem because you are storing a pointer to some memory that is not valid when the loop ends.
string strr = "thisOneIs"; // A temporary object in the loop.
strr.append(std::to_string(i));
settings[i].str = strr.c_str(); // Pointer that won't be valid when the loop ends.
If you learning about low level language features, it's ok to experiment with using char* and raw memory. If you are trying to get a working program, just use std::string.
Also simplify the definition of Settings. You don't need all the typedef non-sense in C++.
struct Settings
{
std::string str;
uint val;
};

C++ Declaring arrays in class and declaring 2d arrays in class

I'm new with using classes and I encountered a problem while delcaring an array into a class. I want to initialize a char array for text limited to 50 characters and then replace the text with a function.
#ifndef MAP_H
#define MAP_H
#include "Sprite.h"
#include <SFML/Graphics.hpp>
#include <iostream>
class Map : public sprite
{
private:
char mapname[50];
int columnnumber;
int linenumber;
char casestatematricia[];
public:
void setmapname(char newmapname[50]);
void battlespace(int column, int line);
void setcasevalue(int col, int line, char value);
void printcasematricia();
};
#endif
By the way I could initialize my 2d array like that
char casestatematricia[][];
I want later to make this 2d array dynamic where I enter a column number and a line number like that
casestatematricia[linenumber][columnnumber]
to create a battlefield.
this is the cpp code so that you have an idea of what I want to do.
#include "Map.h"
#include <SFML/Graphics.hpp>
#include <iostream>
using namespace sf;
void Map::setmapname(char newmapname[50])
{
this->mapname = newmapname;
}
void Map::battlespace(int column, int line)
{
}
void Map::setcasevalue(int col, int line, char value)
{
}
void Map::printcasematricia()
{
}
thank you in advance.
Consider following common practice on this one.
Most (e.g. numerical) libraries don't use 2D arrays inside classes.
They use dynamically allocated 1D arrays and overload the () or [] operator to access the right elements in a 2D-like fashion.
So on the outside you never can tell that you're actually dealing with consecutive storage, it looks like a 2D array.
In this way arrays are easier to resize, more efficient to store, transpose and reshape.
Just a proposition for your problem:
class Map : public sprite
{
private:
std::string mapname;
int columnnumber;
int linenumber;
std::vector<char> casestatematricia;
static constexpr std::size_t maxRow = 50;
static constexpr std::size_t maxCol = 50;
public:
Map():
casestatematricia(maxRow * maxCol, 0)
{}
void setmapname(std::string newmapname)
{
if (newmapname.size() > 50)
{
// Manage error if you really need no more 50 characters..
// Or just troncate when you serialize!
}
mapname = newmapname;
}
void battlespace(int col, int row);
void setcasevalue(int col, int row, char value)
{
// check that col and line are between 0 and max{Row|Column} - 1
casestatematricia[row * maxRow + col] = value;
}
void printcasematricia()
{
for (std::size_t row = 0; row < maxRow; ++row)
{
for (std::size_t col = 0; col < maxCol; ++col)
{
char currentCell = casestatematricia[row * maxRow + col];
}
}
}
};
For access to 1D array like a 2D array, take a look at Access a 1D array as a 2D array in C++.
When you think about serialization, I guess you want to save it to a file. Just a advice: don't store raw memory to a file just to "save" time when your relaunch your soft. You just have a non portable solution! And seriously, with power of your computer, you don't have to be worry about time to load from file!
I propose you to add 2 methods in your class to save Map into file
void dump(std::ostream &os)
{
os << mapname << "\n";
std::size_t currentRow = 0;
for(auto c: casestatematricia)
{
os << static_cast<int>(c) << " ";
++currentRow;
if (currentRow >= maxRow)
{
currentRow = 0;
os << "\n";
}
}
}
void load(std::istream &is)
{
std::string line;
std::getline(is, line);
mapname = line;
std::size_t current_cell = 0;
while(std::getline(is, line))
{
std::istringstream is(line);
while(!is.eof())
{
char c;
is >> c;
casestatematricia[current_cell] = c;
++current_cell;
}
}
}
This solution is only given for example. They doesn't manage error and I have choose to store it in ASCII in file. You can change to store in binary, but, don't use direct write of raw memory. You can take a look at C - serialization techniques (just have to translate to C++). But please, don't use memcpy or similar technique to serialize
I hope I get this right. You have two questions. You want know how to assign the value of char mapname[50]; via void setmapname(char newmapname[50]);. And you want to know how to create a dynamic size 2D array.
I hope you are comfortable with pointers because in both cases, you need it.
For the first question, I would like to first correct your understanding of void setmapname(char newmapname[50]);. C++ functions do not take in array. It take in the pointer to the array. So it is as good as writing void setmapname(char *newmapname);. For better understanding, go to Passing Arrays to Function in C++
With that, I am going to change the function to read in the length of the new map name. And to assign mapname, just use a loop to copy each of the char.
void setmapname(char *newmapname, int length) {
// ensure that the string passing in is not
// more that what mapname can hold.
length = length < 50 ? length : 50;
// loop each value and assign one by one.
for(int i = 0; i < length; ++i) {
mapname[i] = newmapname[i];
}
}
For the second question, you can use vector like what was proposed by Garf365 need to use but I prefer to just use pointer and I will use 1D array to represent 2d battlefield. (You can read the link Garf365 provide).
// Declare like this
char *casestatematricia; // remember to initialize this to 0.
// Create the battlefield
void Map::battlespace(int column, int line) {
columnnumber = column;
linenumber = line;
// Clear the previous battlefield.
clearspace();
// Creating the battlefield
casestatematricia = new char[column * line];
// initialise casestatematricia...
}
// Call this after you done using the battlefield
void Map::clearspace() {
if (!casestatematricia) return;
delete [] casestatematricia;
casestatematricia = 0;
}
Just remember to call clearspace() when you are no longer using it.
Just for your benefit, this is how you create a dynamic size 2D array
// Declare like this
char **casestatematricia; // remember to initialize this to 0.
// Create the battlefield
void Map::battlespace(int column, int line) {
columnnumber = column;
linenumber = line;
// Clear the previous battlefield.
clearspace();
// Creating the battlefield
casestatematricia = new char*[column];
for (int i = 0; i < column; ++i) {
casestatematricia[i] = new char[line];
}
// initialise casestatematricia...
}
// Call this after you done using the battlefield
void Map::clearspace() {
if (!casestatematricia) return;
for(int i = 0; i < columnnumber; ++i) {
delete [] casestatematricia[i];
}
delete [][] casestatematricia;
casestatematricia = 0;
}
Hope this help.
PS: If you need to serialize the string, you can to use pascal string format so that you can support string with variable length. e.g. "11hello world", or "3foo".

What is the easiest way to initialize a 2d array from a vector of strings?

I have:
vector<string> myVector = {0};
myVector.push_back("first");
myVector.push_back("second");
char *list[] = ????
I want it to be initialized like if I was doing this
char *list[] = { "first", "second", NULL };
I know I can start allocating memory based on the size and of the vector and the size of the longest string in the vector (list[v.size()+1][longest_string_in_vector]) but I wanted to see I'm not thinking of something that might be easier/faster.
If the legacy code requires a char **, then to create a variable list, you can create a vector as you initially are doing in your question.
After that, create a std::vector<char *>, where the pointers are pointers within the vector for each item. Of course, you have to ensure that the vector doesn't go out of scope or is resized. It has to be fully "set up" before creating the std::vector<char *>.
In addition, since you are certain that the legacy function does not attempt to alter the strings sent to it, we should take away the "constness" of the strings.
#include <vector>
#include <string>
#include <iostream>
void legacy_function(char **myList)
{
for (int i = 0; myList[i]; ++i)
std::cout << myList[i] << "\n";
}
using namespace std;
int main()
{
vector<string> myVector;
myVector.push_back("first");
myVector.push_back("second");
//...
// create the pointer vector
vector<char *> myPtrVector;
// add pointer to string to vector
for (size_t i = 0; i < myVector.size(); ++i)
myPtrVector.push_back(const_cast<char*>(myVector[i].c_str()));
// stick the null at the end
myPtrVector.push_back(NULL);
// ...
// call legacy function
legacy_function(&myPtrVector[0]);
}
Basically, we created the strings in a vector, and created another vector that stores pointers to the strings.
Note that the function legacy_function takes a char **, and all we need to do is pass it the address of the first element in our pointer vector.
Live Example: http://ideone.com/77oNns
Edit: Rather than having the code strewn in different areas of your program, a better approach in terms of code organization is to encapsulate the creation of the array:
#include <vector>
#include <string>
class CharPtrPtr
{
std::vector<std::string> m_args;
std::vector<char *> m_argsptr;
public:
void add(const std::string& s) { m_args.push_back(s); }
char ** create_argsPtr()
{
m_argsptr.clear();
for (size_t i = 0; i < m_args.size(); ++i)
m_argsptr.push_back(const_cast<char*>(m_args[i].c_str()));
m_argsptr.push_back(NULL);
return &m_argsptr[0];
}
char **get_argsPtr() { return m_argsptr.empty()?NULL:&m_argsptr[0]; }
void clear_args() { m_args.clear(); m_argsptr.clear(); }
};
#include <iostream>
void legacy_function(char **myList)
{
for (int i = 0; myList[i]; ++i)
std::cout << myList[i] << "\n";
}
int main()
{
CharPtrPtr args;
args.add("first");
args.add("second");
legacy_function(args.create_argsPtr());
}
Live Example: http://coliru.stacked-crooked.com/a/834afa665f054a1f
I tried these two ways,
1.Initialize manually
char *list[] = { (char*)&myVector[0][0], (char*)&myVector[1][0] };
2.Initialize in a loop
char **list2 = new char*[ myVector.size() ];
for ( unsigned int i = 0; i < myVector.size(); ++i ) {
list2[ i ] = (char*)&myVector[ i ][0];
}
However these lists only have pointers to the each string in the vector and don't actually have a copy. If you change the strings, you'll see the changes from the lists. But if you empty the vector then the lists will have a dangling pointer.
3.If you want a copy of the strings then,
char **list = new char*[ myVector.size() ];
for ( unsigned int i = 0; i < myVector.size(); ++i ) {
list[ i ] = new char[myVector[i].size()+1];
strcpy( list[ i ], &myVector[i][0] );
}
I wouldn't write this code but, there you go..