Optimal way to fill std::vector<char> buffer - c++

This buffer should contain slots (three in this example) of equal length ( 20 in this example)
The buffer has to have contiguous memory so that it can be passed to a C function in non-const fashion.
const int slot_size = 20;
std::vector<char> vbuffer;
This function takes a string, copies to a temporary buffer of the required size then appeds it to vbuffer
void prepBuffer( const std::string& s)
{
std::vector<char> temp(slot_size);
std::copy(s.c_str(), s.c_str() + s.length() + 1, temp.begin());
vbuffer.insert(vbuffer.end(), temp.begin(), temp.end());
}
Testing the function
int main()
{
vbuffer.reserve(60);
prepBuffer( "Argentina");
prepBuffer( "Herzegovina");
prepBuffer( "Zambia");
cout << &vbuffer[0] << endl;
cout << &vbuffer[20] << endl;
cout << &vbuffer[40] << endl;
}
Question. There is a lot of string copying in my prepBuffer function. I am looking for a better way to fill up vbuffer with minimal copying
EDIT
The size of slots is determined elsewhere in the program. But it is not known at compile time.
EDIT
In line with my accepted answer below, I have settled on this version
void prepBuffer(const std::string& s)
{
assert(s.size() < slot_size );
vbuffer.insert(vbuffer.end(), s.begin(), s.end());
vbuffer.insert(vbuffer.end(), slot_size - s.size(), '\0' );
}
Suggestions are still welcome

How about this:
vbuffer.reserve(vbuffer.size() + 20);
vbuffer.insert(vbuffer.end(), s.begin(), s.end());
vbuffer.insert(vbuffer.end(), 20 - s.size(), '\0');
An additional check on the string length is recommended, along with a policy for handling over-long strings (e.g. assert(s.size() < 20);).

If you don't use std::string at all and avoid the temporary std::vector, you can easily do this without any extra dynamic allocation.
template <unsigned N>
void prepBuffer(char const (&s)[N])
{
std::copy(s, s + N, std::back_inserter(vbuffer));
vbuffer.resize(vbuffer.size() - N + 20);
}
Or, since the number of characters to be written is known ahead of time, you could just as easily use a nontemplate function:
void prepBuffer(char const* s)
{
unsigned n = vbuffer.size();
vbuffer.resize(n + 20);
while (*s && n != vbuffer.size())
{
vbuffer[n] = *s;
++n;
++s;
}
assert(*s == 0 && n != vbuffer.size());
// Alternatively, throw an exception or handle the error some other way
}

Another idea:
std::vector<std::array<char, 20> > prepped(3);
strncpy(prepped[0].begin(), "Argentina", 20);
strncpy(prepped[1].begin(), "Herzegovina", 20);
strncpy(prepped[2].begin(), "Zambia", 20);
You could write
typedef std::vector<std::array<char, 20> > prepped_t;
strncpy(..., ..., sizeof(prepped_t::value_type));
in case you wanted to be a bit more flexible when changing the size of the nested array

void prepBuffer( const char *s, std::size_t offset)
{
strncpy(&vbuffer[offset], s, 20);
}
Testing the function
int main()
{
vbuffer.resize(60);
prepBuffer( "Argentina", 0);
prepBuffer( "Herzegovina", 20);
prepBuffer( "Zambia", 40);
cout << &vbuffer[0] << endl;
cout << &vbuffer[20] << endl;
cout << &vbuffer[40] << endl;
}
That minimizes copying, at the cost of maintainability.
Here is nearly-optimal code that is still readable and maintainable.
std::string vbuffer;
void prepBuffer( const std::string& s)
{
vbuffer += s;
vbuffer.resize( ( (vbuffer.size() +19) / 20) * 20));
}
Testing the function
int main()
{
vbuffer.reserve(60);
prepBuffer( "Argentina");
prepBuffer( "Herzegovina");
prepBuffer( "Zambia");
cout << &vbuffer[0] << endl;
cout << &vbuffer[20] << endl;
cout << &vbuffer[40] << endl;
}

Related

how to get variable's type in template?

I want to use template function to dump data into file,
here is my code:
template<typename T> // T can be `std::unordered_map<int, std::vector<double> >` or `std::unordered_map<int, std::vector<int> >`
void write_down(const std::string & file_path, const T & week) {
std::fstream f;
f.open(file_path.c_str(), std::ios::out);
if (!f) {
printf("openfile %s failed\n", file_path.c_str());
return;
}
for (auto w : week) {
int date = w.first;
auto v = w.second;
char buffer[65536];
snprintf(buffer, sizeof(buffer), "%d\t[", date);
std::string b = buffer;
for (auto i: v) {
char buffer[65536];
snprintf(buffer, sizeof(buffer), "%.2f", i); // here is the problem, how can i identify i is int or double!!!!!!!!!!!!!!
b += buffer;
b += ",";
}
b += "]\n";
f << b;
}
f.close();
}
I have two possible input parameters type:
std::unordered_map<int, std::vector<double> > and std::unordered_map<int, std::vector<int> >
the only difference is the last element, one is double one is int.
but i need to dump them into a file, which means snprintf must know the type of this variable.
how can i identify the varibale type in this template function?
You are using a combination of filestream, string concatenation and snprintf.
You could drop the latter two and write directly to the filestream:
for (auto w : week) {
int date = w.first;
auto v = w.second;
// buffer and snprintf replaced, no need for intermediate string b:
f << date << "\t[";
for (auto i : v) {
// buffer, snprintf and string concatatenation collapsed to one line:
f << std::setprecision(2) << std::fixed << i << ',';
}
f << "]\n";
}
Here the combination of std::setprecision(2) and std::fixed is the equivalent of the format specifier %.2f, it will have no effect if i is an integer.
If you insist on snprintf, something like this should work:
snprintf(buffer, sizeof(buffer),
std::is_same_v<decltype(i), int> ? "%d" : "%.2f", i);

How to duplicate strncat (original)

My stringNAdd function will duplicate strncat (original). I cannot accept arrays as parameters, but pointers. I wonder if my code right?
Here is the fixed code:
#include <string>
#include <iostream>
using namespace std;
char *stringNAdd(char str1[], char str2[],size_t num);
int main()
{
char dest[50] = "Using strncat function,";
char src[50] = " this part is added and this is ignored";
cout<< strncat(dest, src, 20) << endl;
cout << stringNAdd(dest, src, 20) << endl;
cin.get();
return 0;
}
char *stringNAdd(char str1[], char str2[],size_t num){
size_t str1_len = strlen(str1);
size_t i;
for (i=0; i < num && str2[i] != '\0'; i++)
i==num;
str1[str1_len+i] = str2[i];
str1[str1_len+i] = '\0';
return str1;
}
Output:
Using strncat function, this part is added
Using strncat function, this part is added
The problem is that you don't do the test of both functions in the same conditions: once you've executed strncat(), the dest already contains the longer concatenated version.
The second problem is that dest was already enlarged by 15 chars. It has therefore an initial length of 38 chars + the null terminator before calling stringNAdd(). Adding 15 more chars result in a string of 53 chars plus a null terminator, which is 4 chars longer than your array. So you'll get a buffer overflow, hence memory corruption and undefined behavior.
But all this is related to the testing conditions: your clone works fine.
Suggestions:
Run your functions in distinct blocks, and define your testing variables local to that block:
{
char dest[50] = "Using strncat function,";
char src[50] = " this part is added and this is ignored";
cout<< strncat(dest, src, 15) << endl;
cout << strlen(dest)<<endl;
}
{
char dest[50] = "Using strncat function,";
char src[50] = " this part is added and this is ignored";
cout << stringNAdd(dest, src, 15) << endl;
}
Think of a more secure version of your function, in which you would have an additional argument with the total length of the destination array to prevent these errors. This would increase the security of your code. By the way, this is what Microsoft does with strncat_s().
Finally, you could ask your teacher why he/she still lets you work with cstrings, when there are the so much more convenient and secure std::string, and that he certainly could find more modern exercises with the same pedagogical benefits.
Here is equivalent based on https://opensource.apple.com/source/Libc/Libc-167/gen.subproj/i386.subproj/strncat.c
#include <iostream>
char *strnadd(char *dst, const char *src, size_t n)
{
// abort if source is empty
if (n != 0)
{
// copy pointers
char *d = dst;
const char *s = src;
// find end of destination str
while (*d != 0)
d++;
// start copying chars from source str to the end of destination str
// until either source string ends or number of chars copied
// destination string has to be long enough to accommodate source
do
{
if ((*d = *s++) == 0)
break;
d++;
}
while (--n != 0);
// add null termination
*d = 0;
}
// return the resulting string
return dst;
}
int main()
{
char strCat[50];
char strAdd[50];
strcpy(strCat, "string1");
strcpy(strAdd, "string1");
char const *str2 = "string2";
std::cout << strncat(strCat, str2, 6) << std::endl;
std::cout << strnadd(strAdd, str2, 6) << std::endl;
return 0;
}
Prints:
string1string
string1string

C++: get number of characters printed when using ofstream

The C fprintf() function returns the number of characters printed. Is there similar functionality in C++ when writing to a file with ofstream? I am interested in a solution that is compatible with C++03 if possible.
For example:
ofstream file("outputFile");
file << "hello";
// Here would I like to know that five characters were printed.
file << " world";
// Here I would like to know that six characters were printed.
What you're looking for is tellp().
You could use it like so:
ofstream file("outputFile");
auto pos1 = file.tellp();
file << "hello";
auto pos2 = file.tellp();
std::cout << pos2 - pos1 << std::endl;
Seek operations are rather expensive (primarily because they need to prepare streams to potentially switch between reading and writing). I'd personally rather use a filtering stream buffer which provides the counts, e.g.:
class countbuf: public std::streambuf {
std::streambuf* sbuf;
std::size_t count;
char buffer[256];
int overflow(int c) {
if (c != std::char_traits<char>::eof()) {
*this->pptr() = c;
this->pbump(1);
}
return this->sync() == -1
? std::char_traits<char>::eof()
: std::char_traits<char>::not_eof(c);
}
int sync() {
std::size_t size(this->pptr() - this->pbase());
this->count += size;
this->setp(this->buffer, this->buffer + 256);
return size == this->sbuf->sputn(this->pbase(), this->pptr() - this->pbase())
? this->sbuf->pubsync(): -1;
}
public:
countbuf(std::streambuf* sbuf): sbuf(sbuf), count() {
this->setp(buffer, buffer + 256);
}
std::size_t count() const { return count + this->pptr() - this->pbase(); }
std::size_t reset() const {
std::size_t rc(this->count());
this->sync();
this->count = 0;
return rc;
}
};
Once you got this stream buffer, you could just install into an std::ostream (and possibly package the construction into a custom stream class):
countbuf sbuf(std::cout.rdbuf()); // can't seek on this stream anyway...
std::ostream out(&sbuf);
out << "hello!\n" << std::flush;
std::cout << "count=" << out.reset() << '\n';

What is the correct way to assign an const unsigned char* data into an array

I have the following code :
sqlite *sql = new sqlite; // create a new sqlite object.
const char *dbFile = "database.db"; // sqlite database file.
sql->open(dbFile); // open the connection.
sql->query("SELECT * FROM categories"); // make a query.
int numRows = sql->numRows(); // get the number of rows.
const unsigned char *result[numRows]; // an array to store data that will be brought in from the database.
int index = 0; // counter
while(sql->fetch() != SQLITE_DONE){
// store the data into an array
result[index] = sql->getValue("name");
index++;
// print the data directly without storing in an array
cout << sql->getValue("name") << endl;
}
sql->close();
// print the content of the `result` array.
for(int i=0;i<numRows;i++){
cout << result[i] << endl;
}
The result:
Notice:
The method sql->getValue("name"); return const unsigned char* data.
As you seen in the result image, why when print the data directly, appear without problems, while when print the same data stored in the array does not appear ?
The solution
Firstly: I thank everyone who contributed(by comment or answer) to helping me to reach to a solution for my problem.
their answers really deserve the best answer.
sqlite *sql = new sqlite;
const char *dbFile = "database.db";
sql->open(dbFile);
sql->query("SELECT * FROM categories");
int numRows = sql->numRows();
char **result = (char**)malloc(sizeof(char*) * numRows);
int index = 0;
while(sql->fetch() != SQLITE_DONE){
result[index] = (char*)malloc(sizeof(char*) * CHAR_MAX);
strcpy(result[index], reinterpret_cast<const char*> (sql->getValue("name")));
index++;
cout << sql->getValue("name") << endl;
}
cout << "\n\n" << endl;
sql->close();
for(int i=0;i<numRows;i++){
cout << *(result+i) << endl;
}
The result:
I have recently started looking at Sqlite myself so I happen to have some code I knocked up that I have extracted to give as an exampe. This is not supposed to be particularly performant just to get the job done.
It also includes code to get the SQL REGEXP function working.
The idea is to add elements to a data structure during the select callback. The data structure is a std::vector of std::map. The std::map being the table's colum data mapped from the column names and the std::vector containing the rows of columns:
#include <map>
#include <regex>
#include <string>
#include <vector>
#include <iterator>
#include <iostream>
#include <sqlite3.h>
typedef std::map<std::string, std::string> result;
typedef std::vector<result> result_vec;
#define log(msg) std::cout << msg << std::endl
static int select_callback(void* user, int argc, char** argv, char** azColName)
{
result_vec& v = *static_cast<result_vec*>(user);
result r;
for(int i = 0; i < argc; ++i)
if(argv[i])
r.emplace(azColName[i], argv[i]);
v.emplace_back(std::move(r));
return 0;
}
static void regexp_callback(sqlite3_context* context, int argc,
sqlite3_value** argv)
{
unsigned count = 0;
if(argc == 2)
{
const char* pattern = (const char*) sqlite3_value_text(argv[0]);
const char* value = (const char*) sqlite3_value_text(argv[1]);
if(pattern && value)
{
std::string s = value;
std::regex r(pattern, std::regex::icase);
std::smatch m;
if(std::regex_search(s, m, r))
count = m.size();
}
}
sqlite3_result_int(context, (int) count);
}
sqlite3* open(const std::string& name)
{
sqlite3* db;
if(sqlite3_open(name.c_str(), &db) != SQLITE_OK)
{
log("ERROR: opening db: " << name);
log("ERROR: " << sqlite3_errmsg(db));
return nullptr;
}
sqlite3_create_function_v2(db, "REGEXP", 2, SQLITE_ANY, 0, regexp_callback, NULL, NULL, NULL);
return db;
}
bool select(sqlite3* db, const std::string& sql, result_vec& v)
{
char* error = 0;
if(sqlite3_exec(db, sql.c_str(), select_callback, &v, &error) != SQLITE_OK)
{
log("ERROR: " << error);
log("ERROR: " << sqlite3_errmsg(db));
log(" SQL: " << sql);
sqlite3_free(error);
return false;
}
return true;
}
int main()
{
sqlite3* db = open("mydatabase.db");
if(db)
{
result_vec results;
if(!select(db, "select * from mytable", results))
return 1;
for(auto&& row: results)
for(auto&& col: row)
std::cout << col.first << ": " << col.second << '\n';
}
}
NOTE: I just read that you are not looking to use std::vector or C++11 features so this answer is not what you are looking for (although it may still be of use to you). However I will leave it for other people who may google this question.
Your problem is that you're assigning a pointer rather than copying the string. This is an important distinction.
Assigning the pointer doesn't "store the data" as your comment suggests, it simply copies the pointer. SQLite discards the data after it's done with the record, so its buffers are free to use with another record. By the time you go to print out the string, the pointer is no longer valid.
In order to retain the string for later printing you'll need to copy the string to your own buffer.
This means you'll need to allocate buffer space for the string, copy the string, and then free the space when you're done with it.
It sounds like you want to avoid using C++ features, so you'll want to look at malloc(), free(), and strncpy() to accomplish your task. Otherwise, if you wanted to use the C++ STL String class, that would solve your problem nicely.
Okay, replace this original code:
const unsigned char *result[numRows]; // an array to store data that will be brought in from the database.
int index = 0; // counter
while(sql->fetch() != SQLITE_DONE){
// store the data into an array
result[index] = sql->getValue("name");
index++;
}
with this:
#include <string>
#include <vector>
using std::string; using std::vector;
⋮
vector<string> result;
while( sql->fetch() != SQLITE_DONE )
{
result.emplace_back( reinterpret_cast<const char*>(
sql->getValue("name")
) );
}
And also replace the printf with cout <<, or else, in the printf call replace result[i] with result[i].c_str().
All assuming that the original code works.
Disclaimer: code not touched by compiler.
Addendum:
You most recent code-that-doesn't-compile,
const unsigned char **result = (const unsigned char**)malloc(sizeof(const unsigned char*) * numRows);
int index = 0;
while(sql->fetch() != SQLITE_DONE){
result[index] = (const unsigned char*)malloc(sizeof(const unsigned char*) * CHAR_MAX);
strcpy(result[index], sql->getValue("name"));
index++;
cout << sql->getValue("name") << endl;
}
… can be expressed in C-style C++ as
char** result = new char*[numRows]();
int index = 0;
while( sql->fetch() != SQLITE_DONE )
{
assert( index < numRows );
char const* const s = reinterpret_cast<char*>( sql->getValue( "name" ) );
result[index] = new char[1 + strlen( s )];
strcpy( result[index], s );
cout << s << endl;
++index;
}
Again assuming that the original code worked.
Disclaimer: Again, the code has not been touched by a compiler. Also, readers should note that using new directly, while that improves on using malloc, is ungood practice. Good practice would be to use std::vector and std::string, as I advised first of all.

C++ Deque implementation with character arrays

So I'm writing a program that takes in a string of characters in a command line statement, and breaks up the word into two or three pieces (2 for even, first half and second half, 3 for odd, first "half", middle letter, and second "half), and reverses the characters of the first and second halves and re concatenates the characters into a single string htat is outputted. It gets a little uglier than that, as I have to use a deque and use push and pop functions to move around the characters. So I have a few problems I don't really understand. First off, the ABottom integer for some reason is blowing up to outrageously large values, which makes no sense as it is supposed to stay fixed at 0. Secondly, when I pop from A, I get an empty string, and when I pop from B, it alternates every other character from the deque. But the loops in the .h file that put the characters in the deque seems to be working exactly as I anticipated. Any suggestions about the ABottom, or why the pops aren't working?
File 1:
// Kevin Shaffer TwoStackKAS.h
#include<iostream>
#include<string>
#include<vector>
#ifndef TWOSTACKKAS_H_
#define TWOSTACKKAS_H_
using namespace std;
class TwoStacks {
char elements[];
int Abottom, Bbottom;
int AtopSpace, BtopSpace;
int totalSize;
public:
TwoStacks(int maxAdds) {
totalSize = 2*maxAdds +1;
char elements[totalSize];
const int Bbottom = totalSize-1; //bottom for both stacks!
const int Abottom = 0;
AtopSpace= 0;
BtopSpace = totalSize-1; //top for both stacks!
cout<<"Stack Size: "<<totalSize<<endl;
}
virtual bool empty() const {
return Abottom == AtopSpace && Bbottom==BtopSpace;
}
virtual bool full() const { return AtopSpace==BtopSpace;}
virtual int stackSize() {
cout<<Abottom<<" Abottom"<<endl;
return (AtopSpace - Abottom +Bbottom -BtopSpace);
}
virtual char popA() {
if (empty()){
cerr << "Attempting to pop Empty stack!"<< endl;
return ' '; //prepare EmptyQexceptiin
} else {
cout << elements[--AtopSpace] << " testpopA"<< endl;
return elements[--AtopSpace];
}
}
virtual char popB() {
if (empty()){ //later EmptyQException
cerr <<"Attempting to pop an empty stack!" << endl;
return ' ';
} else {
//cout <<elements->at(++BtopSpace) << endl;
cout << elements[++BtopSpace] << " test"<< endl;
return elements[++BtopSpace];
}
}
virtual void pushB(char newItem){
elements[BtopSpace--] = newItem;
}
virtual void pushA(char newItem){
elements[AtopSpace++] = newItem;
}
virtual string toString() const {
string out = "";
for (int i = 0 ; i<=Bbottom; i++) {
out += elements[i];}
return out;
}
};
#endif
And file 2:
/** Kevin Shaffer
* Given an input string, reverse each half of the string;
* pivot on the middle element if it exists.
* uses double ended stack in twoStackKAS.h*/
#include<string>
#include "TwoStackKAS.h"
#include<iostream>
#include<string>
using namespace std;
int main (int argc, char* argv[]){
if (argc<=1){return 0;}
string word = argv[1];
int length = word.size(); // gets length of word
int half = length/2;
TwoStacks* sd = new TwoStacks(length/2);
//cout<<sd->stackSize()<<endl;
for(int i = 0; i < length/2; i++){
sd->pushA(word[i]);
cout << word[i] << endl;
}
for(int i = length; i >= length/2; i--){ //Second half of word
sd->pushB(word[i] ); //has been pushed
cout << word[i] << endl; //in reverse order.
}
//cout << word << endl;
//Recombine word
if(length%2==1){ word = word[length/2];}
else{ word = "";}
cout<<sd->stackSize()<<endl;
string leftHalf; string rightHalf;
string myWord; //new word (shuffled)
for(int i=0; i< half; i++) {
leftHalf += sd->popA();
rightHalf += sd->popB();
}
//cout<<"Stack: "<<sd->toString()<<endl;
cout << rightHalf << endl;
cout << leftHalf << endl;
myWord = leftHalf + word + rightHalf;
cout<<myWord<<endl;
return 0;
}
ABottom is not growing... it is never initialized!
Look at your constructor. You're not assigning Abottom, but you're defining a new variable that masks the member variable. You do that multiple times.
And as VS2015 actually did not accept char elements[]; : "Incomplete type is not allowed", it's probably better it use std::string instead of char*
A better constructor would be something like.
class TwoStacks
{
private:
// totalSize has to be assigned before assigning dependent variables
int totalSize;
string elements;
int Abottom, Bbottom;
int AtopSpace, BtopSpace;
public:
TwoStacks(int maxAdds)
: totalSize(2 * maxAdds + 1)
, elements(totalSize, ' ')
, Abottom(0)
, Bbottom(totalSize - 1)
, AtopSpace(0)
, BtopSpace(totalSize - 1)
{
// preferably don't cout in a constructor
cout << "Stack Size: " << totalSize << endl;
}