Ricardo Saporta
Ricardo Saporta

Reputation: 55420

returning array of char pointers from a function (c++)

I'm trying to return an array of char arrays. While I am able to create the array succesfully, I am apparently returning it incorrectly.

Is my syntax off or am I committing some other error that I am overlooking?

Here are the most relevant lines, the full functions follow

// prototype
  char * testFunc();

// Function
    char * testFunc() {
      char* ptrArray[2];   
      return(*ptrArray);
    }
// Assignment in main()
    int main {
      char * res = testFunc();
    }

Here is a simplified version of the full code

#include <iostream>
using std::cout;

// prototype
char * testFunc();

int main() {

    short i, j;
    char * res = testFunc();

        for (i=0; i < 2; i++)
           cout <<"This is  res[" << i << "] : " << res[i] <<"\n";


    return(0);
}

char * testFunc() {

    char word1[] = "one";
    char word2[] = "two";

    // create an array of char*
    char* ptrArray[2];

    ptrArray[0] = word1;
    ptrArray[1] = word2;

    for (int i=0; i<2; i++)
        cout <<"This is ptrArray[" << i << "] : " << ptrArray[i] <<"\n";

    return(*ptrArray);
}

Upvotes: 1

Views: 5634

Answers (2)

Thomas W
Thomas W

Reputation: 14154

A single "character array" is roughly equivalent to char *. To return an array of arrays, you need char ** or perhaps char[]*.

As the other answer says, if you're returning pointers from inside a function these need to be "global" memory -- not local variables which are only ever valid within the function. Returned pointers to "stack-based" local variables are no longer valid after the function returns, since that stack-space will be overwritten by the next function-call (or sooner).

[Since the original posting, it has been suggested that const char* and (presumably) const char** would be preferred, for "const correctness"].

My C++ is rusty.. but:

const char** testFunc() {
    const char word1[] = "one";
    const char word2[] = "two";

    // create an array of char*
    const char** ptrArray = (const char **) malloc( 2 * sizeof(char *));
    ptrArray[0] = word1;
    ptrArray[1] = word2;

    for (int i=0; i<2; i++)
        cout <<"This is ptrArray[" << i << "] : " << ptrArray[i] <<"\n";

    return ptrArray;
}

And in main:

int main() {
    short i;

    // get the array -- will now be our responsibility to free
    const char** ptrArray = testFunc();

    for (i=0; i < 2; i++) {
        // read single pointer (char*),  from our array of pointers (char**)
        const char* word = ptrArray[i];
        cout <<"This is  res[" << i << "] : " << word <<"\n";
    }

    // free it.
    free( ptrArray);

    return(0);
}

As the original question is posed, the inputs for the array are string constants. Returning a mutable array of constant strings is thus preferred, to returning a mutable array of mutable strings.

Even if the full system (not shown in the question) built up the strings programmatically, as per other the answer, it is more than likely they would best be returned as const char * -- not treated as buffers for further modification.

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 727047

Returning objects allocated in the automatic storage (also known as "stack objects") from a function is undefined behavior. When you need to return an array in C, you have three options:

  1. Return an object allocated in the static storage area,
  2. Return an object allocated in the dynamic storage area, or
  3. Take a buffer and max size, and return the actual size of the array.

The first option is rarely applicable, because it makes your function non-reentrant. The third option is widespread, but it has limitations: when you must return more data than fits into the buffer, the API needs to be called multiple times.

This leaves us with option number two: use new to allocate the memory that you are returning, copy the data into it, and return the result to the caller. It is now caller's responsibility to free the dynamic memory:

// You need two asterisks: a string needs one asterisk, you return
// a 1-D array of strings, so you need another level of indirection.
char ** testFunc() {
    char word1[] = "one"; // Automatic memory - needs a copy
    char word2[] = "two"; // Automatic memory - needs a copy

    // create an array of char*
    char** ptrArray = new char*[2];

    ptrArray[0] = new char[strlen(word1)+1]; // Plus one for the null terminator
    strcpy(ptrArray[0], word1);
    ptrArray[1] = new char[strlen(word2)+1]; // Plus one for the null terminator
    strcpy(ptrArray[1], word2);
    for (int i=0; i<2; i++)
        cout <<"This is ptrArray[" << i << "] : " << ptrArray[i] <<"\n";

    return ptrArray;
}

Note: you may not have reached the standard library yet, so the solution below may not apply. However, you should know that the above solution is not the best C++ can do: you can rewrite this wit dynamic containers, and make the code much easier to read:

vector<strig> testFunc() {
    vector<string> res;
    res.push_back("one");
    res.push_back("two");
    return res;
}

In C++11 you can do even better:

vector<string> test() {
    return vector<string> {"one", "two"};
}

Upvotes: 4

Related Questions