Splitting char array into chunks quickly c++ - c++

Is there a faster/ more efficient way to split a char array into chunks (say 21 chars/ array) other than looping over the whole array?
This is my attempt right now
const char* arr = line.c_str();
char smallArr[(int)ceil((double)strlen(arr)/(double)21)][21];
int arrSisze[(int)ceil((double)strlen(arr)/(double)21)][1];
int m=0;int n=0;
for (int i=0; i<strlen(arr); i++) {
smallArr[m][i]=arr[i];
arrSisze[m][0]=(i+1)-n;
if ((i-n)==19) {
m++;
n+=20;
}
}

1) Using memcpy
char myname[] = "hello";
char dest[20] = {0};
/* using memcpy to copy string: */
memcpy ( dest, myname, 5);
2) using strncpy
char str1[]= "To be or not to be";
char str2[40];
strncpy ( str2, str1, sizeof(str2) );

Yes, pointer arithmetic and memcpy. However, seeing as you're using C++, let's stick to std::strings and assume they do a memcpy for us.
std::vector<std::string> output;
output.reserve(line.length() / 21 + (line.length() % 21) ? 1 : 0);
auto i = line.begin(), j = i + 21;
for(; line.end() - j > 21; i = j, j+= 21)
{
output.emplace(i, j)
}
if(j != line.end())
{
output.emplace(j, line.end());
}
So, what is going on here? For our purpose, it is good enough to think of a std::string as a char array and a length variable.
First, we reserve enough space for our output. You did this too.
Next, we define 2 variables i and j. i represents the beginning of the current substring and j the one-past-the-end iterator. Iterators here can be thought of as pointers into the internal structure of the string's char array - they may even be char*s!
We then iterate over the original string a line at a time. emplace just constructs a new element of a vector in the correct place. The call is equivalent to output.push_back(std::string(i, j)) and is only available in C++11.
To finish, we check whether there is another whole chunk using line.end() - j > 21; line.end() is the one-past-the-end iterator for the char array - it points at the NUL character (if there is one). If there is not a whole chunk, we check for a partial chunk using j != line.end().

Don't re-optimize the standard library.
If you have a std::string, just use it.
Don't use floating point for integer calculations: just use integer arthmetic porperly
the problem complexity is O(1). No other solution will cover it with less of one string walk span, and related copies
Use C++ properly, and forget C.
=
std::vector<std::string> chunks;
chunks.resize(21);
size_t chunksize = line.size()/21+1;
for(size_t i=0,j=0; i<line.size(); i+=chunksize, ++j)
{ chunks[j] = line.substr(i,chunksize); }
Note that sting::size takes N^0, while strlen takes N^1 complexity (it has a loop inside).
In this code, my loop is 21^1 on chunks and substr is (N/21)^1 each chunk content, giving N^1 on the whole length.
There is no need to track string length and null terminate the strings. All is handled by std::string class.

Related

why char array's size is same using sizeof()

I meet a problem with the char array size. I pass an char array into the function and after run the function, I still want to use sizeof to check the size of the array, it won't give me the new size of the array, but the old size? I would like to know why? Thank you very much!
#include<iostream>
using namespace std;
void replacement(char* arr, int len){
int count=0;
for(int i=0; i<len; i++){
if(arr[i]==' '){
count++;
}
}
int newlen=count*2+len;
//arr[newlen]='\0';
int k=newlen-1;
for(int i=len-1; i>=0; i--){
if(arr[i]!=' '){
arr[k--]=arr[i];
}
else{
arr[k--]='0';
arr[k--]='2';
arr[k--]='%';
}
}
}
int main(){
char arr[]="ab c d e g ";
cout<<sizeof(arr)<<endl;
replacement(arr, sizeof(arr));
int i=0;
while(arr[i]!=NULL) cout<<arr[i];
}
You can't change an array's size. If you want to know the length of the string in the array, use strlen() -- this counts the number of characters before the null terminator.
Even better would be to use C++ std::string class.
Right, so you are trying to replace spaces with "%20", right?
Since C++ (or C) doesn't allow an existing array to be resized, you will either need to have enough space in the first place, or use an array allocated on the heap. Then allocate a new "replacement" string in the replacement function and return that.
The proper C++ method of doing this is of course to use std::string, in which case you could just pass it in as a reference, and do the replacement in the existing variable:
void replacement(std::string* str, int len){
std::string perc20 = "%20";
std::string space = " ";
while((pos = str.find(space, pos)) != std::string::npos)
{
str.replace(pos, space.length(), perc20);
pos += perc20.length();
}
}
Much easier...
You can use sizeof() to find the size of only static arrays when the size is known at compile time. Hence it will always return the size of the array as determined at compile time.
Your program technically has Undefined Behavior because your use of sizeof returns the size in bytes of your char array. But a char implicitly contains a null byte \0. That means the for loop is iterating 1 past the length of the array.
It's recommended that you use std::string along with its size member function instead.

initialize character array on the fly

I want to initialize a char array using pointers, on the fly.That is user giving input do not know the size of array.User keeps on giving input until return is pressed.Condition here is to:
Use pointers to initialize
Not to pass size of array in advance.
Assuming a C question, how about (untested):
char *arr = malloc(10);
size_t size = 10, index = 0;
int ch;
while ((ch = getc(stdin)) != EOF && ch != '\n' && ch != '\r') {
if (index >= size) {
size *= 2;
arr = realloc(arr, size); /* XXX check it first. */
}
arr[index++] = ch;
}
arr[index] = 0;
If it's really a C++ question you want std::getline with a std::string.
The std::string has a method push_back also std::vector would do the job. Still if you are REALLY forced to use a dynamic array and char pointers I would advice you to implement reallocation strategy similar to the one used in vector - double the size each time the number of elements is more then the current size.

How to use vector<string> in OCCI setDataBuffer?

I have a simple table called mytable2 with only one column, name as varchar2(20).
I now have a list of names stored as vector of std::string to be inserted into the table.
I want to use executeArrayUpdate, so I must do the setDataBuffer first.
However, as I could see, people always use char[][20] to set databuffer.
This leaves me a big headache, since I have two issues here, first is to convert from vector to array, second is to convert the string to char.
1st, I tired to use vector of char[20], and this doesn't compile. Googled and they say that vector can't take char[], so I changed my vector of std::string to vector of char*.
2nd, I tried to turn the vector to arrray by using "void* p=&names[0]", as some people say this way we can use vectors just as array.
I used stmt->setDataBuffer(1,mystring,OCCI_SQLT_STR,20,NULL), and the program compiled and executed alright, but when I "select name from mytable2", it showed only some strange charaters.
Anyone has had a similiar issue before? what should I do?
My code is simple as below:
count=2;
vector<char*> mystring;
for(int i=0;i<count;i++)
{
char my[20];
strcpy_s(my,"Michael");
mystring.insert(mystring.end(),my);
}
stmt->setDataBuffer(1,&mystring[0],OCCI_SQLT_STR,20,NULL);
stmt->setBatchErrorMode (true);
stmt->executeArrayUpdate(count);
You'd need to dynamically create the char array you're putting into the vector for it to have a chance of working correctly.
I have not used OCCI, but if I had to use API that asked for char[][20], I would give it char[][20]
If you have your existing data in vector, why not just copy it across into the 2D char array? Eg.
// intialise vector with nonsense
unsigned int const VEC_SIZE = 2 ;
vector<string> v;
for (unsigned int i = 0; i < VEC_SIZE; ++i) {
stringstream s;
s << "Jon Paul " << i << endl;
v.push_back ( s.str() ) ;
}
// create the required 2D char array
unsigned int const STR_LEN = 20 ;
char c [VEC_SIZE][STR_LEN];
// copy the data from the vector of strings to the 2D char array
for (unsigned int i = 0; i < VEC_SIZE; ++i) {
string s = v[i].substr(0,STR_LEN);
char const * const cc = s.c_str();
unsigned int j = 0;
for (; j < STR_LEN && j < s.size(); ++j) {
c[i][j] = cc[j];
}
c[i][ j==STR_LEN ? 20 : j ] = 0; // write NULL character
}
I take it you've simplified your example to be a fixed size vector, so my response is going to be simplified to, with the thorny issue of dynamic allocation of 2D arrays left as an exercise for the reader...

Concatenate ints in an array?

As part of a homework assignment I need to concatenate certain values in an array in C++. So, for example if I have:
int v[] = {0,1,2,3,4}
I may need at some point to concatenate v[1] -> v[4] so that I get an int with the value 1234.
I got it working using stringstream, by appending the values onto the stringstream and then converting back to an integer. However, throughout the program there will eventually be about 3 million different permutations of v[] passed to my toInt() function, and the stringstream seems rather expensive (at least when dealing with that many values). it's working, but very slow and I'm trying to do whatever I can to optimize it.
Is there a more optimal way to concatenate ints in an array in C++? I've done some searching and nearly everywhere seems to just suggest using stringstream (which works, but seems to be slowing my program down a lot).
EDIT: Just clarifying, I do need the result to be an int.
Pseudo code for a simple solution:
int result = 0;
for (int i=0; i < len(v); i++)
{
result = result*10 + v[i];
}
Large arrays will bomb out due to int size overflow.
How about:
int result = (((v[1])*10+v[2])*10+v[3])*10+v[4];
If the number of elements is variable rather than a fixed number, I'm sure you can spot a pattern here that can be applied in a loop.
Remember ASCII codes?
char concat[vSize+1];
concat[vSize] = 0;
for(int i = 0; i < vSize; i++) {
concat[i] = (v[i] % 10) & 0x30;
}
All are integers. Shouldn't you do the following.
//if you want to concatenate v[1] and v[4]
int concatenated;
concatenated = v[1]*10+v[4];
//If you want to concatenate all
concatenated = 0;
for(int i=1;i<=4;i++)
concatenated = concatenated*10+v[i];
the output would be an integer ( not a string)
Things you can do:
Make sure that you compile with -O3 (Or equivalent compiler optimization).
Do you generate the values in the vector yourself? If so, try changing toInt() function to accept a simple pointer type.
Write the conversion yourself (Browser code : may not even compile - u get the idea though):
char* toInt(int* values, size_t length)
{
int *end = values + sizeof(int)*length;
int *cur = values;
char* buf = new char[length + 1]
for(char* out = buf;cur < end;++cur, ++buf)
{
*out = (char)*cur + '0';
}
*buf = '\0';
return buf;
}

String concatenation C++

Given an arbitrary floating point number, say -0.13, suppose we have an algorithm which calculates a binary string of known length L for this number, one by one, from left to right.
(I need to do this computation for calculating the Morton Key ordering for particles(co-orindates given) which in turn in used in building octrees. I am creating
such binary strings for each of x,y,z dimensions)
Is it better/efficient to first create a character array of length L, and then convert this array into a string? i.e.
char ch[L];
for(i = 0; i < L; ++i)
{
// calculation of ch[i]
}
//convert array into string
Or is it better/efficient to start of with a empty string, and then concatenate a new calculated bit into the string on the fly. i.e.
string s = "";
for(i = 0; i < L; ++i)
{
// calculation of ch[i]
s = s + string(ch);
}
Why not do both?
std::string myStr(L);
for(i = 0; i < L; ++i)
{
// calculation of ch[i]
myStr[i] = ch;
}
This creates a std::string with a given size. You then just set each character. This will only work if you can know the size beforehand exactly.
Alternatively, if you want something that is safe, even if you have to add more than L characters:
std::string myStr;
myStr.reserve(L);
for(i = 0; i < L; ++i)
{
// calculation of ch[i]
myStr.push_back(ch);
}
std::string::reserve preallocates the storage, but push_back will allocate more if needs be. If you don't go past L characters, then you will only get the one initial allocation.
Can't you just use a string with a pre-allocated length?
string s(L, '\0');
for(i = 0; i < L; ++i)
{
// calculation of ch[i]
}
I'm not sure I fully understand the conversion happening, but we have objects for a reason. If you use std::string::reserve() first, the performance should be minuscule, and it's obvious what the intent is.
string s;
s.reserve(L);
for(i = 0; i < L; ++i)
{
// calculation of ch[i]
string.push_back(ch);
}
If speed is absolutely necessary, you can instead initialize the string as length L, and bypass length checks:
string s(L,'\0');
for(i = 0; i < L; ++i)
{
// calculation of ch[i]
string[i] = ch;
}
Personally, i am probably out of date, but i use
sprintf ( char * str, const char * format, ... );
to create strings from numbers
sprintf ( outString,"%f", floatingPointNumber);
Use the latter, but also call s.reserve(L) before entering the loop. This is almost as efficient as direct array assignment, but still easier to grok.
EDIT: Other answers suggest using push_back(). Vote for them.
Sidebar: I'm not sure what you are computing, but if you just want to generate a string representation of the number, I'd suggest you simply call sprintf(), or insert the number into a std::stringstream.
If you want the C++ way, use ostringstream. This is generally cleaner code, less error-prone, and easier to read:
float f = ... // whatever you set it to
std::ostringstream s;
s << f;
std::string stringifiedfloat = s.str();
// now you have the float in a string.
Alternately, you can use the C way, sprintf. This is generally more error-prone, and harder to read, but faster performance:
float f = ... // whatever you set it to
char* buffer = new char[L];
sprintf(buffer, "%f", f);
// now you have the float in a string.
Or, you could even use boost's lexical_cast. This has better performance than ostringstream, and better readability than sprintf, but it gives you a dependency on boost:
float f = ... // whatever you set it to
std::string stringified = boost::lexical_cast<std::string>(f);
// now you have the float in a string.