Filling a string buffer when using Ocilib - c++

I'm using Ocilib to perform a bulk insert on a Oracle database but I'm having some trouble while filling a string buffer.
The documentation says:
For string/RAW arrays, the input array
MUST BE a contiguous block of data and
not an array of pointers. So to bind
an array of 10 elements for a
varchar2(30) column, binded variable
must be a like array[10][31]
And a sample proceeds to fill a buffer like this:
...
char tab_str[1000][21];
...
OCI_BindArrayOfStrings(st, ":s", (char*) tab_str, 20, 0);
...
for(i=0;i<1000;i++)
{
sprintf(tab_str[i],"Name %d",i+1);
}
...
I'm trying to fill the string buffer while looping through a std::vector of MyClass. MyClass has a std::string member.
I'm trying to use the std::string::copy method to copy over the string contents to the buffer. But I don't know exactly how to index the buffer to do it.
...
OCI_BindArrayOfStrings(st, ":f2", NULL, VCHAR_SIZE, 0);
char** vc_buffer = (char**)OCI_BindGetData(OCI_GetBind(st, 2));
...
int i = 0;
for(vector<MyClass>::const_iterator it = myVec.begin(); it != myVec.end(); ++it)
{
/* 1st try */ it->m_string.copy((vc_buffer + (i * VCHAR_SIZE)), VCHAR_SIZE);
/* 2nd try */ it->m_string.copy(vc_buffer[i], VCHAR_SIZE);
++i;
...
}
...
The first way gives me buggy data in the database. The second makes me hit a null pointer.
What I'm doing wrong?
PS:
The second approach, along the approach proposed by Alessandro Vergani below, results in null strings inserted. The first approach gives this (somewhat bizarre) result:
The gvim window shows what it's supposed to look like, the apex screen shows what ends up in the database.

(Try:
std::vector<char> tab_str(myVec.size() * (VCHAR_SIZE + 1));
...
OCI_BindArrayOfStrings(st, ":s", &tab_str[0], VCHAR_SIZE, 0);
...
int offset = 0;
for(vector<MyClass>::const_iterator it = myVec.begin(); it != myVec.end(); ++it, offset += VCHAR_SIZE)
{
it->m_string.copy(&tab_str[offset], VCHAR_SIZE);
...
}
...
I'm not sure you need to add the null terminator: if not, remove the -1 from the copy and remove the second line.

Related

For loop in C++ stops after a single iteration w/ pointer variable

So first all I'll preface this with: I just started using c++.
I have a structure that I store the pointer to in an unordered_map, setting members' values in the struct pointer as I get them through my process. Then I no longer need them in a map so I transfer then to a vector and loop through them.
Though on the second loop, it outputs my index (1) but the next statement of making a local pointer var for the struct at that index breaks it and the code terminates without any errors. since there are no errors then a try/catch doesn't give me anything either.
// Wanted to create a structure to handle the objects easier instead
// of multiple vectors for each property
struct appData {
std::string id = "";
std::string name = "";
std::string vdf_file = "";
std::string vdf_path = "";
};
// Relevant parts of my main()
int main() {
// Map that stores all the struct pointers
std::unordered_map<std::string, appData*> appDatas;
char memory[sizeof(appData)];
void* p = memory;
// New instance of appData
appData *tempAppData = new(p) appData();
tempAppData->appid = "86901";
// Add tempAppData to map with string key
appDatas["86901"] = tempAppData;
...
std::vector<appData*> unhashed_appDatas;
for (auto const& pair: appDatas) {
unhashed_appDatas.push_back(pair.second);
}
...
for (unsigned int x = 0; x < unhashed_appDatas.size(); x++) {
// Output index to see where it was messing up
std::cout << x << std::endl;
!! // This is where the issue happens on the second loop (see output)
appData *thisAppData = unhashed_appDatas[x];
std::string id = thisAppData->appid;
std::cout << id << std::endl;
/* ...
Do more stuff below
*/
}
...
return 0;
}
Terminal Output:
0 // Initial index of x
86901 // Id of first item
1 // New index of x on second loop before pointer var is created
// Nothing more is printed and execution terminates with no errors
My knowledge of c++ is pretty lacking, started it couple days ago, so the few things within my knowledge I've tried: moving the *thisAppData variable outside of the loop, using a for(var: vector) { ... }, and a while loop. I can assume that the issue lies with the pointer and the local variable when inside the loop.
Any help/input about how I could better approach this or if there's an issue with my code would be appreciated :)
Edit: Changed code to use .size() instead of sizeof() per #Jarod42 answer, though main issue persists
Edit2: Turns out it was my own mess-up, imagine that. 4Am brain wasn't working too well- posted answer regarding what I did incorrectly. Thanks to everyone who helped me
sizeof is the wrong tool here:
for (unsigned int x = 0; x < sizeof(unhashed_appDatas); x++) {
// ^^ wrong: give **static** size of the structure
// mainly 3 members (data, capacity, size), so something like `3*sizeof(void*)`
it should be
for (unsigned int x = 0; x < unhashed_appDatas.size(); x++) {
After many hours of trial and error I have determined the issue (aside from doing things in a way I should, which I've since corrected) it was something I messed up on that caused this issue.
TLDR:
Items wouldn't exist that I assumed did and tried to read files with a blank path and parse the contents that didn't exist.
Explaination:
In the first loop, the data I was getting was a list of files from a directory then parsing a json-like file that contained these file names and properties associated with them. Though, the file list contained entries that weren't in this other data file (since I had no check if they existed) so it would break there.
Additionally in the last loop I would get a member from a struct that would be the path of a file to read, but it would be blank (unset) because it didn't exist in data file so std::ifstream file(path); would break it.
I've since implemented checks for each key and value to ensure it will no longer break because of that.
Fixes:
Here are some fixes that were mentioned that I added to the code, which did help it work correctly in the end even if they weren't the main issue that I myself caused:
// Thanks to #EOF:
// No longer "using placement new on a buffer with automatic storage duration"
// (whatever that means haha) and was changed from:
char memory[sizeof(appData)];
void* p = memory;
appData *tempAppData = new(p) appData();
// To:
appData *tempAppData = new appData();
// Thanks to #Jarod42:
// Last for loop limit expression was corrected from:
for (unsigned int x = 0; x < sizeof(unhashed_appDatas); x++) {
}
// To:
for (unsigned int x = 0; x < unhashed_appDatas.size(); x++) {
}
// I am still using a map, despite comment noting to just use vectors
// (which I could have, but just would prefer using maps):
std::unordered_map<std::string, appData*> appDatas;
// Instead of doing something like this instead (would have arguably have been easier):
std::vector<std::string> dataKeys = { "1234" };
std::vector<appData*> appDatas = { ... };
auto indx = find(dataKeys.begin(), dataKeys.end(), "1234");
indx = (indx != dataKeys.end() ? indx : -1);
if (indx == -1) continue;
auto dataItem = appDatas[indx];
//
I appreciate everyone's assistance with my code

Dynamically changing the size of an array and reading in values. (w/o vectors)

Hello I am having the following difficulty,
I am trying to read in a table of doubles (1 entry per line) and store it in an array, while dynamically changing this array's size (for each line/entry). This is for a school assignment and it forbids the use of vectors(would be much easier...). The main idea that I had is to have a main array which stores the value, then store the previous values and the next one into a new array and do this iteratively. Currently, the problem that I am having is that only the last value of the table is being stored. I am aware, that somehow I need to be passing the data by refference to the global function and that the pointers that I am working with become null ater they exit the following iteration of the while. However, since the exact length of the data is unknown, this seems impossible since intializing an array in the main() is impossible (exact length not known). Any help would be appreciated.
Code posted below.
EDIT: after consideration of the two comments I made the following changes to the code, however I am not sure, whether they will behave appropriately. I added a new function called add_new_datapoint, that should globally change the values of the pointer/length and this is done by passing the values by refference. Called in the problematic else statement as add_new_datapoint(data_ptr, data_len, new_dp). Also, I am not sure that reallocating new memory to the pointer variable, will not result in a memory leak. In essence (after I reallocate data_ptr is the memory that was 'being pointed to' released or do I have to delete it and then re-inialise it in the . In such case, can I refference the pointer 'data_ptr' again in the next iteration of the loop?
I think it will be easier to simplify your posted code than trying to find all the places where you could have errors.
If you expect to see only double values in your file, you can simplify the code for reading data from the file to:
while ( data_file >> new_data_pt )
{
// Use new_data_pt
}
If you expect that there might be values other than doubles, then you can use:
while ( getline(data_file, line) )
{
std::istringstream str(line);
while ( str >> new_data_pt )
{
// Use new_data_pt
}
}
but then you have to understand the code will not read any more values from a line after it encounters an error. If your line contains
10.2 K 25.4
the code will read 10.2, encounter an error at K, and will not process 25.4.
The code to process new_data_pt is that it needs to be stored in a dynamically allocated array. I would suggest putting that in a function.
double* add_point(double* data_ptr, int data_len, double new_data_pt)
Call that function as:
data_ptr = add_point(data_ptr, data_len, new_data_pt);
Assuming the first while loop, the contents of main become:
int main()
{
std::fstream data_file{ "millikan2.dat" };
// It is possible that the file has nothing in it.
// In that case, data_len needs to be zero.
int data_len{ 0 };
// There is no need to allocate memory when there is nothing in the file.
// Allocate memory only when data_len is greater than zero.
double* data_ptr = nullptr;
double new_data_pt;
if (!data_file.good()) {
std::cerr << "Cannot open file";
return 1;
}
while ( data_file >> new_data_pt )
{
++data_len;
data_ptr = add_point(data_ptr, data_len, new_data_pt);
}
// No need of this.
// The file will be closed when the function returns.
// data_file.close();
}
add_point can be implemented as:
double* add_point(double* data_ptr, int data_len, double new_data_pt)
{
double* new_data_ptr = new double[data_len];
// This works even when data_ptr is nullptr.
// When data_ptr is null_ptr, (data_len - 1) is zero. Hence,
// the call to std::copy becomes a noop.
std::copy(data_ptr, data_ptr + (data_len - 1); new_data_ptr);
// Deallocate old memory.
if ( data_ptr != nullptr )
{
delete [] data_ptr;
}
new_data_ptr[data_len-1] = new_data_pt;
return new_data_ptr;
}
The code to track the number of bad points is a lot more complex. Unless you are required to do it, I would advise to ignore it.
You already got an excellent answer but I figured it may be helpful to point out a few mistakes in your code, so you can understand why it won't work.
In the second else scope you declare data_ptr again, even though it is visible from the outer scope. (delete[] doesn't delete the pointer itself, it just deallocates the memory the pointer points to.)
else {
double* data_temp { new double[data_len] };
std::copy(data_ptr, data_ptr + data_len - 2, data_temp);
*(data_temp + data_len - 1) = new_data_pt;
delete[] data_ptr;
double* data_ptr{ new double[data_len] }; // <- Right here
//for (int j{1}; j < data_len; j++) *(data_ptr + j) = *(data_temp + j);
std::cout << std::endl;
}
Instead you could just write data_ptr = new double[data_len]. However, that alone won't make this work.
All of your data disappears because on every iteration you create a new array, pointed to by data_temp and copy the data there, and on the next iteration you set data_temp to point to a new array again. This means that on every iteration you lose all data from previous iterations. This also causes a memory leak, since you allocate more memory every time you hit this line:
double* data_temp { new double[data_len] };
but you don't call delete[] data_temp afterwards.
I hope this helps to understand why it doesn't work.

How to copy std::vector<std::string> to GPU device with CUDA

I'm reading lines from a file, and want to perform some computation on each row by the GPU.
The problem that I'm facing is that up until now I used to copy an array of int in a constant size, now I have a vector of strings and each of them in a different size. I'm using:
std::vector<std::string> lines;
I have used a constant size to copy array. something like:
err = cudaMemcpy(_devArr, tmp, count * sizeof(unsigned int) * 8, cudaMemcpyHostToDevice);
But I'm not sure I fully get the idea how can it worked with vectors. How can I address and copy Vector of Strings? can I somehow copy it and still access it like an array with a thread+block index?
*Using the latest CUDA 10.2 and CUDA RTX 2060 graphic card
You need to flatten the strings down into a contiguous block of memory containing all the strings. My recommendation is to do it with two (total) blocks, one containing the combined string data, and one containing indexes for each of these strings.
std::string combined; //Works perfectly fine so long as it is contiguously allocated
std::vector<size_t> indexes; //You *might* be able to use int instead of size_t to save space
for(std::string const& line : lines) {
combined += line;
indexes.emplace_back(combined.size());
}
/* If 'lines' initially consisted of ["Dog", "Cat", "Tree", "Yard"], 'combined' is now
* "DogCatTreeYard", and 'indexes' is now [3, 6, 10, 14].
*/
//I'm hoping I am writing these statements correctly; I don't specifically have CUDA experience
err = cudaMemcpy(_devArr, combined.data(), combined.size(), cudaMemcpyHostToDevice);
err = cudaMemcpy(_devArr2, indexes.data(), indexes.size() * sizeof(size_t), cudaMemcpyHostToDevice);
Then, in the device itself, you'll be able to read each string as you need them. I'm unfamiliar with the syntax that CUDA employs, so I'm going to write this in OpenCL syntax instead, but the principles should cleanly and directly translate over to CUDA; someone correct me if I'm mistaken.
kernel void main_func(
global char * lines, //combined string data
global ulong * indexes, //indexes telling us the beginning and end of each string
ulong indexes_size, //number of strings being analyzed
global int * results //space to return results back to Host
) {
size_t id = get_global_id(0);//"Which String are we examining?"
if(id >= indexes_size) //Bounds Checking
return;
global char * string; //Beginning of the string
if(id == 0) //First String
string = lines;
else
string = (lines + indexes[id-1]);
global char * string_end = (lines + indexes[id]); //end of the string
for(; string != string_end; string++) {
if(*string == 'A') {
results[id] = 1; //We matched the criteria; we'll put a '1' for this string
return;
}
}
results[id] = 0; //We did not match. We'll put a '0' for this string
}
The results of this code, executed on the initial list of strings, is that for any string that contains an A, it will get a result of 1; if it does not, it gets a result of 0. The logic here should be cleanly transferable to the particular syntax that CUDA uses; let me know if it is not.

How can I find the size of a (* char) array inside of a function?

I understand how to find the size using a string type array:
char * shuffleStrings(string theStrings[])
{
int sz = 0;
while(!theStrings[sz].empty())
{
sz++;
}
sz--;
printf("sz is %d\n", sz);
char * shuffled = new char[sz];
return shuffled;
}
One of my questions in the above example also is, why do I have to decrement the size by 1 to find the true number of elements in the array?
So if the code looked like this:
char * shuffleStrings(char * theStrings[])
{
//how can I find the size??
//I tried this and got a weird continuous block of printing
int i = 0;
while(!theStrings)
{
theStrings++;
i++;
}
printf("sz is %d\n", i);
char * shuffled = new char[i];
return shuffled;
}
You should not decrement the counter to get the real size, in the fist snippet. if you have two element and one empty element, the loop will end with value , which is correct.
In the second snippet, you work on a pointer to a pointr. So the while-condition should be *theStrings (supposing that a NULL pointer ist the marker for the end of your table.
Note that in both cases, if the table would not hold the marker for the end of table, you'd risk to go out of bounds. Why not work with vector<string> ? Then you could get the size without any loop, and would not risk to go out of bounds
What you are seeing here is the "termination" character in the string or '\0'
You can see this better when you use a char* array instead of a string.
Here is an example of a size calculator that I have made.
int getSize(const char* s)
{
unsigned int i = 0;
char x = ' ';
while ((x = s[i++]) != '\0');
return i - 1;
}
As you can see, the char* is terminated with a '\0' character to indicate the end of the string. That is the character that you are counting in your algorithm and that is why you are getting the extra character.
As to your second question, seem to want to create a new array with size of all of the strings.
To do this, you could calculate the length of each string and then add them together to create a new array.

One question about element inserting in STL list

CODE:
struct Stringdata
{
// Length of data in buffer.
size_t len;
// Allocated size of buffer.
size_t alc;
// Buffer.
char data[1];
};
typedef std::list<Stringdata*> Stringdata_list;
Stringdata_list strings_;
Stringdata *psd = this->strings_.front();
//...
if (len > psd->alc - psd->len)
alc = sizeof(Stringdata) + buffer_size;
else
{
char* ret = psd->data + psd->len;
memcpy(ret, s, len - sizeof(Stringpool_char));
memset(ret + len - sizeof(Stringpool_char), 0,
sizeof(Stringpool_char));
psd->len += len;
return reinterpret_cast<const Stringpool_char*>(ret);
}
In the code sample above, I have confused about the operations in the else
branch.
Does it create a new element and insert it after the front element or
just place a new element after within the first element of list?
Your code appears to do neither. The code in the else branch does not modify the strings_ structure at all. The code is only modifying the element return from the front of the list. This should have no affect on the actual list structure.
It doesn't create a new element -- just appends data from s to the data that's already in the front element, if there's space. Very confusingly written code, though.
As far as I can tell (some important code is missing from your excerpt), you have a block of data, which is essentially an array of Stringdata object, and a list<> of pointers into that block. The else block is expanding that array.
You probably would be better off with a vector<Stringdata> rather than a list<Stringdata*>