It has been a long time since I have programmed in C++, but I recently wrote a little C++ function and am having a little bit of trouble. The function returns a struct, Result, that have some strings in it. I thought I allocated memory for the strings, but jsonResult is sometimes partially overwritten.
//The structs
struct Interp {
int score;
char* sentence;
char* jsonResult;
};
struct Result {
int resultCode;
char* errorMessage;
Interp interp;
};
...
//Inside the function
Result result;
//Store decode
const char* jsonResult,* sentence;
if (result.resultCode == -1)
{
LVInterpretation interp = port.GetInterpretation(voiceChannel, 0);
result.interp.score = interp.Score();
sentence = interp.InputSentence();
jsonResult = interp.ResultData().Print(SI_FORMAT_ECMA);
}
//Allocate memory for strings
result.interp.jsonResult = new char[strlen(jsonResult) + 1];
strcpy(result.interp.jsonResult, jsonResult);
result.interp.sentence = new char[strlen(sentence) + 1];
strcpy(result.interp.sentence, sentence);
result.errorMessage = new char[strlen(errorMessage) + 1];
strcpy(result.errorMessage, errorMessage);
return result;
Other info:
I am observing all of this behind the python binding that I wrote, using ctypes. Don't think that is really effecting anything though.
Use std::string. You won't regret it.
I'd put money on your problem being in here:
jsonResult = interp.ResultData().Print(SI_FORMAT_ECMA);
Who 'owns' the char* array returned by Print()? Maybe it's attempting to return a pointer to memory that's out of scope???
example:
char* badFunction(void)
{
char test[100];
strcpy(test,"This is really clever"); // oh, yeah?
return test; // returns pointer to data that's out of scope
}
One other thing. Assign null pointers to sentence, jsonResult, etc when you declare them. Otherwise you could end up strcpy()ing uninitialized data,
Couple of things:
What does "partially overwritten" mean? How do you know this? i.e. what is your expected output vs. what you see?
It's not really clear how result.resultCode is set to -1 (or if it is at all), and if it is set, how does the memory get allocated in interp.InputSentence() and interp.ResultData().Print(SI_FORMAT_ECMA)? I'd suggest that your problem lies there
The rest of the code should work as long as jsonResult and sentence contain valid null terminated strings.
Related
Is it possible to add a string to a string pointer in C++?
Not working example:
String* temp;
temp[0] = "string";
Just like it's possible in:
String temp[3];
temp[0] = "string";
Before suggesting to just use a normal array or copy it to a different fixed array, the string pointer needs to be returned in a function. Eg.
String* SomeClass::toArray(String str)
I am also open to other suggestions how I can return an array from this function.
Independing of what is String this code snippet
String* temp;
temp[0] = "string";
if it is compiled results in undefined behaviour because the pointer temp either has an indeterminate value (if it is a local variable) or NULL and you may not derefence it.
Provided that this code snippet
String temp[3];
temp[0] = "string";
is valid you could write for example
String* other_temp = temp;
other_temp[0] = "string";
you can't add anything to POINTER, pointer is just pointing to some memory.
You need first to have some instance, like in your second example String temp[3]; you are creating three instances of String.
So String temp; will create local instance of String, then to get it's pointer you can use String * tempPtr = &temp;, but I don't see why you would want that, as you can use temp as is... like temp.clear(); or whatever functions the class String has (see it's API).
Edit about returning String pointer.
That's sort of unfortunate C++ API design. So who will own the memory of that instance?
For example:
String* SomeClass::toArray(String str) {
String result;
// BUG, DO NOT DO THIS!
return &result; // returns pointer to local stack variable
// which gets released *here*, invalidating the pointer
}
String* SomeClass::toArray(String str) {
String *result = new String;
return result; // returns pointer to global heap
// now if the upper layer of code will not call "delete" on it
// you have memory leak
}
BTW, from the "toArray" name it looks like you want array of String instances, not String pointer. So that functions should be rather defined as String[] SomeClass::toArray(String str), still having the same problem with memory ownership.
What I would do is not return an array.
maybe void SomeClass::toArray(const String & str, std::vector<String> & array), filling up the data into array vector.
I do not know how much you use C++ on arduino, if std::vector is OK, or not, but having a class for String feels like vector<> will be OK too, especially if you are wasting your stack by passing copy instance of String instead of reference. (unless String is some macro/typedef for char[], please, don't tell me that... I mean, even C++ can be written in low memory footprint way, you don't have to hardwire arrays everywhere, if you avoid unnecessary allocation of temporary instances of C++ classes).
I'm reading the 3rd edition of The C++ Programming Language by Bjarne Stroustrup and attempting to complete all the exercises. I'm not sure how to approach exercise 13 from section 6.6, so I thought I'd turn to Stack Overflow for some insight. Here's the description of the problem:
Write a function cat() that takes two C-style string arguments and
returns a single string that is the concatenation of the arguments.
Use new to find store for the result.
Here's my code thus far, with question marks where I'm not sure what to do:
? cat(char first[], char second[])
{
char current = '';
int i = 0;
while (current != '\0')
{
current = first[i];
// somehow append current to whatever will eventually be returned
i++;
}
current = '';
i = 0;
while (current != '\0')
{
current = second[i];
// somehow append current to whatever will eventually be returned
i++;
}
return ?
}
int main(int argc, char* argv[])
{
char first[] = "Hello, ";
char second[] = "World!";
? = cat(first, second);
return 0;
}
And here are my questions:
How do I use new to find store? Am I expected to do something like std::string* result = new std::string; or should I be using new to create another C-style string somehow?
Related to the previous question, what should I return from cat()? I assume it will need to be a pointer if I must use new. But a pointer to what?
Although the problem doesn't mention using delete to free memory, I know I should because I will have used new to allocate. Should I just delete at the end of main, right before returning?
How do I use new to find store? Am I expected to do something like std::string* result = new std::string; or should I be using new to create another C-style string somehow?
The latter; the method takes C-style strings and nothing in the text suggests that it should return anything else. The prototype of the function should thus be char* cat(char const*, char const*). Of course this is not how you’d normally write functions; manual memory management is completely taboo in modern C++ because it’s so error-prone.
Although the problem doesn't mention using delete to free memory, I know I should because I will have used new to allocate. Should I just delete at the end of main, right before returning?
In this exercise, yes. In the real world, no: like I said above, this is completely taboo. In reality you would return a std::string and not allocate memory using new. If you find yourself manually allocating memory (and assuming it’s for good reason), you’d put that memory not in a raw pointer but a smart pointer – std::unique_ptr or std::shared_ptr.
In a "real" program, yes, you would use std::string. It sounds like this example wants you to use a C string instead.
So maybe something like this:
char * cat(char first[], char second[])
{
char *result = new char[strlen(first) + strlen(second) + 1];
...
Q: How do you "append"?
A: Just write everything in "first" to "result".
As soon as you're done, then continue by writing everything in "second" to result (starting where you left off). When you're done, make sure to append '\0' at the end.
You are supposed to return a C style string, so you can't use std::string (or at least, that's not "in the spirit of the question"). Yes, you should use new to make a C-style string.
You should return the C-style string you generated... So, the pointer to the first character of your newly created string.
Correct, you should delete the result at the end. I expect it may be ignored, as in this particular case, it probably doesn't matter that much - but for completeness/correctness, you should.
Here's some old code I dug up from a project of mine a while back:
char* mergeChar(char* text1, char* text2){
//Find the length of the first text
int alen = 0;
while(text1[alen] != '\0')
alen++;
//Find the length of the second text
int blen = 0;
while(text2[blen] != '\0')
blen++;
//Copy the first text
char* newchar = new char[alen + blen + 1];
for(int a = 0; a < alen; a++){
newchar[a] = text1[a];
}
//Copy the second text
for(int b = 0; b < blen; b++)
newchar[alen + b] = text2[b];
//Null terminate!
newchar[alen + blen] = '\0';
return newchar;
}
Generally, in a 'real' program, you'll be expected to use std::string, though. Make sure you delete[] newchar later!
What the exercise means is to use new in order to allocate memory. "Find store" is phrased weirdly, but in fact that's what it does. You tell it how much store you need, it finds an available block of memory that you can use, and returns its address.
It doesn't look like the exercise wants you to use std::string. It sounds like you need to return a char*. So the function prototype should be:
char* cat(const char first[], const char second[]);
Note the const specifier. It's important so that you'll be able to pass string literals as arguments.
So without giving the code out straight away, what you need to do is determine how big the resulting char* string should be, allocate the required amount using new, copy the two source strings into the newly allocated space, and return it.
Note that you normally don't do this kind of memory management manually in C++ (you use std::string instead), but it's still important to know about it, which is why the reason for this exercise.
It seems like you need to use new to allocate memory for a string, and then return the pointer. Therefore the return type of cat would be `char*.
You could do do something like this:
int n = 0;
int k = 0;
//also can use strlen
while( first[n] != '\0' )
n ++ ;
while( second[k] != '\0' )
k ++ ;
//now, the allocation
char* joint = new char[n+k+1]; //+1 for a '\0'
//and for example memcpy for joining
memcpy(joint, first, n );
memcpy(joint+n, second, k+1); //also copying the null
return joint;
It is telling you to do this the C way pretty much:
#include <cstring>
char *cat (const char *s1, const char *s2)
{
// Learn to explore your library a bit, and
// you'll see that there is no need for a loop
// to determine the lengths. Anything C string
// related is in <cstring>.
//
size_t len_s1 = std::strlen(s1);
size_t len_s2 = std::strlen(s2);
char *dst;
// You have the lengths.
// Now use `new` to allocate storage for dst.
/*
* There's a faster way to copy C strings
* than looping, especially when you
* know the lengths...
*
* Use a reference to determine what functions
* in <cstring> COPY values.
* Add code before the return statement to
* do this, and you will have your answer.
*
* Note: remember that C strings are zero
* terminated!
*/
return dst;
}
Don't forget to use the correct operator when you go to free the memory allocated. Otherwise you'll have a memory leak.
Happy coding! :-)
I need an array to store char arrays of variable size. I could use vectors or anything else, but unfortunately this is for a MPI project and I am forced to use an array so I can send it using MPI::COMM_WORLD.Send(...) function.
My idea comes from this link.
This is a simplified example of the problem I have:
char* arrayStorage[3]; //I want to store 3 char arrays of variable size!
int index = 0;
char array_1[RANDOM_SIZE] = {.....};
char array_2[RANDOM_SIZE] = {.....};
char array_3[RANDOM_SIZE] = {.....};
arraySorage[index] = array_1;
index++;
arraySorage[index] = array_2;
index++;
arraySorage[index] = array_3;
index++;
I have also seen people talking about malloc and stuff like that, but I don't know much about pointers. I do malloc, I have to call free and I don't know where, so I am avoiding that for now.
This code obviously doesn't work, array_1, array_2, array_3 are all OK, but when I try to access them I get garbage. The problem seems to be inside the index variable. Maybe I shouldn't be doing index++, perhaps I should be doing index += RANDOM_SIZE, but that also fails.
How can I store variable size char arrays in an array?
Use malloc and free (or new and delete in C++). You can do it with vectors too - as vectors can be treated as arrays.
char *str = "hello world";
// need the +1 for null character
arraySorage[0] = (char *)malloc (strlen(str) + 1);
strcpy(arraySorage[0], str);
...
free(arraySorage[0]);
with new/delete
arraySorage[0] = new char[strlen(str)+1];
strcpy(arraySorage[0], str);
...
delete arraySorage[0];
Using vector and std::string is the correct C++ way, for lots of reasons, including not leaking memory and proper handling of exceptions.
#include <iostream>
#include <string.h>
using namespace std;
void newBuffer(char* outBuffer, size_t sz) {
outBuffer = new char[sz];
}
int main(void) {
const char* abcd = "ABCD";
char* foo;
foo = NULL;
size_t len = strlen(abcd);
cout<<"Checkpoint 1"<<endl;
newBuffer(foo, len);
cout<<"Checkpoint 2"<<endl;
cout<<"Checkpoint 2-A"<<endl;
memset(foo, '-', len);
cout<<"Checkpoint 3"<<endl;
strncpy(foo, abcd, len);
cout<<"Checkpoint 4"<<endl;
cout << foo << endl;
int hold;
cin>>hold;
return 0;
}
This program crashes between checkpoint 2-1 and 3. What it tries to do is to set the char array foo to the char '-', but it fails because of some access issues. I do not understand why this happens. Thank you very much in advance!
Your newBuffer function should accept the first parameter by reference so that changes made to it inside the function are visible to the caller:
void newBuffer(char*& outBuffer, size_t sz) {
outBuffer = new char[sz];
}
As it is now, you assign the result of new char[sz] to the local variable outBuffer which is only a copy of the caller's foo variable, so when the function returns it's as if nothing ever happened (except you leaked memory).
Also you have a problem in that you are allocating the buffer to the size of the length of ABCD which is 4. That means you can hold up to 3 characters in that buffer because one is reserved for the NUL-terminator at the end. You need to add + 1 to the length somewhere (I would do it in the call to the function, not inside it, because newBuffer shouldn't be specialised for C-strings). strncpy only NUL-terminates the buffer if the source string is short enough, so in this case you are only lucky that there happens to be a 0 in memory after your buffer you allocated.
Also don't forget to delete[] foo in main after you're done with it (although it doesn't really matter for a program this size).
It fails because your newBuffer function doesn't actually work. The easiest way to fix it would be to change the declaration to void newBuffer (char *&outBuffer, size_t sz). As it's written, the address of the newly allocated memory doesn't actually get stored into main's foo because the pointer is passed by value.
You are passing the pointer by value. You would need to pass either a reference to the pointer, or the address of the pointer.
That said, using the return value would be better in my view:
char* newBuffer(size_t sz) {
return new char[sz];
}
When written this way, the newBuffer function doesn't really seem worthwhile. You don't need it. You can use new directly and that would be clearer.
Of course, if you are using C++ then this is all rather pointless. You should be using string, smart pointers etc. You should not have any need to call new directly. Once you fix the bug you are talking about in this question you will come across the problem that your string is not null-terminated and that the buffer is too short to hold the string since you forgot to allocate space for the null-terminator. One of the nice things about C++ is that you can escape the horrors of string handling in C.
Okay the previous question was answered clearly, but i found out another problem.
What if I do:
char *test(int ran){
char *ret = new char[ran];
// process...
return ret;
}
And then run it:
for(int i = 0; i < 100000000; i++){
string str = test(rand()%10000000+10000000);
// process...
// no need to delete str anymore? string destructor does it for me here?
}
So after converting the char* to string, I don't have to worry about the deleting anymore?
Edit: As answered, I have to delete[] each new[] call, but on my case its not possible since the pointer got lost, so the question is: how do I convert char to string properly?
Here you are not converting the char* to a [std::]string, but copying the char* to a [std::]string.
As a rule of thumb, for every new there should be a delete.
In this case, you'll need to store a copy of the pointer and delete it when you're done:
char* temp = test(rand()%10000000+10000000);
string str = temp;
delete[] temp;
You seem to be under the impresison that passing a char* into std::string transfers ownership of the allocated memory. In fact it just makes a copy.
The easiest way to solve this is to just use a std::string throughout the entire function and return it directly.
std::string test(int ran){
std::string ret;
ret.resize(ran - 1); // If accessing by individual character, or not if using the entire string at once.
// process... (omit adding the null terminator)
return ret;
}
Yes, yes you do.
If you are using linux/os x, look into something like valgrind which can help you with memory issues
You can change your test function so that it returns a string instead of char *, this way you can delete [] ret in the test function.
OR you could just use a string in test as well and not have to worry about new/delete.
You must call delete for every new otherwise you will leak memory. In the case you have shown you are throwing away the pointer, if you must leave the function as returning a char* then you will need to use two lines to create the std::string so you can retain a copy of the char* to delete.
A better solution would be to rewrite your test() function to return a std::string directly.
You need to do something like this:
for(int i = 0; i < 100000000; i++){
int length = rand()%10000000+10000000;
char* tmp = test(length);
string str(tmp);
delete[length] tmp;
}
This deletes the allocated char-array properly.
By the way, you should always zero-terminate a string if you create it this way (i.e. inside the function test), otherwise some functions can easily get "confused" and treat data behind your string as part of it, which in the best case crashes your application, and in the worst case creating a silent buffer overflow leading to undefined behaviour at a later point, which is the ultimate debugging nightmare... ;)