Returning an Array using pointers

Hi all,

First and foremost, thank you for your help in advance.

Basically, I am trying to return an array of strings in a function I wrote. I figured out through reading that you have to use a pointer to do this because C++ doesn't support returning of arrays. That being said, I can't figure out why my code won't work. The code below basically takes a string such as "1A 23 35" and should return a 3 member array of strings containing {1A, 23, 35}. My guess is the array I create in my function that I wish to return gets deleted at the end of the function and basically I get a bunch of gibberish as my returned array. I thought maybe I could declare a global variable to achieve this but it seems like a big workaround and not the proper way to do things. Any and all help is much appreciated. If you guys can point me to the correct way to do this I'd much rather learn that than an "easy" way that's inefficient but gets it done.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
string* disect(string *s){
    string d[3], temp;
    string st;
    st = *s;
    string *pointer;
    pointer = &d[3];
    int i,j=0,count=0,last =0;

    for(i=0; i<st.length(); i++){
        if(st[i] == ' '){
            for(j=last; j<i; j++){
                temp[j] = st[j];     
            }
            last = i+1;
            d[count] = temp;
            count++;    
        }    
    }
    return pointer;  
}

int main(){
    
    // Primary Initalizations                                 
    hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    
    // Other Variables     
    int i,j;
    string input;
    
    string test = "1A 34 67";
    string *pointer;
    pointer = disect(&test);
    
    for(i=0;i<6;i++){
        cout<<i<<" = "<<*(pointer+i)<<endl;    
    }

    return 0;
}
You would need to create a new array of strings:
std::string *myStrArray = new std::string[3];
I'm not so sure how this plays out since a string is really just an array. I haven't played with 1D arrays much, let alone a 2D, in this case, it's really a 2D array, one.

Don't forget to delete the new's once you're done with them(which will be where ever the function returns to).
Last edited on
Thanks for your reply Volatile Pulse.

To be honest, not sure what the "new" is and what difference it makes. Haven't found documentation on it either. I would really appreciate an explanation or pointing me to where I can read about it.

Thanks.
Just tried this as well, runs now but freezes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
string* disect(string *s, string st){
    string temp;
    int i,j=0,count=0,last =0;
    
    for(i=0; i<st.length(); i++){
        if(st[i] == ' '){
            for(j=last; j<i; j++){
                temp[j] = st[j];     
            }
            last = i+1;
            *(s+count) = temp;
            count++;    
        }    
    }
    
    return s;  
}
int main(){
    
    // Primary Initalizations                                 
    hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    
    // Other Variables      
    int i,j;
    string input;
    
    string test = "1A 34 67";
    string d[3];
    string *pointer = new string[3];
    pointer = d;
    pointer = disect(pointer,test);
    
    for(i=0;i<6;i++){
        cout<<i<<" = "<<*(pointer+i)<<endl;    
    }
return 0;
}
Your (original) function does the following, in broad terms:

Create an array of strings on the stack.
The array consists of d[0], d[1] and d[2].
Then create a pointer to the non-existent element d[3], which is off the end of the array.
Return that pointer (after which the entire array is destroyed anyway, as you suspected, because that's what happens to variables created on the stack in a function when that function ends).

So you get back a pointer to a place that is off the end of an array that no longer exists and may be full of garbage by now.

You need to learn about the following things:

Arrays (in particular, how they start at zero).
The stack.
Local (i.e. stack) variables.

When you have learnt about these things, you will understand what you have done wrong.

Then, you can learn about new. new creates a variable in a different section of memory, called the heap. Those variables are not destroyed when the function ends; they are destroyed when you delete them.

Creating an array using new is easy. Volatile Pulse's example is correct, but here it is again anway.

string* d = new string[3]; // d is a pointer to the first element of an array of 3 strings
Last edited on
I actually messed up in my previous code, but new returns a pointer. Essentially, the way new works, or how it was explained to me, was that it allocates memory. In this case, it allocates memory for 3 strings (again, not sure how strings are handled when allocating memory) and returns a pointer to the first string, [0] in the index.

How this works with standard data types is as follows:
1
2
3
4
5
6
7
// Creates a pointer to an int
int *intPtr;
// Points to the newly allocated int
intPtr = new int;
// Since we don't have a variable name for the new int,
// We must use the pointer
*intPtr = 5; // the * dereference's it to be used like a regular variable. 


Used as an array:
1
2
3
4
5
int *intPtr;
// Creates an array of 5 ints and returns a pointer to the first one.
intPtr = new int[5];
intPtr ++; // is now pointing at the 2nd index
*intPtr = 5; // 2nd index ([1]) now equals 5 


Since when you "new" an array the compiler allocates set amount of blocks to the side, you can traverse those blocks simply with the pointer. This way, you can return the pointer and use it to navigate through the array you just created. Since you allocated memory, you must also destroy the memory or face a memory leak. This is done by deleteing your memory. If you new'd an array of 5 ints, you need to delete an array of 5 ints as well. In my last example, it would be:
delete intPtr[5];

delete[] intPtr; fixed

I might have sidetracked a little, but I hope this helps. One last idea (in case this sounds a little tricky), is to pass an array to the function for the function to modify itself.
Last edited on
it would be:
delete intPtr[5];

Not quite. Try this:
delete[] intPtr;

I'm not so sure how this plays out since a string is really just an array.

You're thinking of a C-style string, which is an array of char. A C++ string will contain a pointer to an array of char, but it's a lot more than just that.
Last edited on
Yes, you got it right that the variables declared in a function are destroyed upon exiting that function. The easiest way to return an array from a function is to use the containers. In your case I would use std::vector<std::string>. It will also allow you to avoid hard-coding the number of substrings (3 in your case).

I assume you wrote using namespace std; in the beginning. I don't like it, but I will stick with it for now. Also I made some comments in the other parts of code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
vector<string> disect(const string& s) // using a reference will allow you to avoid writing *s in the same way as making a copy - see below 
{
    vector<string> result; 
    // string st; // avoid unneeded copying
    // st = *s;
    // string *pointer;
    // pointer = &d[3]; // I really don't understand what you tried to achieve with this line of code
    int i,last =0;

    for(i=0; i<s.length(); i++){
        if(s[i] == ' '){
            result.push_back(s.substr(last, i - last));
            last = i+1;
        }    
    }
    return result;  
}

int main(){
    
    // Primary Initalizations                                 
    hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    
    // Other Variables     
    int i,j;
    string input;
    
    string test = "1A 34 67";
    vector<string> splitResult = disect(test);
    
    for(i=0;i<splitResult.size();i++){
        cout<<i<<" = "<<  splitResult[i] <<endl;    
    }

    return 0;
}


This code is still far from being perfect, but I hope you learned something from it. Also, with introduction of move constructors in C++11 this code is not inefficient anymore, but that's a different story.
Do the C++ strings affect using the new in the form of an array? Or does it just reserve one spot for the pointer of the string? Everything above works correctly for C++ strings, but not C strings, correct?
Thanks a lot for all of the help guys. I will look into vector but the pointer examples are starting to make a lot more sense.

What I don't understand from KRAkatau's code is (const string& s). First off, why the const? Also, you're basically sending the address of a string? I'm a little confused as to why its &s and not *s. If you would care to explain this bit I would much appreciate it.
The purpose to a const reference (I just learned this myself) is that you're ensuring that the reference, in this case the string s, won't be modified. By passing a reference, you're using the same memory block from before, which is faster than creating a copy. You get the best of both worlds. It should, however, only be used when you absolutely don't want to modify it at all, for example, you're testing the string or just displaying it.
The main purpose of const is to specify your intent. If a parameter is passed by value, the function gets the copy of that parameter. Therefore no matter if the function modifies it - the original value will stay intact. However, if the parameter is passed by pointer (or reference, which is internally the same thing - it's just some syntactic sugar, so you can avoid writing stuff like (*s)[0]), the original object may be modified. So by specifying const you communicate to the user of the function, that the parameter will not be modified (which is true in your case) - it is kind of self-documenting code: "function disect needs a string as its parameter, and it will not be modified". So the user of that function (perhaps the code of your function is packaged in a library and the user cannot see the actual code) KNOWS that nothing will happen to that string he passed and he can use it accordingly in his code after calling disect.

Sometimes you just have to have const to work, for example, with string literals.
1
2
void f1(char*); // will not compile if you call it as f1("test");
void f2(const char*); // f2("test") will compile  
Last edited on
Topic archived. No new replies allowed.