Concatenating strings in Visual Studio C++ 6.0 in a loop - c++

Can you help me optimize this block of code in C++ for Visual Studio C++ 6.0:
char output[10000] = "";
for (int i = 0; i < cnt; i++) {
char row[150];
_snprintf(row, 149, "…", …);
row[149] = '\0';
strcat(output, row);
}
return _snprintf(buffer, size-1, "%s\r\nend\r\n", output);
What I need is that I do not specify size of output[] but increase it dynamically. The same maybe true for row[]. Sorry I'm novice in C++.
Thanks for any help.

In C++, you ought to use std::string for strings instead of char arrays, and std::stringstream and its cousins std::istringstream and std::ostringstream instead of sprintf() or snprintf() for formatting in string buffers. Here’s the basis of a C++ solution:
std::ostringstream result;
for (int i = 0; i < cnt; ++i) {
result << "...\n";
}
result << "end\n";
return result.str();
The std::string class handles all of the details of managing memory, and std::stringstream uses std::string internally.

std::stringstream coupled with operator << works like a charm.

I think the use of C++ containers given as answers are not as optimized as you can get. There has been no memory reserved to begin with, and the results do not copy into the buffer as in your supplied code.
You can still do better like this:
char suffix[] = "\r\nend\r\n";
int suffix_len = strlen(suffix);
char *buf_end = buffer + size - suffix_len - 1;
char *buf_begin = buffer;
for (int i = 0; i < cnt; i++) {
int nchars = _snprintf(buf_begin, buf_end-buf_begin, "…", …);
if( nchars >= 0 ) {
buf_begin += nchars;
} else {
// You may want to set an overflow flag here.
buf_begin = buf_end;
break;
}
}
// There will always be enough room in the buffer to store the suffix, so
// this will null-terminate even if the above loop overflowed the buffer.
_sprintf(buf_begin, "%s", suffix);
I've modified this to write directly into buffer instead of output. It utilizes the fact that the _sprintf family returns the number of characters written (or negative if max chars written). To me, this is the preferable way to concatenate data into a buffer, even in C++.

If you are using MFC, it is very easy using the CString class:
// loop count
int nCount = 100;
CString strOutput, strOne;
for (int i=0 ; i<nCount ; i++)
{ // format one line
strOne.Format(_T("..."), ...);
// accumulate the result
strOutput += strOne;
}
return strOutput;

Related

C++. How can I free memory correctly?

Written code to find and remove the largest word in a string without the using of library functions. Everything works fine. But when I want to free memory, the result is negative (displays an empty line). If you remove the call to the memory release function, everything will work correctly, but there will be a leak of memory.
How do I fix it? Please help me.
#include <iostream>
using namespace std;
int length(char *text) // string length
{
char *begin = text;
while(*text++);
return text - begin - 1;
}
int size(char **text) // size of two-dimensional array
{
int i = 0;
while(text[i]) i++;
return i;
}
void free_memory(char **text)
{
for(int i=0; i<size(text); i++)
delete text[i];
delete [] text;
}
char **split(char *text, char delim)
{
int words = 1;
int len = length(text);
for(int i=0; i<len; i++)
if(text[i] == delim) words++;
char **result = new char*[words + 1];
int j = 0, t = 0;
for(int i=0; i<words; i++)
{
result[i] = new char[len];
while(text[j] != delim && text[j] != '\0') result[i][t++] = text[j++];
j++;
t = 0;
}
result[words + 1] = nullptr;
return result;
}
char *strcat(char *source, char *destination)
{
char *begin = destination;
while(*destination) destination++;
*destination++ = ' ';
while(*source) *destination++ = *source++;
return begin;
}
char *removeWord(char *in_string)
{
char **words = split(in_string, ' ');
int max = length(words[0]);
int j = 0;
for(int i=0; i<size(words); i++)
if(max < length(words[i]))
{
max = length(words[i]);
j = i;
}
int index;
char *result;
if(!j) index = 1;
else index = 0;
result = words[index];
for(int i=0; i<size(words); i++)
if(i != j && i != index)
result = strcat(words[i], result);
free_memory(words); // I want free memory here
return result;
}
int main()
{
char text[] = "audi and volkswagen are the best car";
cout << removeWord(text) << endl;
return 0;
}
In fact, this is C style programming - not C++. I see that your aim is to implement everything from scratch, possibly for practicing. But even then, your code is not designed/structured properly.
Besides that, you also have several bugs in your code:
result[words + 1] = nullptr; must be result[words] = nullptr;
You need result[i][t] = '\0'; after the while loop in split
delete text[i] must be delete [] text[i]
You cannot assign to your result pointer memory from words, then free it and then return it for use by the caller.
There is at least one further bug in the second half of removeWord. It would be tedious to try to understand what you are trying to do there.
You might want to start with a simpler task. You also should proceed step-by-step and check each function for correctness independently first and not implement everything and then test. Also take a look at the tool valgrind for memory checking - if you use Linux.
The way you free memory correctly is to use RAII:
Only use new and new[] in constructors
Pair those with delete and delete[] in the corresponding destructor
Use automatic storage duration objects as much as possible
If you are specifically not using std::string and std::vector etc, for reasons of learning pointers, you will end up writing some small number of classes that resemble string and vector and unique_ptr, and then you go about programming as if you were using the std versions.
You have two issues. First is that result is assigned to a memory location in words. Second, is that you're storing the result of strcat in words[i] which will likely not have enough room (see strcat documentation).
result = new char[len(in_string)+1]; // +1 for space for null char
// the old loop reversed the word order -- if you want to keep doing
// that, make this a descending loop
for(int i=0; i<size(words); i++)
if(i != j && i != index)
strcat(result, words[i]);
free_memory(words);
return result;
So that when you free words, what result points to is also free'd. You would then need to free your result in main().
int main()
{
char text[] = "audi and volkswagen are the best car";
char * result = removeWord(text);
cout << result << endl;
delete[] result;
return 0;
}

Convert string vector to buffer

I have a string vector which contains some number of strings greater than 500. I am using openssl functions that require buffers for encryption/decryption. Given that I am using string vectors and buffers in this manner, what is the best algorithm in terms of space and time to make this conversion. Each string can be assumed to be less than 200 chars.
Currently, I am extracting each entry in paths, concatenating the strings, calling the .c_str() method and using strcpy to extract from a function.
void copy(vector<string>& paths, unsigned char** plainTextBuffer, size_t& p_len){
int size = paths.size();
int i = 0;
string temp = "";
for(i=0; i<size; i++){
temp+= paths[i];
temp+= "\n";
}
p_len = temp.length();
(*plainTextBuffer) = malloc(p_len + 1);
strcpy((*plainTextBuffer), temp.c_str());
return;
}
Are there any built in tools to do this better and faster? (I have excluded error checking and casting from this snippet)
Edit:
I added the +1 to the malloc. I asked for a minimum complexity manner of getting from the initial conditions to the expected output. I am using malloc because I am using a simple buffer and it is faster than new.
Edit 2:
Thanks to some of the comments I am cutting out the middleman with some of the copying and have the following
void copy(vector<string>& paths, unsigned char** plainTextBuffer, size_t& p_len){
int size = paths.size(), total = 0, i = 0;
for(i=0; i<size; i++){
total+= paths[i].size() + 1;
}
p_len = total;
(*plainTextBuffer) = malloc(p_len + 1);
(*plainTextBuffer)[0] = '\0';
for(i=0; i<size; i++){
strcat((*plainTextBuffer), paths[i].c_str());
strcat((*plainTextBuffer, "\n");
}
return;
}
Again I left out some casting. Is there a more efficient manner of getting the buffer data into the plainTextBuffer?
The fastest way to convert a string to a C-style string is to not do any conversions. So first, let's convert our std::vector<std::string> into one std::string:
std::vector<std::string> v = ...;
std::string output;
for (auto& s : v) {
output += s;
output += '\n';
}
And then you can pass that in:
void some_c_api(char*, size_t );
void some_const_c_api(const char*, size_t);
some_c_api(&output[0], output.size());
some_const_c_api(output.c_str(), output.size());
Appending repeatedly into a string will result in the string repeatedly reallocating memory and shuffling its content into the new bigger space. A stringstream has a bigger creation cost, but it appends much faster than std::string, so instead of appending to a string in a loop, append to a stringstream:
stringstream temp;
for(size_t i=0; i<paths.size(); i++){
temp << paths[i] << endl;
}
const std::string& tmp = temp.str();
Then just use tmp like you would have used your previous temp string. It is better to get a constant reference to temp.str() because it will not copy the content of the temporary created by str().

C++ using execvp with string array

I'm writing a program to execute Unix commands with any amount of arguments. I have no problem receiving input and making tokens as I use regular strings. However, execvp will only accept an array of pointers and I'm not sure how to go about converting the array of strings to this. Here's what I have:
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>
#include <unistd.h>
int main()
{
while (true)
{
int argc = 0;
std::istringstream iss;
std::string command;
std::cout << "$> ";
getline(std::cin, command);
iss.str(command);
for (unsigned i = 0; i <= command.length(); i++)
{
if (command[i] == ' ' || command[i] == '\0')
{
argc++;
}
}
std::string arr[argc+1];
for (int i = 0; i < argc; i++)
{
iss >> arr[i];
}
if (arr[0].compare("quit"))
{
break;
}
else
{
char*argv[argc+1];
for (int i = 0; i < argc; i++)
{
argv[i] = arr[i].c_str(); //This line is wrong
}
argv[argc] = NULL;
execvp(argv[0], argv);
}
}
return 0;
}
I've tried various methods and can't figure out how to convert a string to a char array in the proper manner. Methods like strcpy won't work because the length of each argument will vary. Any help would be greatly appreciated.
You have very small mistakes.
Replace:
argv[i] = arr[i].c_str(); with argv[i] = const_cast<char*>(arr[i].c_str());
if(arr[0].compare("quit")) with if(!arr[0].compare("quit"))
And you are good to go, and this would work in any compiler.
Run here
But I have some advice to make it using fork so it won't run only one command at a time.
Example here
Your problem is that your array is holding char*, while std::string::c_str() returns const char*. It can't be stored in your array, because it would lose const-ness.
If you're using a C++11 compliant compiler, you can use &arr[i][0] to obtain a non-const pointer to the internal string buffer.
If you aren't using a C++11 compliant compiler, the internal buffer may not be null-terminated, so your only option is to use new or malloc to allocate correctly sized buffers, then strcpy the strings into them.
char* buffer = new char[arr[i].length() + 1];
strcpy(buffer, arr[i].c_str());
argv[i] = buffer;
You can ensure null terminator at the end of each string in the array this way:
for (int i = 0; i < argc; i++)
{
iss >> arr[i];
arr[i].push_back('\0');
}
Then you can simply capture pointer to the first character of each string. Clean and safe, without any const_cast:
for (int i = 0; i < argc; i++)
{
argv[i] = &arr[i][0];
}

Get string content from string pointer C++

so I'm working on a project that I have to read contents from a file and then analyze them. But I'm having a problem with getting the string out of a pointer that contains the address to what I need.
string lePapel(vector<char> vec){
string *str, s;
int i, j = 0;
vector<char> aux;
aux.resize(6);
for (i = 57; i <= 62; i++){
aux[j] = vec[i];
j++;
}
str = new string[aux.size()];
for (i = 0; i < 6; i++){ str[i] = aux[i]; }
return s;
}
So, the file contains in the array positions from 57 to 62 the word: ABCB4, but when returning the string s my output is A only as expected because of the pointer.
The thing is that I have been trying to find a solution and storing the whole content from vec[57] to vec[64] into the string s and returning it, and the closest that I got to returning anything plausible was using a pointer.
So, now to my question, how can I iterate the *str pointer and copy the whole content to s and return it?
Thanks in advance
I'd suggest you to not use pointers on string in your case. The following code is probably what you want :
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string lePapel(vector<char> vec){
int j = 0;
vector<char> aux;
aux.resize(6);
for (int i = 57; i <= 62; i++){
aux[j] = vec[j];
j++;
}
string str;
str.reserve(6);
for (int i = 0; i < 6; i++){ str.push_back(aux[i]); }
return str;
}
int main() {
char x[5] = {'A', 'B', 'C', 'B', '4'};
vector<char> vec(x, x + 5);
string s = lePapel(vec);
cout << s;
return 0;
}
Tested here : Tested code
About reserving space to your vector : c++ vector::reserve
Same for strings : reserve for strings
The dynamic array of string objects and the whole aux vector seem completely needless here (unless there's some other purpose for them in your code). Additionally, str is currently causing a memory leak because you never delete it when you're finished.
A much simpler approach is just to append the characters one-at-a-time to the s string object (assuming it's a std::string):
string lePapel(vector<char> vec) {
string s;
for (int i = 57; i <= 62; i++) {
s += vec[i];
}
return s;
}
There are various ways to make the code even shorter (and more efficient) than that though, if you really want to.
EDIT: If you still need/want to iterate your dynamic array and concatenate the contents into s, here's how you could do it:
for (i = 0; i < 6; i++) s += str[i];
delete [] str; //<-- very important!
Short answer, you don't want a string * you want a char *. What you created is a string array. String objects contain a pointer to the char * data you are trying to capture. Also, the sizeof(std::string) (8 bytes in size) is a lot bigger than sizeof(char) (1 byte in size) the second character you store is 8 bytes away from the first character instead of being adjacent.
There are a lot of other C++ style and safety concerns, but I'll stick with the question. ;)

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.