14

I've been programming badly for quite a while and I only really just realised. I have previously created many functions that return character strings as char arrays (or at least pointers to them).

The other day someone pointed out that when my functions return the char arrays pointed to by my functions have gone out of scope and I'm essentially now pointing to a random bit of memory (A nasty dangling pointer).

I didn't really notice this for a while because the char arrays when outputted to the console didn't appear to be corrupt (probably because there wasn't time for that data to be overwritten). I did however notice this when I was returning a string buffer (char array) generated by reading the serial port which was frequently corrupt.

So, how best should I do it?

My bad code is as follows:

#include <cstdlib>
#include <iostream>

using namespace std;

char* myBadFunction(){
    char charArray[] = "Some string\n";
    char* charPointer = charArray;
    return charPointer;
}


int main(int argc, char** argv) {

    cout << myBadFunction();

    return 0;
}

I understand that I should perhaps allocate memory in the program before calling the function or create a global variable to put the returned string in, but if my called function is used by many different programs when how should it know the size of the buffer being passed into it in advance and when should this memory be deleted?

The following code also doesn't do what I want it to properly:

#include <cstdlib>
#include <iostream>

using namespace std;

void fillArray(char* charPointer){
    char charArray[] = "Some string\n"; // Create string
    charPointer = charArray; // Not correct, want to fill predefined array with created string
    return;
}


int main(int argc, char** argv) {

    char predefinedArray[50] = {0};
    fillArray(predefinedArray);
    cout << predefinedArray;

    return 0;
}

I want to fill the array that the pointer parsed points to but this doesnt' happen in the code above.

Also, when should I use the new[] command to create my array? is it needed? and when should I call delete[] on it.

Many thanks for this, its obviously very fundamental but something I've been doing wrong for a while.

Binary Worrier
  • 50,774
  • 20
  • 136
  • 184
Zac
  • 2,229
  • 9
  • 33
  • 41
  • 1
    you'd better add the kind of code you write in the tags. – Stefanvds Sep 17 '10 at 08:03
  • Regarding the second part of your question, You'll have to use manually loop and copy each character into the second array or use `memcpy`... – st0le Sep 17 '10 at 08:03

4 Answers4

11

The simplest way would be to return a std::string, and if you needed access to the internal char array use std::string::c_str().

#include <iostream>
#include <string>

using namespace std;

string myGoodFunction(){
    char charArray[] = "Some string\n";
    return string(charArray);
}


int main(int argc, char** argv) {  
    cout << myGoodFunction();
    return 0;
}

If you need to return something other than a char array, remember that pointers can be used as iterators. This allows you to encapsulate an array in a vector or a similar structure:

vector<int> returnInts() {
    int someNums[] = { 1, 2, 3, 4 };
    return vector<int>(someNums, someNums + 4);
}
Paul
  • 2,218
  • 1
  • 15
  • 18
  • 8
    I disagree. While this solves the current problem, it doesn't explain the issues of using arrays of other types. I won't downvote, that would be unfair, but a better answer would explain the problems with his initial code. – Alexander Rafferty Sep 17 '10 at 08:09
  • 1
    @Alexander: Good point. I've updated my answer to reflect your comment. – Paul Sep 17 '10 at 08:25
  • This works, I'll tick it in a minute. So I'm correct in thinking the returned string does not go out of scope because it is an object return type but a char array does because its only a pointer and not the entire array returned? – Zac Sep 17 '10 at 08:25
  • @Zac: Conceptually, first a temporary string object is created from the char array. This temporary object is then copied to the client before it is destroyed. Technically, this copy is often optimized away. – fredoverflow Sep 17 '10 at 09:01
  • Ok I still have a problem, not sure if I should write it here or create a new thread. I NEED to end up with a char array rather than a string type purely because the char array is used to contain a pump port name ie "COM7" and is used as an argument in createfile() function to open the port to writting (actually a char pointer) this function does not accept string types. – Zac Sep 17 '10 at 09:07
  • Ok forget that, I resolved it by returning a string type then calling .cstr() on it and creating a char pointer in the calling function that points to that new string. – Zac Sep 17 '10 at 09:26
  • @Zac: The string will go out of scope. But since it is a return by value, we get a copy in the caller. – Chubsdad Sep 17 '10 at 10:37
6

You have two options for returning an array in C++. You can fill in pre-allocated memory (good), or allocate your own within the function and return it (bad). The reason that the first is preferred is because it re-enforces proper disposal of allocated memory.

A basic example would look like this:

void fillArray(char* buffer, int sz) {
  char text[] = "hello there!";
  if (sizeof(text)>sz) {
    // overflow! Buffer is too small!
    return;
  }
  for (int n=0;n<sizeof(text);n++) {
    buffer[n] = text[n];
  }
}

int main() {
  char* buffer = new char[30]; // allocates a buffer of 30 bytes.
  fillArray(buffer,30);
  cout << buffer;
  delete [] buffer;
}

/* note that it would be easier to use static memory in this example */

It isn't hard when you think about the problem.

Alexander Rafferty
  • 6,134
  • 4
  • 33
  • 55
  • This solves the issue except when do I call new[] and when delete[] ? And additionally what if the string added is dynamically allocated by cin >> string? who should the internal function know the size of the buffer being passed to it ? – Zac Sep 17 '10 at 08:23
  • You allocate the memory in the main function. The function doesn't need to know the buffer size unless there is a possibility for an overflow. I'll update my answer for you. – Alexander Rafferty Sep 17 '10 at 10:08
2

Declare the array as "static" varible and return with its address. This code works, but causes a warning :

#include <cstdlib>
#include <iostream>
using namespace std;

char* myBadFunction(){
    static char charArray[] = "Some string\n";    // insert "static"
    // char* charPointer = charArray;  
    return charArray;             // charArray is a pointer to the static array
}                                 // after returning static varibles stay safe
int main(int argc, char** argv) {
    cout << myBadFunction();
    return 0;
}
Rambo
  • 21
  • 1
1

"Some string\n" is a string literal and will therefore exist for the lifetime of the program, so the following would be valid:

#include <cstdlib>
#include <iostream>

using namespace std;

char* myGoodFunction(){
    char* charPointer = "Some string\n";
    return charPointer;
}

int main(int argc, char** argv) {
    cout << myGoodFunction();

    return 0;
}

Of course this is only useful if the function always returns the same string. If the returned string can vary (generally the case) then you can declare the char array in your function as static and return it's address (as has already been suggested).

G. Brown
  • 11
  • 2