Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I prefer char* instead std::string, so I wrote a function combining char pointers. I created a new project and tested it. It works fine. But when I try to use it in some larger GUI project, my program crashes.
Here's an example (working) code:
#include <Windows.h>
#include <vector>
char *StringJoin(const char *String, const char* ...)
{
va_list ArgList;
va_start(ArgList, String);
std::vector<const char *> StringData;
std::vector<unsigned int> StringLen;
StringData.push_back(String);
unsigned int SingleLength = strlen(String);
StringLen.push_back(SingleLength);
unsigned int TotalLength = SingleLength;
while (1)
{
const char* Val = va_arg(ArgList, const char*);
if (!Val)
break;
StringData.push_back(Val);
SingleLength = strlen(Val);
StringLen.push_back(SingleLength); // In larger projects it crashes here
TotalLength += SingleLength;
}
va_end(ArgList);
char *NewString = new char[TotalLength + 1];
unsigned int VectorSize = StringData.size();
unsigned int NewLength = 0;
for (unsigned int Element = 0; Element < VectorSize; Element++)
{
memcpy(NewString + NewLength, StringData[Element], StringLen[Element]);
NewLength += StringLen[Element];
}
NewString[TotalLength] = '\0';
StringData.clear();
StringLen.clear();
return NewString;
}
int main(void)
{
char* New = StringJoin("Does ", "it ", "works ", "for ", "you ", "?");
printf("%s\n", New);
system("PAUSE");
return 1;
}
Is my code safe and stable?
You can't use the !Val condition:
const char* Val = va_arg(ArgList, const char*);
if (!Val)
break;
When using variable argument list you need to know exactly how many arguments have been passed, or (update) when to stop processing the arguments, using e.g. NULL / nullptr (or any other) sentinel.
You definitely should use variadic templates if your compiler supports it.
The following quite simple function takes an arbitrary number of strings and concatenates it in a loop. It supports both std::string and char* for the arguments (and even mixed):
template<class ...Strings>
std::string StringJoin(Strings ...strings) {
std::string joined;
for (auto s : { strings... })
joined += s;
return joined;
}
Live Demo
Now if you want the result to be a char*, you need to think about where you allocate the memory and where you deallocate it, i.e. you need to manually manage memory. Unless you use smart pointers:
template<class ...Strings>
std::unique_ptr<char[]> StringJoin(Strings ...strings) {
std::string joined;
for (auto s : { strings... })
joined += s;
std::unique_ptr<char[]> buf(new char[joined.size() + 1]);
memcpy(buf.get(), joined.data(), joined.size());
buf[joined.size()] = '\0';
return buf;
}
Live Demo
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 28 days ago.
Improve this question
The following code outputs the correct string in the parameters function, but the incorrect string in main.
Obviously something is going wrong, but I can't see what it is. Thanks.
#include <iostream>
#include <string>
using namespace std;
typedef struct sim {
const char* dir;
} sim;
string convertToString(char* a)
{
string s(a);
return s;
}
int parameters(sim *sdata, char **argv, int argc){
char *filename;
string token;
string delimiter = "=";
size_t pos = 0;
string s;
for (int i = 0; i < argc; ++i){
s = convertToString(argv[i]);
while ((pos = s.find(delimiter)) != string::npos) {
token = s.substr(0, pos);
s.erase(0, pos + delimiter.length());
}
if(token == "-dir"){
sdata->dir = s.c_str();
cout << sdata->dir << endl;
}
}
}
int main(int argc, char** argv) {
sim * sdata = (sim*)malloc(sizeof(sim));
parameters(sdata, argv, argc);
cout << sdata->dir << endl;
free(sdata);
return 0;
}
I started the program with ./teststring -dir=/home/stephen and got:
/home/stephen
�a
I was expecting both outputs to be the same.
The program has undefined behavior.
The pointer sdata->dir will be invalid after exiting the function parameters because the object s will not be alive. It has only the block scope of the function.
Also use the operators new and delete instead of calling the C function malloc. So write
sim * sdata = new sim;
You could write within the function for example like
if ( token == "-dir" )
{
sdata->dir = new char[s.length() + 1 ];
strcpy( sdata->dir, s.c_str() );
cout << sdata->dir << endl;
}
else
{
sdata->dir = nullptr;
}
provided that the data member dir is declared without the qualifier const.
typedef struct sim {
char* dir;
} sim;
Also using the typedef specifier in the structure declaration is redundant in C++.
So in main you will need to write
delete [] sdata->dir;
delete sdata;
I have a function in my code called buildPacket that takes some parameters, and converts them into a char* and adds them together using a std::vector<char> and at the end returns the result as a char*. The problem is that after I convert the vector to a char* all characters become a weird character.
I tried using other ways of converting the vector to a char*, like with using reinterpret_cast<char*>. When I print the contents of the vector from inside the function, I get the expected result so the problem is with the conversion.
The function's code:
char* buildPacket (int code, std::string data)
{
char* codeBytes = CAST_TO_BYTES(code);
std::vector<char> packetBytes(codeBytes, codeBytes + sizeof(char));
size_t dataLength = data.size() + 1;
char* dataLengthBytes = CAST_TO_BYTES(dataLength);
packetBytes.insert(packetBytes.end(), dataLengthBytes, dataLengthBytes + sizeof(int));
const char* dataBytes = data.c_str();
packetBytes.insert(packetBytes.end(), dataBytes, dataBytes + dataLength);
return &packetBytes[0];
}
The CAST_TO_BYTES macro:
#define CAST_TO_BYTES(OBJ) static_cast<char*>(static_cast<void*>(&OBJ));
The intent of the function is to take the input and build a packet out of it to send through a socket later on, the packet's format consists of a 1-byte long code, 4-byte long data length and data with variable length.
The input I gave it is code = 101 and data = "{\"password\":\"123456\",\"username\":\"test\"}"
This is the result I am getting when printing the characters: ▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌
EDIT: Thanks for all the help, I've returned a vector<char> at the end as suggested and took a different approach in converting to values to a char*.
You're returning a pointer to something inside of a local variable. You should change your code to have your vector<char> alive outside of your buildPacket function (such as by returning it instead of the char*).
You might try this solution. I thing using STL makes it more clearer what you are trying to achieve. There was also an undefined reference in your code, that could lead to unpredictable crashes.
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
// Better return std::vector<char>
char* buildPacket(int code, const std::string& data)
{
auto result = data;
result.append(1, static_cast<char>(code));
char* ret = new char[data.size() + 2];
ret[data.size() + 1] = '\0';
std::copy(result.begin(), result.end(), ret);
return ret;
}
std::vector<char> buildPacketStl(int code, const std::string& data)
{
std::vector<char> ret;
std::copy(data.begin(), data.end(), std::back_inserter(ret));
ret.push_back(static_cast<char>(code));
return ret;
}
int main() {
std::cout << buildPacket(65, "test") << std::endl;; // 65 -> A
auto stl= buildPacketStl(65, "test"); // 65 -> A
std::copy(stl.begin(), stl.end(), std::ostream_iterator<char>(std::cout, ""));
std::cout << std::endl;
}
For the given array, I need to write a function to sort words alphabetically:
char strings [][10] = {
"hello",
"world",
"computers",
"are",
"awesome"
};
I've tried to write the function sortWords by using insertion sort, but I think my swap function isn't working:
void swap(char *e1, char *e2) {
int tmp = *e1;
*e1 = *e2;
*e2 = tmp;
}
void sortWords( char (* words2Darray)[10], unsigned short length ) {
unsigned int i, curPos;
char curChars[10];
for(i = 1; i < length; i++) {
// Copy the current word into curChars
strncpy_s(curChars, words2Darray[i], 10);
curPos = i;
// Compare and move the word to the correct position
while(curPos > 0 && strcmp(curChars, words2Darray[i-1]) > 0) {
swap(words2Darray[curPos], words2Darray[curPos-1]);
curPos--;
}
}
}
I've attempted debugging my code using the Local Windows Debugger and found that curChars is being copied properly.
Can someone please explain to me what I am doing wrong and how I should go about solving this problem? I'm not allowed to use std::string in this problem. No full solutions please!
You can just use std::sort:
std::sort(std::begin(strings), std::end(strings), cmp);
This requires a comparator. I whipped one up based on strcmp.
See it Live on IdeOne
#include <algorithm>
#include <iostream>
#include <cstring>
int main()
{
char const* strings[] = {
"hello",
"world",
"computers",
"are",
"awesome"
};
struct {
bool operator()(char const* a, char const* b) const {
return (a && b)? 0 > strcmp(a,b) : a < b;
}
} cmp;
std::sort(std::begin(strings), std::end(strings), cmp);
for (auto& s : strings)
std::cout << s << "\n";
}
Note that I took the liberty of making the array elements char* instead of char[].
This is for the reasons pointed out by Carl Norum.
You're not swapping strings, you're swapping the first characters of strings. If you want to pass by value, you need something like:
void swap(char **e1, char **e2) {
char *tmp = *e1;
*e1 = *e2;
*e2 = tmp;
}
And then to use it:
swap(&words2Darray[curPos], &words2Darray[curPos-1]);
Alternately you can leave the swap call as-is and use references:
void swap(char *&e1, char *&e2) {
char *tmp = e1;
e1 = e2;
e2 = tmp;
}
(I think that's right - my C++ is rusty. I'll make a test to be sure.)
Below is my sample code. Its just a sample which is similar to the code which i'm using in my applicaiton.
#define STR_SIZE 32
void someThirdPartyFunc(const char* someStr);
void getString(int Num, const char* myStr)
{
char tempStr[] = "MyTempString=";
int size = strlen(tempStr) + 2;
snprintf((char*)myStr, size, "%s%d", tempStr, Num);
}
int main()
{
const char * myStr = new char(STR_SIZE);
getString(1, myStr); // get the formated string by sending the number
someThirdPartyFunc(myStr); // send the string to the thirdpartyFunction
delete myStr;
return 0;
}
I am getting an exception if i use this code. I think the problem is with deleting the "myStr". But delete is really necessary.
Is there any other way to format the string in getString and send it to the ThirdPartyFunc??
Thanks in advance.
you are allocating not an array of chars but one char with this line:
const char * myStr = new char(STR_SIZE);
and that one allocated char is initialized with the value of STR_SIZE, causing a "char overflow" in this case.
if you want an array of size STR_SIZE:
const char * myStr = new char[STR_SIZE];
(note the rectangular [ ]). you have to deallocate such allocated chunk of memory by using the delete[] operator.
personal note: the code you have written above (manually allocated strings etc) is good educational wise; you will do a lot of such mistakes and thus learn about the inner workings of C / C++. for production code you do not want that, for production code you want std::string or other string-containers to avoid repeating string-related mistakes. in general you are not the one who sucessfully reinvent how string-libraries will work. the same is true for other container-types like dynamically-growable-arrays (std::vector) or dictionary-types or whatever. but for educational fiddling around your code above serves a good purpose.
there are other problems in your code snippet (handing over const char* to a function and then modifying the ram, not calculating correctly the size parameter when calling snprintf etc), but these are not related to your segfault-problem.
Re the technical, instead of
const char * myStr = new char(STR_SIZE);
do
char const myStr[STR_SIZE] = "";
Note that both have the problem that the string can’t be modified.
But you only asked about the allocation/deallocation problem.
But then, there's so much wrong at levels above the language-technical.
Here's the original code, complete:
void someThirdPartyFunc(const char* someStr);
void getString(int Num, const char* myStr)
{
char tempStr[] = "MyTempString=";
int size = strlen(tempStr) + 2;
snprintf((char*)myStr, size, "%s%d", tempStr, Num);
}
int main()
{
const char * myStr = new char(STR_SIZE);
getString(1, myStr); // get the formated string by sending the number
someThirdPartyFunc(myStr); // send the string to the thirdpartyFunction
delete myStr;
return 0;
}
Here's how to do that at the C++ level:
#include <string> // std::string
#include <sstream> // std::ostringstream
using namespace std;
void someThirdPartyFunc( char const* ) {}
string getString( int const num )
{
ostringstream stream;
stream << "MyTempString=" << num;
return stream.str();
}
int main()
{
someThirdPartyFunc( getString( 1 ).c_str() );
}
The #define disappeared out of the more natural code, but note that it can very easily lead to undesired text substitutions, even with all uppercase macro names. And shouting all uppercase is an eyesore anyway (which is why it's the macro name convention, as opposed to some other convention). In C++ simply use const instead.
So I am working on a tool that dereferences the values of some addresses, it is in both C and C++, and although I am not familiar with C++ I figured out I can maybe take advantage of the string type offered by C++.
What I have is this:
unsigned char contents_address = 0;
unsigned char * address = (unsigned char *) add.addr;
int i;
for(i = 0; i < bytesize; i++){ //bytesize can be anything from 1 to whatever
if(add.num == 3){
contents_address = *(address + i);
//printf("%02x ", contents_address);
}
}
As you can see what I am trying to do is dereference the unsigned char pointer. What I want to do is have a string variable and concatenate all of the dereferenced values into it and by the end instead of having to go through a for case for getting each one of the elements (by having an array of characters or by just going through the pointers) to have a string variable with everything inside.
NOTE: I need to do this because the string variable is going to a MySQL database and it would be a pain to insert an array into a table...
Try this that I borrowed from this link:
http://www.corsix.org/content/algorithmic-stdstring-creation
#include <sstream>
#include <iomanip>
std::string hexifyChar(int c)
{
std::stringstream ss;
ss << std::hex << std::setw(2) << std::setfill('0') << c;
return ss.str();
}
std::string hexify(const char* base, size_t len)
{
std::stringstream ss;
for(size_t i = 0; i < len; ++i)
ss << hexifyChar(base[i]);
return ss.str();
}
I didn't quite understand what you want to do here (why do you assign a dereferenced value to a variable called ..._address)?.
But maybe what you're looking for is a stringstream.
Here's a relatively efficient version that performs only one allocation and no additional function calls:
#include <string>
std::string hexify(unsigned char buf, unsigned int len)
{
std::string result;
result.reserve(2 * len);
static char const alphabet[] = "0123456789ABCDEF";
for (unsigned int i = 0; i != len)
{
result.push_back(alphabet[buf[i] / 16]);
result.push_back(alphabet[buf[i] % 16]);
{
return result;
}
This should be rather more efficient than using iostreams. You can also modify this trivially to write into a given output buffer, if you prefer a C version which leaves allocation to the consumer.