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);
}
Related
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;
}
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;
};
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".
I'm totally lost and confused and could use some help.
I'm currently working on a small command line-based game. For this I wrote a class Inventory, dynamically creating an array of invSpace-objects, each space representing a pair of a pointer to an Item (another class of mine) and a integer, depicting a quantity. Here's the code:
class invSpace {
public:
Item *item;
int quantity;
invSpace() {
item = NULL;
quantity = 0;
}
};
class Inventory {
private:
invSpace* spaces = NULL;
size_t size;
public:
int free_space() {
int free = 0;
for (int i = 0; i < size; i++) {
if (spaces[i].item == NULL) {
free++;
}
}
return free;
}
Inventory() {}
Inventory(size_t new_size) {
size = new_size;
spaces = new invSpace[size];
for (int i = 0; i < size; i++) { //I know this is obsolete because
spaces[i].item = NULL; //of the invSpace constructor, I
spaces[i].quantity = 0; //just did this for testing
}
~Inventory() {
delete[] spaces;
}
invSpace& operator[](int index) {
return spaces[index];
}
};
There are some more methods in this class, like for adding, deleting and searching for items, but those don't matter now. So this is basically just a simple array within one object, dynamically allocating memory in the constructor and with some extra methods. After being created, the array contains zero elements, or Items, so the free_space() method should return the size of the array. But it doesn't. It returns about half of the size.
My first thought was that something went wrong with the allocation. But at a second glance I noticed that the Inventory is totally fine directly after being created; with exactly as many spaces as requested, all of them set to item=NULL/quantity=0. But after a call of getline() at the start of main() that scans user input and saves it to a string for further analyzing, some spaces get filled with random addresses and integers.
Even stranger, with each new call of getline() some spaces are freed, some others filled. As far as my debugging, experimenting and testing goes, none of these addresses belong to any variable in my program, they are just plain random. Also, at no point is there be any interference with the Inventory and the getline() function or the string it returns. In fact, after being created, no part of this object is used anywhere in the code beside the free_space() method. What's even stranger is that spaces in the Inventory class is marked private, so a method is required to meddle with this pointer/array (or so I would expect).
This problem occurs with getline() and cin but not with any of C's <stdio.h> input stream functions. Using malloc() instead of new[] makes no difference. Of course, I could use something like scanf() for the reading from the console. Still, I just want to know why all these things happen. I have absolutely no idea.
Thanks in advance for every answer!
EDIT:
I narrowed the whole code so that it still produces the same error, also changed free_space() so that it prints adress and integer if present:
#include <iostream>
#include <string>
#include <map>
using namespace std;
class Item {
public:
static map<string, Item*> itemlist;
string name;
string description;
Item() {}
Item(const string new_name, const string new_description) {
name = new_name;
description = new_description;
itemlist.insert(pair<string, Item*> (name, this));
}
};
map<string, Item*> Item::itemlist;
/*The more Items are declared, the more random adresses appear in the
inventory*/
Item item01("sword", "A sharp and deadly weapon.");
Item item02("shield", "This will protect you. To a certain extent.");
Item item03("stick", "What is this for exactly?");
Item item04("bottle of water", "A bottle full of refreshing spring water.");
class invSpace {
public:
Item *item;
int quantity;
invSpace() {
item = NULL;
quantity = 0;
}
};
class Inventory {
private:
invSpace* spaces = NULL;
size_t size;
public:
int free_space() {
int free = 0;
for (int i = 0; i < size; i++) {
if (spaces[i].item == NULL) {
free++;
cout << i << " = free" << endl;
}
else {
cout << spaces[i].item << " / " << spaces[i].quantity << endl;
}
}
return free;
}
Inventory() {}
Inventory(size_t new_size) {
size = new_size;
spaces = new invSpace[size];
for (int i = 0; i < size; i++) {
spaces[i].item = NULL;
spaces[i].quantity = 0;
}
}
~Inventory() {
delete[] spaces;
}
};
class Player {
public:
string name;
Inventory inventory;
Player(const string new_name) {
inventory = Inventory(40);
name = new_name;
}
};
Player player("Me");
int main() {
string input;
//Inventory inventory(40); //no error when declared outside the Player class
while (1) {
cout << "\n>> ";
getline(cin, input);
if (input == "x") {
break;
}
else {
player.inventory.free_space();
}
}
}
Some things I noticed: No error occurs if the inventory isn't part of a Player-object. If it is but no Items are declared only the first inventory space receives a random adress (and int value) after the first call of getline().
The more Items there are, the more random adresses I get, it seems...
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..